复杂布局SwipeRefreshLayout+TabLayout+NestedScrollView+RecyclerView冲突

复杂布局SwipeRefreshLayout+NestedScrollView+ViewPager+TabLayout
引起滑动冲突

今天做了项目的时候遇到一个布局比较复杂的界面。
最外层是一个SwipeRefreshLayout
然后包裹了一个CoordinatorLayout
其中又使用到了可折叠的AppBarLayout
以及NestedScrollView和ViewPager

总体的布局是这样子的

<SwipeRefreshLayout>
    <CoordinatorLayout>
        <AppBarLayout>
            <轮播图/>
            <分类/>
            <CollapsingToolbarLayout>
                <TabLayout/>
            </CollapsingToolbarLayout>
        </AppBarLayout>
        <NestedScrollView>
            <ViewPager/>
        </NestedScrollView>
    </CoordinatorLayout>
</SwipeRefreshLayout>

其中Viewpager有嵌套了两个带有RecyclerView的Fragment

首先是RecyclerView和NestedScrollViewd 冲突


首先是RecyclerView和NestedScrollViewd 冲突,造成滑动不流畅的问题

这个比较简单,设置RecyclerView.setNestedScrollingEnabled(false);
就可以解决。

然后是SwipeRefreshLayout和NestedScrollView刷新的问题

SwipeRefreshLayout中嵌套了NestedScrollView会导致滑动NestedScrollView的时候激活SwipeRefreshLayout
解决办法是通过监听滑动是否到顶部,具体代码如下:

NestedScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                    SwipeRefreshLayout.setEnabled
                    (NestedScrollView.getScrollY() == 0);
            }
        });

最后就是一个TabLayout和SwipeRefreshLayout还有NestedScrollView组合使用的问题了

因为是嵌套了CoordinatorLayout,AppBarLayout和CollapsingToolbarLayout形成一个可以折叠的功能,
顶部的轮播图和分类可以折叠起来,而TabLayout与ViewPager结合,
其中ViewPager由包括了RecyclerView

然后问题就来了

首先,当你滑动Viewpager中的RecyclerView后,界面会往下滑动,直到TabLayout固定在顶部,
然后滑动事件转移到RecyclerView开始下滑,这一切都是正常的,
但是当你往回滑动的时候问题就出现了,因为TabLayout固定在顶部,
当RecyclerView往回滑动到最上后按照理想的状态,
下一个动作是轮播图开始从这点状态变为展开,但是APP会以为你已经滑到顶部了,
而实际上顶部折叠起来的轮播图还未展开,这时候你继续下滑就会唤出SwipeRefreshLayout
这并不是我们想要的效果,一些帖子之后,发现appBarLayout中带有一个监听事件addOnOffsetChangedListener能够监听折叠和非折叠的距离
那么,刚才的代码就需要修改一下,变成下面这样,通过判断AppBarLayout和NestedScrollView是否都已到达顶部。

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (!binding.refreshFind.isRefreshing()) {    //如果不在刷新状态
                    //判断是否滑动到最顶部
                    binding.refreshFind
                            .setEnabled(binding.scrollviewFins.getScrollY() == verticalOffset);
                }
            }
        });

自己记录一下,原创文章,转载请注明出处

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
这个实现需要以下步骤: 1. 在布局文件中添加ViewPager2和TabLayout: ```xml <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabGravity="fill" app:tabMode="fixed" /> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 2. 在代码中初始化ViewPager2和TabLayout: ```java ViewPager2 viewPager = findViewById(R.id.view_pager); TabLayout tabLayout = findViewById(R.id.tab_layout); viewPager.setAdapter(new MyPagerAdapter(this)); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText("Tab " + (position + 1)) ).attach(); ``` 3. 创建PagerAdapter,用于管理Fragment: ```java public class MyPagerAdapter extends FragmentStateAdapter { public MyPagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new MyFragment(position + 1); } @Override public int getItemCount() { return 3; } } ``` 4. 创建Fragment,用于显示RecyclerView: ```java public class MyFragment extends Fragment { private int mTabNumber; public MyFragment(int tabNumber) { mTabNumber = tabNumber; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_my, container, false); RecyclerView recyclerView = rootView.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(new MyRecyclerViewAdapter(mTabNumber)); return rootView; } } ``` 5. 创建RecyclerViewAdapter,用于显示数据: ```java public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { private int mTabNumber; public MyRecyclerViewAdapter(int tabNumber) { mTabNumber = tabNumber; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_my, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { holder.mTextView.setText("Tab " + mTabNumber + ", Item " + (position + 1)); } @Override public int getItemCount() { return 10; } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(@NonNull View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.text_view); } } } ``` 6. 创建RecyclerView的item布局文件和Fragment的布局文件: item_my.xml: ```xml <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" /> ``` fragment_my.xml: ```xml <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 这样就完成了实现。每个Tab都显示一个RecyclerView,切换Tab时切换RecyclerView
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值