手把手实现ScrollView+ViewPager+RecyclerView常规嵌套首页布局

本文详细介绍了如何实现ScrollView+ViewPager+RecyclerView的嵌套布局,包括SwipeRefreshLayout的使用,以及处理滑动冲突的方法。通过自定义ComboScrollLayout和ComboChildLayout,解决了TabLayout和ViewPager2不支持嵌套滑动的问题,同时提供了完整项目的GitHub链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

目前主流APP常见首页布局有顶部banner+列表、顶部banner+ViewPager等形式,如果有刷新需求,再通过外层嵌套SwipeRefreshLayout以实现刷新需求。若能掌握这些布局方式,就能应对大部分APP需求。

XML布局

布局用到系统控件,需要添加依赖:

implementation ‘androidx.appcompat:appcompat:1.1.0’
implementation ‘androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03’
implementation “androidx.viewpager2:viewpager2:1.0.0”
implementation ‘com.google.android.material:material:1.1.0-beta02’

一. SwipeRefreshLayout+顶部banner+RecyclerView

效果预览:
在这里插入图片描述

xml实现:

<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipe_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NestedScrollViewActivity">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".NestedScrollViewActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/banner_view"
                android:layout_width="match_parent"
                android:layout_height="300dp" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

使用androidx.swiperefreshlayout.widget.SwipeRefreshLayout、androidx.core.widget.NestedScrollView、androidx.recyclerview.widget.RecyclerView按照这种排列布局即可实现,不需要自定义view处理滑动冲突。so easy~

ps:RecyclerView初始化、adapter初始化、模拟数据填充等代码,可以参考NestedRecyclerViewActivity.java

二. SwipeRefreshLayout+顶部banner+ViewPager

效果预览:
在这里插入图片描述

xml实现:

<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipe_refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NestedScrollViewActivity">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".NestedScrollViewActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/banner_view"
                android:layout_width="match_parent"
                android:layout_height="300dp" />

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tablayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <androidx.viewpager2.widget.ViewPager2
                android:id="@id/viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

布局方式和上面类似,只是将RecyclerView替换成TabLayout和ViewPager2。
接下来运行,会发现…有点不对劲,滑动卡壳了。怎么回事,为什么同样是系统控件,TabLayout和ViewPager2就不支持嵌套滑动呢?

点开SwipeRefreshLayout和NestedScrollView源码,发现他们均实现了NestedScrollingParent2、NestedScrollingChild2接口,RecyclerView实现了NestedScrollingChild2接口。而TabLayout和ViewPager2没有实现NestedScrollingParent2、NestedScrollingChild2任一接口。

关于NestedScrollingParent2、NestedScrollingChild2接口

  • NestedScrollingParent2官方注释:

This interface should be implemented by {@link android.view.ViewGroup ViewGroup} subclasses that wish to support scrolling operations delegated by a nested child view.
Classes implementing this interface should create a final instance of a {@link NestedScrollingParentHelper} as a field and delegate any View or ViewGroup methods to the NestedScrollingParentHelper methods of the same signature.

简单说就是希望支持嵌套滑动的父容器需要实现此接口,处理来自子视图传递的滑动事件。可以借助NestedScrollingParentHelper辅助类来执行相应方法。

  • NestedScrollingChild2官方注释:

This interface should be implemented by {@link View View} subclasses that wish to support dispatching nested scrolling operations to a cooperating parent {@link android.view.ViewGroup ViewGroup}.
Classes implementing this interface should create a final instance of a {@link NestedScrollingChildHelper} as a field and delegate any View methods to the NestedScrollingChildHelper methods of the same signature.

简单说就是希望支持嵌套滑动的子视图需要实现此接口,优先将滚动事件向上传递给父容器处理。可以借助NestedScrollingChildHelper辅助类来执行相应方法。

  • NestedScrollingParent2接口方法说明:
/**
 * 子视图触发滑动时会回调该方法,父容器在该方法中根据子view、滑动方向、触摸类型等判断自己是否支持接收,
 * 若接收返回true,否则返回false。(可由NestedScrollingChild2的startNestedScroll方法触发)
 */
boolean onStartNestedScroll(@NonNull View child, @NonNull View target, @ScrollAxis int axes, @NestedScrollType int type);

/**
 * onStartNestedScroll返回true后会回调该方法,可在此方法中做一些初始配置操作。
 */
void onNestedScrollAccepted(@NonNull View child, @NonNull View target, @ScrollAxis int axes, @NestedScrollType int type);

/**
 * 开始滑动时,子视图会优先回调该方法。父容器可以处理自己的滚动操作,之后将剩余的滚动偏移量
 * 传回给子视图。(可由NestedScrollingChild2的dispatchNestedPreScroll方法触发)
 */
void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, @NestedScrollType int type);

/**
 * 子视图处理完剩余的滚动偏移量后,若还有剩余,则将剩余的滚动偏移量再通过该回调传给
 * 父容器处理。(可由NestedScrollingChild2的dispatchNestedScroll方法触发)
 */
void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsume
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值