Android-向其他视图发送触摸事件

Android-向其他视图发送触摸事件,android,layout,android-recyclerview,Android,Layout,Android Recyclerview,我正在尝试实现滚动效果,我认为这是可以做到的,因为我看到一些应用程序实现了这一点 我有一个框架布局,在这个布局中我有: -回收者的观点 -浮动视图 <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:layout_widt

我正在尝试实现滚动效果,我认为这是可以做到的,因为我看到一些应用程序实现了这一点

我有一个框架布局,在这个布局中我有: -回收者的观点 -浮动视图

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout // float layout here
        android:layout_width="match_parent"
        android:layout_height="100dp">
    </LinearLayout>
</FrameLayout>

当我滚动recycler视图时,我也可以看到float视图滚动,但当它到达屏幕顶部时,我希望它停止在那里。我已经成功地实现了这一点,但在那之后,我面临着一个新问题。因为float视图位于recycler视图上方,所以触摸并滚动float视图时无法滚动。在这种情况下,float视图似乎消耗了touch事件,因此回收者什么也不做

我想要实现的是,当用户想要滚动回收器视图时,应该使用它。 我想把float视图的touch事件发送到recycler视图


谢谢。

我不久前发现了同样的问题。这是我的解决方案(有点粗糙,但没有找到更好的解决方案)。在自定义FrameLayout类中放入:

public class CustomFrameLayout extends FrameLayout {

    ... 

    @InjectView(R.id.rv_details)
    RecyclerView recyclerView;

    @InjectView(R.id.ll_details_action_bar_wrapper)
    ViewGroup actionBarWrapperViewGroup;

    private List<MotionEvent> cachedEventList = new ArrayList<>();

    private boolean touchIsFromActionBar;

    private boolean yTranslationThresholdPassed;

    // Pawel Janeczek
    // Those two overrides is for forwarding touch events, that started on action bar, to recyclerview.
    // But you may ask, why there are so many lines? it should by only recyclerView.dispatchTouchEvent(ev) and it should be fine
    // It is because RecyclerView when it is starting scrolling it sends parent.requestDisallowInterceptTouchEvent which disables sending onInterceptTouchEvent to parent
    // In such case we must set a flag touchIsFromActionBar when motion event starts and is in action bar, and then when this flag is set we remove calling super on requestDisallowInterceptTouchEvent
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (action == MotionEvent.ACTION_DOWN && viewUtils.isWithinViewBounds(actionBarWrapperViewGroup, ev.getRawX(), ev.getRawY())) {
            touchIsFromActionBar = true;
        }
        if (touchIsFromActionBar && shouldDispatchEventToRecyclerView(ev)) {
            if (!listUtils.isEmpty(cachedEventList)) {
                for (MotionEvent motionEvent : cachedEventList) {
                    recyclerView.dispatchTouchEvent(motionEvent);
                }
                cachedEventList.clear();
            }
            recyclerView.dispatchTouchEvent(ev);
        }
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            cachedEventList.clear();
            yTranslationThresholdPassed = false;
            touchIsFromActionBar = false;
        }
        return false;
    }

    private boolean shouldDispatchEventToRecyclerView(MotionEvent event) {
        if (yTranslationThresholdPassed) {
            return true;
        } else if (listUtils.isEmpty(cachedEventList)) {
            cachedEventList.add(MotionEvent.obtain(event));
            return false;
        }

        int yTranslationThreshold = 2;

        MotionEvent lastEvent = listUtils.getLast(cachedEventList);
        if (Math.abs(lastEvent.getY() - event.getY()) > yTranslationThreshold) {
            yTranslationThresholdPassed = true;
            return true;
        } else {
            cachedEventList.add(MotionEvent.obtain(event));
            return false;
        }
    }

    @Override
    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        if (!touchIsFromActionBar) {
            super.requestDisallowInterceptTouchEvent(disallowIntercept);
        }
    }
    ...
}
公共类CustomFrameLayout扩展了FrameLayout{
... 
@注入视图(R.id.rv_详图)
回收视图回收视图;
@InjectView(R.id.ll\u详细信息\u操作\u栏\u包装器)
视图组actionBarWrapperViewGroup;
private List cachedEventList=new ArrayList();
私有布尔触摸来自ActionBar;
私有布尔yTranslationThresholdPassed;
//帕维尔·詹切克
//这两个覆盖用于将从操作栏上开始的触摸事件转发到recyclerview。
//但你可能会问,为什么会有这么多线路?它应该只由recyclerView.dispatchTouchEvent(ev)完成,应该没问题
//这是因为RecyclerView在开始滚动时发送parent.RequestDisallowWinterCeptTouchEvent,这将禁用向父级发送onInterceptTouchEvent
//在这种情况下,我们必须在运动事件开始并处于动作栏时设置一个标志touchIsFromActionBar,然后当设置该标志时,我们删除对RequestDisallowWinterCeptTouchEvent的调用
@凌驾
公共布尔值onInterceptTouchEvent(MotionEvent ev){
int action=ev.getAction();
if(action==MotionEvent.action\u DOWN&&viewUtils.isWithinViewBounds(actionBarWrapperViewGroup,ev.getRawX(),ev.getRawY()){
touchIsFromActionBar=true;
}
如果(从ActionBar触摸并应发送事件到循环视图(ev)){
如果(!listUtils.isEmpty(cachedEventList)){
对于(MotionEvent MotionEvent:cachedEventList){
recyclerView.dispatchTouchEvent(运动事件);
}
cachedEventList.clear();
}
recyclerView.dispatchTouchEvent(ev);
}
if(action==MotionEvent.action\u CANCEL | | action==MotionEvent.action\u UP){
cachedEventList.clear();
yTranslationThresholdPassed=false;
touchIsFromActionBar=false;
}
返回false;
}
私有布尔值shouldDispatchEventToRecyclerView(运动事件){
如果(yTranslationThresholdPassed){
返回true;
}else if(listUtils.isEmpty(cachedEventList)){
cachedEventList.add(MotionEvent.get(event));
返回false;
}
int-ytransationthreshold=2;
MotionEvent lastEvent=listUtils.getLast(cachedEventList);
if(Math.abs(lastEvent.getY()-event.getY())>ytransationthreshold){
yTranslationThresholdPassed=true;
返回true;
}否则{
cachedEventList.add(MotionEvent.get(event));
返回false;
}
}
@凌驾
public void requestDisallowinetCeptTouchEvent(布尔值DisallowinetCept){
如果(!touchIsFromActionBar){
super.requestDisallowerceptoochevent(Disallowercept);
}
}
...
}
名为actionBarWrapperViewGroup的视图组是示例中的流布局

和用于CustomFrameLayout的xml:

<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <RecyclerView
            android:id="@+id/rv_details"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />

    <LinearLayout
            android:id="@+id/ll_details_action_bar_wrapper"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

        ...

        <FrameLayout
            android:id="@+id/ll_details_action_bar_container"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="@dimen/default_bar_height"
            android:background="?colorPrimary"/>

        ...
    </LinearLayout>
</merge>

...
...

这是从我的项目现场复制,所以名称可能会误导,但我认为这是可以理解的。如果您有任何问题,请继续。

谢谢,我会回来查看结果。:)太好了,一切正常。:)。标记为答案的。谢谢。我发现了一个小问题(不是大问题)。当您轻触“actionBarWrapperViewGroup”并滚动时,不会滚动回收器视图。但它在滚动像素量后立即跳转。请尝试将YTranslationReshold更改为1。我认为这应该解决问题