Android - 向其他视图发送触摸事件
Android - Send touch event to other views
我正在尝试实现滚动效果,我认为可以实现,因为我看到一些应用程序实现了这一点。
我有一个 FrameLayout,在这个布局中我有:
- 回收者观点
- 浮动视图
<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>
当我滚动回收站视图时,我也可以看到浮动视图滚动,但是当它到达屏幕顶部时,我希望它停在那里。我已经成功实施了这一点,但之后我面临一个新问题。因为浮动视图在回收器视图上方,所以触摸和滚动浮动视图时我无法滚动。在这种情况下,浮动视图似乎消耗了触摸事件,因此回收器什么都不做。
我想要实现的是当用户想要滚动回收视图时应该使用它。
我正在考虑将浮动视图的触摸事件发送到回收器视图。
谢谢。
我前段时间发现了同样的问题。这是我的解决方案(有点老套,但没有找到更好的解决方案)。放入您的自定义 FrameLayout class:
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);
}
}
...
}
名为 actionBarWrapperViewGroup 的 ViewGroup 是您示例中的流式布局。
对于 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>
它是从我的项目中实时复制的,因此名称可能会产生误导,但我认为这是可以理解的。如果您有任何问题,请继续。
我正在尝试实现滚动效果,我认为可以实现,因为我看到一些应用程序实现了这一点。
我有一个 FrameLayout,在这个布局中我有: - 回收者观点 - 浮动视图
<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>
当我滚动回收站视图时,我也可以看到浮动视图滚动,但是当它到达屏幕顶部时,我希望它停在那里。我已经成功实施了这一点,但之后我面临一个新问题。因为浮动视图在回收器视图上方,所以触摸和滚动浮动视图时我无法滚动。在这种情况下,浮动视图似乎消耗了触摸事件,因此回收器什么都不做。
我想要实现的是当用户想要滚动回收视图时应该使用它。 我正在考虑将浮动视图的触摸事件发送到回收器视图。
谢谢。
我前段时间发现了同样的问题。这是我的解决方案(有点老套,但没有找到更好的解决方案)。放入您的自定义 FrameLayout class:
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);
}
}
...
}
名为 actionBarWrapperViewGroup 的 ViewGroup 是您示例中的流式布局。
对于 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>
它是从我的项目中实时复制的,因此名称可能会产生误导,但我认为这是可以理解的。如果您有任何问题,请继续。