Android 如果子视图占据焦点,OnKeyListener或OnKeydown不起作用

Android 如果子视图占据焦点,OnKeyListener或OnKeydown不起作用,android,android-scrollview,trackball,Android,Android Scrollview,Trackball,我想听听滚动视图,看看它是否在滚动。我用过一个听者,效果很好。但是,当我想使用OnKeyListener或重写OnKeydown方法为trackball添加兼容性时,它无法工作。似乎是子按钮获取焦点导致了问题 有解决此问题的解决方案或解决方法吗?感谢您的帮助 下面是一些重现我的问题的演示代码: public class TestActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState)

我想听听滚动视图,看看它是否在滚动。我用过一个听者,效果很好。但是,当我想使用OnKeyListener或重写OnKeydown方法为trackball添加兼容性时,它无法工作。似乎是子按钮获取焦点导致了问题

有解决此问题的解决方案或解决方法吗?感谢您的帮助

下面是一些重现我的问题的演示代码:

public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    ScrollView scrollView = (ScrollView) findViewById(R.id.scroll_view);
    LinearLayout mainLayout = (LinearLayout) findViewById(R.id.main_layout);

    LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.FILL_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT);
    for (int i = 0; i < 100; i++) {
        MyItem item = (MyItem) LayoutInflater.from(this).inflate(R.layout.item, null);
        item.setParent(scrollView);
        item.setBackgroundColor(Color.WHITE);
        item.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.WRAP_CONTENT));
        mainLayout.addView(item, wrapParams);
    }

    scrollView.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // can go into here
        }

    });

    scrollView.setOnKeyListener(new OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                // never go in, unless no child button get focus
            }
            return false;
        }
    });
}

}
MyItem.java

public class MyItem extends LinearLayout {

    private Button myButton;
    public MyItem(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected boolean onRequestFocusInDescendants(int direction,
            Rect previouslyFocusedRect) {
        // never go into here
        Log.i("MyItem", "request focus in descendants");
        return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
    }

}

触摸事件从子对象传递到父对象。如果任何子级消耗偶数(返回true),则它将停止;它不会传递给父级。因此,有两种解决方案

首先是扩展视图容器类并重写
onInterceptTouchEvent()
。这里有一个例子,我是为
TabHost
做的,但对您来说可能是
LinearLayout
,或者其他什么

public class FlingableTabHost extends TabHost {
    private GestureDetector gestureDetector;

    public FlingableTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
        initGestureListener();
    }

    public FlingableTabHost(Context context) {
        super(context);
        initGestureListener();
    }

    public boolean onInterceptTouchEvent(MotionEvent event){
        super.onInterceptTouchEvent(event);
        // handle touch event. only return true if you handle it yourself here.
    }
}
第二种方法是将“为所有子视图递归设置触摸侦听器”设置为自定义触摸侦听器

ViewGroup myLayout = ...;
registerTouchListener(myLayout, myTouchListener);

private void registerTouchListener(View view, View.OnTouchListener listener) {
  view.setOnTouchListener(listener);
  if (view instanceof ViewGroup) {
    ViewGroup vg = (ViewGroup)view;
    for (int i = 0, n = vg.getChildCount(); i < n; i++) {
      View v = vg.getChildAt(i);
      registerTouchListener(v, listener);
    }
  }
}
ViewGroup myLayout=。。。;
registerTouchListener(myLayout、myTouchListener);
私有void registerTouchListener(视图,View.OnTouchListener侦听器){
view.setOnTouchListener(listener);
if(视图组的视图实例){
ViewGroup vg=(ViewGroup)视图;
for(int i=0,n=vg.getChildCount();i
谢谢@Jeffrey。但我找到了更好的方法。只需覆盖ScrollView中的dispatchkeyevent方法,并在那里处理轨迹球/键盘事件。它工作得很好

public class MyScroller extends ScrollView {

public MyScroller(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if ((KeyEvent.KEYCODE_DPAD_UP == event.getKeyCode() || KeyEvent.KEYCODE_DPAD_DOWN == event.getKeyCode())) {
            //handle key events here
    }
    return super.dispatchKeyEvent(event);
}

}

但我的问题只是发生在轨迹球/键盘上。触摸很好。我知道有类似的解决方案,比如你的#2。我可以将焦点更改侦听器设置为所有子视图。但这看起来有点难看,而且不具备良好的可伸缩性(将来我应该将侦听器添加到每个新的子视图中)
public class FlingableTabHost extends TabHost {
    private GestureDetector gestureDetector;

    public FlingableTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
        initGestureListener();
    }

    public FlingableTabHost(Context context) {
        super(context);
        initGestureListener();
    }

    public boolean onInterceptTouchEvent(MotionEvent event){
        super.onInterceptTouchEvent(event);
        // handle touch event. only return true if you handle it yourself here.
    }
}
ViewGroup myLayout = ...;
registerTouchListener(myLayout, myTouchListener);

private void registerTouchListener(View view, View.OnTouchListener listener) {
  view.setOnTouchListener(listener);
  if (view instanceof ViewGroup) {
    ViewGroup vg = (ViewGroup)view;
    for (int i = 0, n = vg.getChildCount(); i < n; i++) {
      View v = vg.getChildAt(i);
      registerTouchListener(v, listener);
    }
  }
}
public class MyScroller extends ScrollView {

public MyScroller(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if ((KeyEvent.KEYCODE_DPAD_UP == event.getKeyCode() || KeyEvent.KEYCODE_DPAD_DOWN == event.getKeyCode())) {
            //handle key events here
    }
    return super.dispatchKeyEvent(event);
}

}