最近项目中嵌套的控件比较多,遇到了不少问题,昨天解决了,赶紧记录下
场景是 ViewPager2 嵌套 NestedScrollView 嵌套 RecyclerView 瀑布流
效果图:
没办法,压缩太严重,凑合看
主要问题如下:
- NestedScrollView / ScrollView 嵌套 RecyclerView 冲突,不滚动、显示不完整、或者不显示问题
- NestedScrollView / ScrollView 嵌套 RecyclerView 瀑布流双重滑动问题
- 打开页面后定位到 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 中设置,切换其他页面后回来,焦点总是在顶部(设置焦点的位置);
如果在代码中设置,切换页面后回来,位置会停留在之前浏览的位置。
下面是具体的解决方案。
-
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"/>
-
代码中处理
第二中是在代码中处理。我采用的这种方式,也很简单。
既然是 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 的使用
解决嵌套显示不全
嵌套不显示问题
今天的文章NestedScrollView、ScrollView嵌套Recyclerview的冲突、显示不完整及焦点问题解决方案分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/20758.html