OnKeyListener or OnKeydown do not work when looking at children

I want to listen to ScrollView to see if it scrolls. I used OnTouchListener, it works well. But when I want to add trackball compatibility using OnKeyListener or overriding the OnKeydown method, it won't work. Focus buttons seem to be causing problems.

Any solution or workaround to solve this problem? Any help is appreciated.

Here are some demo codes to reproduce my problem:

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; } }); } } 

main.xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <com.fannyxie.MyScroller android:id="@+id/scroll_view" android:layout_width="fill_parent" android:layout_height="wrap_content" android:descendantFocusability="beforeDescendants" android:clickable="true" android:focusable="true"> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/main_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> </LinearLayout> </LinearLayout> </com.fannyxie.MyScroller> </LinearLayout> 

item.xml:

 <?xml version="1.0" encoding="utf-8"?> <com.fannyxie.MyItem xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="TITLE"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/myButton" android:text="Button"></Button> </com.fannyxie.MyItem> 

MyScroller.java

 public class MyScroller extends ScrollView { public MyScroller(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //not go into here... Log.i("MyScroller", "onKeyDown"); return super.onKeyDown(keyCode, event); } @Override public boolean onTrackballEvent(MotionEvent event) { //not go into here... Log.i("MyScroller", "onTrackballEvent"); return super.onTrackballEvent(event); } @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { //some times go into here, when no button get the focus when entering first time Log.i("MyScroller", "request focus in descendants"); return super.onRequestFocusInDescendants(direction, previouslyFocusedRect); } } 

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); } } 
+6
source share
2 answers

Thanks @ Jeffrey. But I found a better way to do this. Just override the dispatchkeyevent method in ScrollView and handle the trackball / keyboard events there. It works well.

 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); } } 
+6
source

touch events are passed from child to parent. if any child consumes an even (returns true), he stops; it is not passed on to parents. therefore, 2 solutions,

First, extend the view container class and override onInterceptTouchEvent() . here is an example where I did this for TabHost , but for you it could be LinearLayout or something else,

 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. } } 

the second way is to set the touch recursively to listen to all child views on your custom listener,

 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); } } } 
0
source

Source: https://habr.com/ru/post/920245/


All Articles