栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

ViewPager,ScrollView 嵌套ViewPager滑动冲突解决,flutter跳转传参

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ViewPager,ScrollView 嵌套ViewPager滑动冲突解决,flutter跳转传参

break;

case MotionEvent.ACTION_UP:

break;

}

return super.dispatchTouchEvent(ev);

}


ScrollView 里面嵌套ViewPager导致的滑动冲突


外部解决法

如上面所述,从 父View ScrollView着手,重写 OnInterceptTouchEvent方法,在上下滑动的时候拦截事件,在左右滑动的时候不拦截事件,返回 false,这样确保子View 的dispatchTouchEvent方法会被调用,代码 如下

public class VerticalScrollView extends ScrollView {

public VerticalScrollView(Context context) {

super(context);

}

public VerticalScrollView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public VerticalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@TargetApi(21)

public VerticalScrollView(Context context, AttributeSet attrs, int defStyleAttr, int

defStyleRes) {

super(context, attrs, defStyleAttr, defStyleRes);

}

private float mDownPosX = 0;

private float mDownPosY = 0;

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

final float x = ev.getX();

final float y = ev.getY();

final int action = ev.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

mDownPosX = x;

mDownPosY = y;

break;

case MotionEvent.ACTION_MOVE:

final float deltaX = Math.abs(x - mDownPosX);

final float deltaY = Math.abs(y - mDownPosY);

// 这里是否拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截

if (deltaX > deltaY) {// 左右滑动不拦截

return false;

}

}

return super.onInterceptTouchEvent(ev);

}

}

内部解决法

如上面上述,通过requestDisallowInterceptTouchEvent(true)方法来影响父View是否拦截事件,我们通过重写ViewPager的 dispatchTouchEvent()方法,在左右滑动的时候请求父View ScrollView不要拦截事件,其他的时候由子View 拦截事件

public class MyViewPager extends ViewPager {

private static final String TAG = “xujun”;

int lastX = -1;

int lastY = -1;

public MyViewPager(Context context) {

super(context);

}

public MyViewPager(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

int x = (int) ev.getRawX();

int y = (int) ev.getRawY();

int dealtX = 0;

int dealtY = 0;

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

dealtX = 0;

dealtY = 0;

// 保证子View能够接收到Action_move事件

getParent().requestDisallowInterceptTouchEvent(true);

break;

case MotionEvent.ACTION_MOVE:

dealtX += Math.abs(x - lastX);

dealtY += Math.abs(y - lastY);

Log.i(TAG, “dealtX:=” + dealtX);

Log.i(TAG, “dealtY:=” + dealtY);

// 这里是否拦截的判断依据是左右滑动,读者可根据自己的逻辑进行是否拦截

if (dealtX >= dealtY) { // 左右滑动请求父 View 不要拦截

getParent().requestDisallowInterceptTouchEvent(true);

} else {

getParent().requestDisallowInterceptTouchEvent(false);

}

lastX = x;

lastY = y;

break;

case MotionEvent.ACTION_CANCEL:

break;

case MotionEvent.ACTION_UP:

break;

}

return super.dispatchTouchEvent(ev);

}

}

注意事项(坑)


当我们 ScrollView 的最上层的 Layout 里面多多个孩子的时候,当下面一个孩子是 RecyclerView 或者ListView 的时候,往往会自动滑动到 ListView 或者 RecyclerView 的第一个 item,导致进入界面的时候会导致 RecyclerView 上面的 View 被滑动到界面之外,看不见,这时候的用户体验是比较差的

即结构如下面的时候

在Activity中的相关解决方法

于是我查找了相关的资料,在Activity中完美解决,主要要一下两种方法

第一种方法,重写Activity的onWindowFocusChanged()方法,在里面调用mNoHorizontalScrollView.scrollTo(0,0);方法,滑动到顶部,因为onWindowFocusChanged是在所有View绘制完毕的时候才会回调的,不熟悉的话建议先回去看一下Activity的生命周期的相关介绍

private void scroll() {

mNoHorizontalScrollView.scrollTo(0,0);

}

@Override

public void onWindowFocusChanged(boolean hasFocus) {

super.onWindowFocusChanged(hasFocus);

if(hasFocus && first){

first=false;

scroll();

}

}

第二种解决方法,调用RecyclerView上面的View的一下方法,让其获取焦点

view.setFocusable(true);

view.setFocusableInTouchMode(true);

view.requestFocus();

这段代码在初始化的时候就让该界面的顶部的某一个控件获得焦点,滚动条自然就显示到顶部了。

在Fragment中的相关解决方法

同样是调用第二种方法,调用RecyclerView上面的View的一下方法,让其获取焦点

view.setFocusable(true);

view.setFocusableInTouchMode(true);

view.requestFocus();

这段代码在初始化的时候就让该界面的顶部的某一个控件获得焦点,滚动条自然就显示到顶部了。但是该方法存在缺点,就是当我们上面的view如果滑动到一半的时候,切换到下一个Fragment,在切换回来的时候,RecyclerView的第一个item会自动滑动到顶部。目前我还没有找到相对比较好的解决这个问题的方法,大家知道相关解决方法的话也欢迎联系我,可以加我 微信或者在留言区评论,谢谢。

网友提供的解决方案

关于 ViewPagerActivity 在Fragment页面切换的时候,RecyclerView抢占焦点的问题已经解决,特别 感谢Jianqiu,他的博客地址:http://niorgai.github.io/

在 ViewPagerActivity 里面的 Fragment的 代码中加入以下代码,可以阻止 RecyclerView 的子 View 获得焦点,从而阻止 RecyclerView 抢占位置。

// 是为了确保mNoHorizontalScrollView他的子孙不能获得焦点

mNoHorizontalScrollView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

详细代码见项目中的ListFragement

个人疑点

借鉴于解决Activity的方法,目前我还没有找到一个方法是在Fragemnt界面完全绘制完毕以后回调的方法,如果大家知道怎样处理的 话,欢迎大家提出来


ViewPager里面嵌套ViewPager导致的滑动冲突


内部解决法

从子View ViewPager着手,重写 子View的 dispatchTouchEvent方法,在子 View需要拦截的时候进行拦截,否则交给父View处理,代码如下

public class ChildViewPager extends ViewPager {

private static final String TAG = “xujun”;

public ChildViewPager(Context context) {

super(context);

}

public ChildViewPager(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

int curPosition;

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

getParent().requestDisallowInterceptTouchEvent(true);

break;

case MotionEvent.ACTION_MOVE:

curPosition = this.getCurrentItem();

int count = this.getAdapter().getCount();

Log.i(TAG, “curPosition:=” +curPosition);

// 当当前页面在最后一页和第0页的时候,由父亲拦截触摸事件

if (curPosition == count - 1|| curPosition==0) {

getParent().requestDisallowInterceptTouchEvent(false);

} else {//其他情况,由孩子拦截触摸事件

getParent().requestDisallowInterceptTouchEvent(true);

}

}

return super.dispatchTouchEvent(ev);

}

}

外部解决法

这个如果要采用外部解决法来解决的话想,相对很麻烦,我提一下自己的个人思路,我们可以先测量子View在哪个区域,然后我们在根据我们按下的点是否在区域以内,如果是的话,在根据子View时候需要拦截进行处理


讨论


对于这种效果,上面是轮播图的,下面是RecyclerView或者ListView的,一般有一下几种实现方式

  • 使用我们上述提

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

高的ScrollView里面嵌套ViewPager和RecyclerView,这种实现方式需要自己解决View滑动事件的冲突,同时还有我在上述提高的在Fragment中存在的问题

  • 使用listView的addHeaderView来实现,或者是通过多种不同的item来实现

  • 使用RecyclerView添加headerView来实现,或者复用多种不同的item来实现。关于RecyclerView如何添加headerView可以参考鸿洋大神的这一篇博客 Android 优雅的为RecyclerView添加HeaderView和FooterView

  • 使用SupportLibrary中的CoordinatorLayout等控件

其布局文件如下,Activity代码见项目中的SixActivity

xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:background="@android:color/background_light"

android:fitsSystemWindows=“true”

android:layout_width=“match_parent”

android:layout_height=“300dp”

android:fitsSystemWindows=“true”

android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"

android:layout_width=“match_parent”

android:layout_height=“match_parent”

app:layout_scrollFlags=“scroll|snap”>

android:id="@+id/viewPager"

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:id="@+id/tv_page"

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/681910.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号