我正在尝试实现滚动效果,我认为可以这样做,因为我看到一些应用实现了这个。
我有一个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>
当我滚动回收器视图时,我也可以看到浮动视图滚动,但当它到达屏幕顶部时,我希望它停在那里。我已成功实现了这一点,但在此之后我面临一个新问题。由于浮动视图位于回收器视图上方,因此触摸并滚动浮动视图时无法滚动。在这种情况下,浮动视图似乎消耗了触摸事件,因此回收器不执行任何操作。
我想要实现的是当用户想要滚动回收器视图时应该使用它。 我想把浮动视图的触摸事件发送到回收者视图。
感谢。
答案 0 :(得分:2)
前段时间我发现了同样的问题。这是我的解决方案(它有点hacky,但没有找到更好的解决方案)。放入自定义的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);
}
}
...
}
名为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>
它是从我的项目中复制的,因此名称可能会产生误导,但我认为这是可以理解的。如果您有任何疑问,请继续。