NestedScrollView、ScrollView嵌套Recyclerview的冲突、显示不完整及焦点问题解决方案

·  阅读 1668

最近项目中嵌套的控件比较多,遇到了不少问题,昨天解决了,赶紧记录下

场景是 ViewPager2 嵌套 NestedScrollView 嵌套 RecyclerView 瀑布流

效果图:

没办法,压缩太严重,凑合看

主要问题如下:

  1. NestedScrollView / ScrollView 嵌套 RecyclerView 冲突,不滚动、显示不完整、或者不显示问题
  2. NestedScrollView / ScrollView 嵌套 RecyclerView 瀑布流双重滑动问题
  3. 打开页面后定位到 RecyclerView 问题

主要就这三个问题,下面按照顺序分别解决,NestedScrollView 和 ScrollView 我试过了,效果没区别

问题一:NestedScrollView / ScrollView 嵌套 RecyclerView 冲突,不滚动、显示不完整、或者不显示问题

关于该问题,是最主要的问题,CSDN 上说了很多都是要修改 layout_height match_parent 为 wrap_content,其实这个没什么影响,因为问题本质是我们需要给 RecyclerView 一个固定的高度来解决的。

如果你设置为 match_parent,就会出现不显示的效果,我们只要给 RecyclerView 设置一个固定的高度。或者动态计算控件高度,然后设置上,就可以解决该问题了。

我们可以在 XML 中给 RecyclerView 的 layout_height 设置一个固定高度,1000dp 之类的,这样可以解决。但是我们没办法控制瀑布流的高度。但是实际开发中我们不能确定数据需要加载多高,所以写死高度可能不太好。所以布局代码就不贴了

换种思路就是动态计算出所需的高度,然后设置给他就可以了。

我这里是根据瀑布流数据的长度来处理的。可以根据具体的业务计算高度。

		// 计算需要高度
        ViewGroup.LayoutParams layoutParams = menuHomeBinding.rvWaterFallsFlow.getLayoutParams();
        int height = 0;
        for (int i = 0; i < waterFallsFlowBeanArrayList.size(); i++) {
            if (i % 2 == 0) {
                height += 400;
            } else if (i % 3 == 0) {
                height += 360;
            } else {
                height += 440;
            }
        }
        // 只要把业务处理后的高度赋值给layoutParams.height就可以了
        layoutParams.height = height - waterFallsFlowBeanArrayList.size() * 100;
        menuHomeBinding.rvWaterFallsFlow.setLayoutParams(layoutParams);
复制代码

这样就可以了
我也有想过在 Adapter 中计算高度,然后得到后处理,但是试了下,获取的一直是 0,如果有思路的可以告知下。

问题二:NestedScrollView / ScrollView 嵌套 RecyclerView 瀑布流双重滑动问题

在正常显示后,会出现 NestedScrollView / ScrollView 滑动,里面的 RecyclerView 也可以滑动的效果。

这里我们需要处理一下,不让里面的 RecyclerView 滑动,而是随着 NestedScrollView / ScrollView 一起滑动。
这里呢,官方 API 中有一个属性,可以帮助我们解决这个问题。就是这个 setNestedScrollingEnabled,这是启动嵌套滚动的开关。默认是 true。

当然也可以在布局文件中设置,如果是在布局文件中设置,是要在 RecyclerView 上设置的。我这里是在代码中设置的。

		menuHomeBinding.rvWaterFallsFlow.setNestedScrollingEnabled(false);
复制代码

问题三:打开页面后定位到 RecyclerView 问题

在上面的基础上,效果已经可以正常显示,但是打开 App 后就自动定位到 RecyclerView 的位置 了。

这是因为 RecyclerView 是默认自动获取焦点的,所以我们需要处理一下。有两种方式

XML 方式和代码中设置的方式,先说一下区别:
在 XML 中设置,切换其他页面后回来,焦点总是在顶部(设置焦点的位置);
如果在代码中设置,切换页面后回来,位置会停留在之前浏览的位置。

下面是具体的解决方案。

  1. XML 方式

    在 NestedScrollView / ScrollView 的第一个子控件上添加获取焦点的属性

                android:focusable="true"
                android:focusableInTouchMode="true"
复制代码

这里需要说明一下,NestedScrollView和ScrollView都是只允许有一个子控件,这里说的第一个子控件是唯一子控件里面的第一个子控件。

<androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <!-- 第一个子控件-->
            <androidx.viewpager.widget.ViewPager
                android:id="@+id/vp_home_menu_banner"
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:layout_marginStart="10dp"/>
复制代码
  1. 代码中处理

    第二中是在代码中处理。我采用的这种方式,也很简单。

    既然是 RecyclerView 默认自动获取焦点,那么我们只要在代码中设置不让他默认获取焦点就可以解决了。

		menuHomeBinding.rvWaterFallsFlow.setFocusable(false);
复制代码

总结

基本上用到的属性就

		menuHomeBinding.rvWaterFallsFlow.setHasFixedSize(true);
        menuHomeBinding.rvWaterFallsFlow.setNestedScrollingEnabled(false);
        menuHomeBinding.rvWaterFallsFlow.setFocusable(false);
复制代码

要点:确定 RecyclerView 的高度

完整代码
XML:请忽略无用的代码,只要看最外层 NestedScrollView 和最下面的 RecyclerView 就 OK

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>

    </data>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <!-- Banner -->
            <androidx.viewpager.widget.ViewPager
                android:id="@+id/vp_home_menu_banner"
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:layout_marginStart="10dp"/>
            <!--   功能菜单     -->
            <LinearLayout
                android:id="@+id/ll_home_menu"
                android:layout_width="match_parent"
                android:layout_height="90dp"
                android:layout_marginHorizontal="16dp"
                android:layout_marginTop="10dp"
                android:orientation="horizontal">

                <LinearLayout
                    android:id="@+id/ll_home_menu_reservation"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginEnd="16dp"
                    android:layout_weight="1"
                    android:background="@drawable/style_constraintlayout_purple_gradient_bg"
                    android:gravity="center"
                    android:orientation="vertical">

                    <androidx.cardview.widget.CardView
                        android:id="@+id/cv_menu_home_reservation"
                        android:layout_width="match_parent"
                        android:layout_height="60dp"
                        android:layout_marginHorizontal="6dp"
                        android:layout_marginTop="4dp"
                        app:cardCornerRadius="8dp"
                        app:cardElevation="0dp">

                        <ImageView
                            android:layout_width="60dp"
                            android:layout_height="match_parent"
                            android:layout_gravity="center"
                            android:scaleType="centerInside"
                            android:src="@drawable/home_menu_reservation" />
                    </androidx.cardview.widget.CardView>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="20dp"
                        android:layout_marginTop="2dp"
                        android:layout_marginBottom="4dp"
                        android:gravity="center"
                        android:text="@string/homeMenuReservation"
                        android:textColor="@color/white" />
                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_home_menu_group"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginStart="8dp"
                    android:layout_marginEnd="16dp"
                    android:layout_weight="1"
                    android:background="@drawable/style_constraintlayout_blue_gradient_bg"
                    android:gravity="center"
                    android:orientation="vertical">

                    <androidx.cardview.widget.CardView
                        android:id="@+id/cv_menu_home_group"
                        android:layout_width="match_parent"
                        android:layout_height="60dp"
                        android:layout_marginHorizontal="6dp"
                        android:layout_marginTop="4dp"
                        app:cardCornerRadius="8dp"
                        app:cardElevation="0dp">

                        <ImageView
                            android:layout_width="60dp"
                            android:layout_height="match_parent"
                            android:layout_gravity="center"
                            android:scaleType="centerInside"
                            android:src="@drawable/home_menu_group" />
                    </androidx.cardview.widget.CardView>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="20dp"
                        android:layout_marginTop="2dp"
                        android:layout_marginBottom="4dp"
                        android:gravity="center"
                        android:text="@string/homeMenuGroup"
                        android:textColor="@color/white" />
                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_home_menu_unpack"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginStart="8dp"
                    android:layout_marginEnd="16dp"
                    android:layout_weight="1"
                    android:background="@drawable/style_constraintlayout_orange_gradient_bg"
                    android:gravity="center"
                    android:orientation="vertical">

                    <androidx.cardview.widget.CardView
                        android:id="@+id/cv_menu_home_unpack"
                        android:layout_width="match_parent"
                        android:layout_height="60dp"
                        android:layout_marginHorizontal="6dp"
                        android:layout_marginTop="4dp"
                        app:cardCornerRadius="8dp"
                        app:cardElevation="0dp">

                        <ImageView
                            android:layout_width="60dp"
                            android:layout_height="match_parent"
                            android:layout_gravity="center"
                            android:scaleType="centerInside"
                            android:src="@drawable/home_menu_unpack" />
                    </androidx.cardview.widget.CardView>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="20dp"
                        android:layout_marginTop="2dp"
                        android:layout_marginBottom="4dp"
                        android:gravity="center"
                        android:text="@string/homeMenuUnpack"
                        android:textColor="@color/white" />
                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_home_menu_game"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_marginStart="8dp"
                    android:layout_weight="1"
                    android:background="@drawable/style_constraintlayout_red_gradient_bg"
                    android:gravity="center"
                    android:orientation="vertical">

                    <androidx.cardview.widget.CardView
                        android:id="@+id/cv_menu_home_game"
                        android:layout_width="match_parent"
                        android:layout_height="60dp"
                        android:layout_marginHorizontal="6dp"
                        android:layout_marginTop="4dp"
                        app:cardCornerRadius="8dp"
                        app:cardElevation="0dp">

                        <ImageView
                            android:layout_width="60dp"
                            android:layout_height="match_parent"
                            android:layout_gravity="center"
                            android:scaleType="centerInside"
                            android:src="@drawable/home_menu_game" />
                    </androidx.cardview.widget.CardView>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="20dp"
                        android:layout_marginTop="2dp"
                        android:layout_marginBottom="4dp"
                        android:gravity="center"
                        android:text="@string/homeMenuGame"
                        android:textColor="@color/white" />
                </LinearLayout>

                <TextView
                    android:id="@+id/tv_home_menu_gourmet"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:drawableTop="@mipmap/ic_home_menu_gourmet"
                    android:drawablePadding="3dp"
                    android:gravity="center"
                    android:text="@string/homeMenuGourmet"
                    android:visibility="gone" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/lightGray"
                android:nestedScrollingEnabled="false"
                android:orientation="vertical">
                <!-- 秒杀 -->
                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/cl_home_spike"
                    android:layout_width="match_parent"
                    android:layout_height="120dp"
                    android:layout_marginHorizontal="16dp"
                    android:layout_marginTop="10dp"
                    android:background="@drawable/style_linearlayout_round">

                    <TextView
                        android:id="@+id/tv_home_spike"
                        android:layout_width="match_parent"
                        android:layout_height="30dp"
                        android:background="@drawable/style_textview_horizontal_gradient_round_top"
                        android:gravity="start|center_vertical"
                        android:paddingStart="16dp"
                        android:paddingEnd="10dp"
                        android:text="@string/homeSpike"
                        android:textColor="@color/white"
                        android:textSize="16sp"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <androidx.cardview.widget.CardView
                        android:id="@+id/cv_home_spike_img"
                        android:layout_width="80dp"
                        android:layout_height="80dp"
                        android:layout_gravity="center"
                        android:layout_marginStart="20dp"
                        app:cardCornerRadius="8dp"
                        app:cardElevation="0dp"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toStartOf="@id/ll_home_spike"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_home_spike">

                        <ImageView
                            android:layout_width="match_parent"
                            android:layout_height="80dp"
                            android:src="@drawable/test_1" />
                    </androidx.cardview.widget.CardView>

                    <LinearLayout
                        android:id="@+id/ll_home_spike"
                        android:layout_width="0dp"
                        android:layout_height="60dp"
                        android:orientation="vertical"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintStart_toEndOf="@+id/cv_home_spike_img"
                        app:layout_constraintTop_toBottomOf="@id/tv_home_spike">

                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="30dp"
                            android:gravity="start|center_vertical"
                            android:paddingStart="20dp"
                            android:text="00000000"
                            android:textColor="@color/deepTextColor"
                            android:textSize="16sp" />

                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="30dp"
                            android:gravity="start|center_vertical"
                            android:paddingStart="20dp"
                            android:text="111111111111" />
                    </LinearLayout>

                    <TextView
                        android:id="@+id/tv_home_spike_discount_price"
                        android:layout_width="wrap_content"
                        android:layout_height="30dp"
                        android:gravity="center"
                        android:paddingStart="20dp"
                        android:text="¥99.00"
                        android:textColor="@color/crimson"
                        app:layout_constraintStart_toEndOf="@id/cv_home_spike_img"
                        app:layout_constraintTop_toBottomOf="@id/ll_home_spike" />

                    <TextView
                        android:id="@+id/tv_home_spike_price"
                        android:layout_width="wrap_content"
                        android:layout_height="30dp"
                        android:gravity="start|center_vertical"
                        android:paddingStart="20dp"
                        android:text="¥199.00"
                        android:textColor="@color/grey"
                        app:layout_constraintStart_toEndOf="@id/tv_home_spike_discount_price"
                        app:layout_constraintTop_toBottomOf="@id/ll_home_spike" />

                </androidx.constraintlayout.widget.ConstraintLayout>
                <!-- 优惠券 -->
                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/cl_home_coupon"
                    android:layout_width="match_parent"
                    android:layout_height="140dp"
                    android:layout_marginHorizontal="16dp"
                    android:layout_marginTop="10dp"
                    android:background="@drawable/style_linearlayout_round">

                    <TextView
                        android:id="@+id/tv_menu_home_coupon_list"
                        android:layout_width="match_parent"
                        android:layout_height="35dp"
                        android:background="@drawable/style_textview_horizontal_gradient_round_top"
                        android:gravity="start|center_vertical"
                        android:paddingStart="16dp"
                        android:text="@string/menuHomeCouponList"
                        android:textColor="@color/white"
                        android:textSize="16sp"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <TextView
                        android:id="@+id/tv_menu_home_coupon_seller1"
                        android:layout_width="0dp"
                        android:layout_height="30dp"
                        android:gravity="center"
                        android:text="每满1000减100元"
                        android:textColor="@color/crimson"
                        app:layout_constraintBottom_toTopOf="@id/tv_menu_home_description1"
                        app:layout_constraintEnd_toStartOf="@id/tv_menu_home_coupon_seller2"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_coupon_list" />

                    <TextView
                        android:id="@+id/tv_menu_home_description1"
                        android:layout_width="0dp"
                        android:layout_height="30dp"
                        android:gravity="center"
                        android:text="仅可购买部分品类商品"
                        app:layout_constraintEnd_toStartOf="@id/tv_menu_home_description2"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_coupon_seller1" />

                    <Button
                        android:id="@+id/btn_menu_home_coupon1"
                        android:layout_width="100dp"
                        android:layout_height="28dp"
                        android:layout_marginStart="40dp"
                        android:background="@drawable/style_coupon_button_round"
                        android:text="@string/menuHomeCouponReceive"
                        android:textColor="@color/crimson"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toStartOf="@id/tv_menu_home_coupon_dividing_line"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_description1" />

                    <TextView
                        android:id="@+id/tv_menu_home_coupon_dividing_line"
                        android:layout_width="100dp"
                        android:layout_height="100dp"
                        android:layout_marginHorizontal="-40dp"
                        android:background="@drawable/style_dividing_line_vertical"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toStartOf="@id/tv_menu_home_coupon_seller2"
                        app:layout_constraintStart_toEndOf="@id/tv_menu_home_coupon_seller1"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_coupon_list" />

                    <TextView
                        android:id="@+id/tv_menu_home_coupon_seller2"
                        android:layout_width="0dp"
                        android:layout_height="30dp"
                        android:gravity="center"
                        android:text="每满1000减100元"
                        android:textColor="@color/crimson"
                        app:layout_constraintBottom_toTopOf="@id/tv_menu_home_description2"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintStart_toEndOf="@id/tv_menu_home_coupon_seller1"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_coupon_list" />

                    <TextView
                        android:id="@+id/tv_menu_home_description2"
                        android:layout_width="0dp"
                        android:layout_height="30dp"
                        android:gravity="center"
                        android:text="仅可购买部分品类商品"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintStart_toEndOf="@id/tv_menu_home_description1"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_coupon_seller2" />

                    <Button
                        android:id="@+id/btn_menu_home_coupon2"
                        android:layout_width="100dp"
                        android:layout_height="28dp"
                        android:layout_marginEnd="40dp"
                        android:background="@drawable/style_coupon_button_round"
                        android:text="@string/menuHomeCouponReceive"
                        android:textColor="@color/crimson"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toEndOf="@id/tv_menu_home_coupon_dividing_line"
                        app:layout_constraintTop_toBottomOf="@id/tv_menu_home_description2" />

                </androidx.constraintlayout.widget.ConstraintLayout>
                <!-- 瀑布流 -->
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv_water_falls_flow"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginHorizontal="16dp"
                    android:layout_marginTop="10dp" />
            </LinearLayout>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
复制代码

Fragment:同样请忽略无用逻辑

package com.qingnuo.yami.view.home;

import android.content.Context;
import android.content.Intent;
import android.database.Observable;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableField;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.youth.banner.adapter.BannerImageAdapter;
import com.youth.banner.holder.BannerImageHolder;
import com.youth.banner.indicator.CircleIndicator;

import java.util.ArrayList;
import java.util.List;

/**
 * 首页横向菜单首页
 */
public class HomeMenuFragment extends Fragment implements View.OnClickListener {
    private static final String TAG = "HomeMenuFragment";
    private FragmentMenuHomeBinding menuHomeBinding;
    private Context mContext;


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        menuHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_menu_home, container, false);
        mContext = getContext();
        initView();
        return menuHomeBinding.getRoot();
    }

    private void initView() {

        //设置Adapter
        HomeWaterFallsFlowAdapter waterFallsFlowAdapter = new HomeWaterFallsFlowAdapter(mContext);
        waterFallsFlowAdapter.setList(waterFallsFlowBeanArrayList);
        menuHomeBinding.rvWaterFallsFlow.setAdapter(waterFallsFlowAdapter);
        // 计算需要高度
        ViewGroup.LayoutParams layoutParams = menuHomeBinding.rvWaterFallsFlow.getLayoutParams();
        int height = 0;
        for (int i = 0; i < waterFallsFlowBeanArrayList.size(); i++) {
            if (i % 2 == 0) {
                height += 400;
            } else if (i % 3 == 0) {
                height += 360;
            } else {
                height += 440;
            }
        }
        layoutParams.height = height - waterFallsFlowBeanArrayList.size() * 100;
        menuHomeBinding.rvWaterFallsFlow.setLayoutParams(layoutParams);
        menuHomeBinding.rvWaterFallsFlow.setHasFixedSize(true);
        menuHomeBinding.rvWaterFallsFlow.setNestedScrollingEnabled(false);
        menuHomeBinding.rvWaterFallsFlow.setFocusable(false);

    }

}
复制代码

参考
NestedScrollView 嵌套 RecyclerView 无法正常显示
NestedScrollView 的使用
解决嵌套显示不全
嵌套不显示问题

分类:
Android
标签:
分类:
Android
标签: