2011-06-16 96 views
32

我有一个自定义ViewSwitcher其中我实现了触摸事件,因此我可以使用触摸屏在屏幕上滚动。将触摸事件传递给父视图

我的布局,层次结构如下所示:

<ViewSwitcher> 

    <LinearLayout> 
     <ListView /> 
    </LinearLayout> 

    <LinearLayout> 
     <ListView /> 
    </LinearLayout> 

</ViewSwitcher> 

现在的问题是,触摸事件正在由 ListViews消耗,我不能切换的意见。当我 没有ListViews时它工作正常。我需要能够滚动浏览 的视图并滚动ListView

我该如何解决这个问题?

编辑:我还需要ListView项目可点击。

在此先感谢!

回答

74

谢谢大家回答这个问题。但我能够以一种更简单的方式解决问题。由于我的ViewSwitcher未检测到触摸事件,因此我截获了触摸事件,称为onTouchEvent(),并返回false。在这里:

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) 
{ 
    onTouchEvent(ev); 
    return false; 
} 

通过重写onInterceptTouchEvent(),我能够在活动中拦截触摸事件。然后我拨打ViewSwitcher中的onTouchEvent()来处理ListViews的切换。最后通过返回false,确保ViewGroup不消耗该事件。

+0

假设我想在gridView的单元格内有一个horizo​​ntalScrollView,那么如何使用这个解决方案在这种情况下不能很好地工作,并且允许我同时执行水平滚动和单击/长按GridView的单元格? – 2014-01-18 14:32:54

+1

这帮助我解决了一个ViewPager问题,我认为我会为后代抛出这个问题。我在ViewPager内部有必须附加OnClickListener/OnTouchListener的视图。这些消耗运动事件导致父ViewPager不滚动。通过将这个技巧应用于包含视图寻呼机的布局,我可以将所有触摸事件转发给寻呼机(滚动器),而不管子是否将该事件用作点击。 – mszaro 2015-03-13 21:10:52

+5

我不认为这是在onInterceptTouchEvent()中调用onTouchEvent()的“官方”方式,除非这是指某种破解。因为如果从onInterceptTouchEvent()返回true,onTouchEvent()将被调用。 – KarolDepka 2016-01-16 20:36:03

0

您是否尝试将ListView项目设置为不可点击的状态,如下所示:listView.setClickable(false);这应该向上传播点击事件。

+0

这因此未修复它。而且我还需要listview的项目是可点击的。 – 2011-06-16 17:21:58

0

如果您的视图想要传递事件,请确保您在onTouchEvent中返回false。否则,平台认为您已使用该事件,无需进一步处理。

1

我不认为有这样一个简单的方法。

这并不复杂,但您需要创建自己的视图来扩展ListView。然后你可以重写onTouch处理程序并决定(取决于触摸事件)是否要处理它(并返回true)或将其传递给父视图。

的问题还在于,一旦视图处理触摸事件,它是一个将得到所有剩余的...

Android documentation

onTouch() - 这返回一个布尔值为 指示您的听众 是否消耗此事件。重要的是 的事情是这个事件可以有 多个行动,其他每个 。因此,如果您在 收到关闭操作事件时返回false,则您的 表示您没有在该事件的后续操作中使用 事件并且也不感兴趣 。 因此,你将不会被要求对事件中的任何 其他操作,如 的手指手势,或最终 后续行动事件

因此,举例来说,如果你想拥有垂直移动到在列表中滚动并且在相同的触摸事件期间(不用抬起手指),您想要水平移动来切换视图,这将是相当具有挑战性的。

但是,如果您可以使用手势作为示例或处理自定义视图中的所有内容,并根据MotionEvent的内容将命令发送到ViewSwitcher。

0

我所做的就是在viewwitcher的listview上设置toucheventlistener,处理事件,检测fling动作并调用viewswitcher的metchod。有用。

4

通过孩子视图的的TouchEvent到父视图最简单的方法是添加这孩子的看法:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    super.onTouchEvent(event); 
    return false; 
} 
+0

这是我为RecyclerView工作的唯一解决方案。看起来你必须扩展RecyclerView,覆盖onTouchEvent,并禁用任何进一步的交互,并继续事件链。 – Georgi 2017-03-30 19:03:30

0

你也可以插入一个呼叫处理toucheventdispatchTouchEvent,但在这种情况下,你必须还覆盖onTouchEvent返回true,否则只有第一个MotionEvent手势的向下将被传递。

这是可触摸的包装容器:

<?xml version="1.0" encoding="utf-8"?> 
<view xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/pager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    class="com.example.myapp.FragmentContainer$TouchableWrapper" /> 

和类:

public static class TouchableWrapper extends FrameLayout { 
    private GestureDetector gestureDetector; 
    public void setGestureDetector(GestureDetector gestureDetector) { 
     this.gestureDetector = gestureDetector; 
    } 

    // these constructors for the XML inflater 
    public TouchableWrapper(Context context) { 
     super(context); 
    } 
    public TouchableWrapper(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 
    public TouchableWrapper(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     Log.d(TAG, "onInterceptTouchEvent " + event.toString()); 
     return false; // true for intercept, false è default and pass on to children View 
    } 
    @Override 
    public boolean dispatchTouchEvent(MotionEvent event) { 
     Log.d(TAG, "dispatchTouchEvent " + event.toString()); 
     gestureDetector.onTouchEvent(event); 
     return super.dispatchTouchEvent(event); 
    } 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     Log.d(TAG, "onTouchEvent " + event.toString()); 
     return true; //return super.onTouchEvent(event); 
    } 
} 

这是GestureDetector参考:

private GestureDetector gestureDetector; 

此所述GestureListener

private GestureDetector.SimpleOnGestureListener sOGL = new GestureDetector.SimpleOnGestureListener() { 
    private static final int SWIPE_THRESHOLD = 100; 
    private static final int SWIPE_VELOCITY_THRESHOLD = 100; 

    @Override 
    public boolean onDown(MotionEvent e) { 
     return true; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     boolean result = false; 
     try { 
      float diffY = e2.getY() - e1.getY(); 
      float diffX = e2.getX() - e1.getX(); 
      if (Math.abs(diffX) > Math.abs(diffY)) { 
       if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { 
        if (diffX > 0) { 
         goToRight(); // onSwipeRight(); 
        } else { 
         goToLeft(); // onSwipeLeft(); 
        } 
       } 
       result = true; 
      } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { 
       if (diffY > 0) { 
        // onSwipeBottom(); 
       } else { 
        // onSwipeTop(); 
       } 
      } 
      result = true; 

     } catch (Exception exception) { 
      exception.printStackTrace(); 
     } 
     return result; // return false indicate event not handled 
    } 
}; 

蚂蚁这种加载可触摸容器片段和包含片段:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    Log.d(TAG, "onCreateView()"); 
    View view = inflater.inflate(R.layout.fragmentcontainer, container, false); 

    gestureDetector = new GestureDetector(view.getContext(), sOGL); 
    ((FragmentContainer.TouchableWrapper) view).setGestureDetector(gestureDetector); 

    FragmentManager fm = this.getFragmentManager(); 
    FragmentTransaction ft = fm.beginTransaction(); 
    ft.replace(R.id.pager, frag).commit(); 

    return view; 
} 
0

在我父母的布局,我已经找到了防止儿童捕捉触摸事件的唯一方法是通过覆盖onInterceptTouchEvent返回真正。

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) 
{ 
    return true; 
} 
0

有必要以处理TextView的触控与自动链接=父视图“三化” 这样做:

private LinearLayout mParentView; 
private TextView mTextView; 
private View.OnTouchListener mParentListener = new OnTouchListener() { 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     ...... 
     return false; 
    } 
}; 
mParentView.setOnTouchListener(mParentListener); 

mTextView.setOnTouchListener(new View.OnTouchListener() { 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     mParentListener.onTouch(mParentView, event); 
     return false; 
    } 
}; 
相关问题