Solution to the conflict, incomplete display and focus problem of NestedScrollView and ScrollView nested Recyclerview

Solution to the conflict, incomplete display and focus problem of NestedScrollView and ScrollView nested Recyclerview

Recently, there are many nested controls in the project, and many problems have been encountered. Yesterday, I solved it. Hurry up and record it.

The scene is ViewPager2 nested NestedScrollView nested RecyclerView waterfall flow

Effect picture:

No way, the compression is too serious, just do it

The main issues are as follows:

  1. NestedScrollView/ScrollView nested RecyclerView conflict, no scrolling, incomplete display, or no display problem
  2. NestedScrollView/ScrollView nested RecyclerView waterfall flow double sliding problem
  3. After opening the page, locate the RecyclerView problem

Mainly on these three problems, the following are solved in order, I tried NestedScrollView and ScrollView, and the effect is no difference.

Problem 1: NestedScrollView/ScrollView nested RecyclerView conflicts, no scrolling, incomplete display, or no display problems

Regarding this problem, it is the main problem. CSDN says that a lot of it is to modify layout_height match_parent to wrap_content. In fact, this has no effect, because the essence of the problem is that we need to give RecyclerView a fixed height to solve.

If you set it to match_parent, there will be a non-display effect, we only need to set a fixed height for RecyclerView. Or dynamically calculate the height of the control, and then set it to solve the problem.

We can set a fixed height for the layout_height of RecyclerView in XML , 1000dp or the like, and this can be solved. But we cannot control the height of the waterfall. However, in actual development, we cannot determine how high the data needs to be loaded, so the hardcoded height may not be good. So the layout code will not be posted

Another way of thinking is to dynamically calculate the required height , and then set it to him.

Here I deal with it according to the length of the waterfall data. The height can be calculated according to the specific business.

//Calculate the required height 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; } } //Just assign the height after business processing to layoutParams.height. layoutParams.height = height-waterFallsFlowBeanArrayList.size() * 100; menuHomeBinding.rvWaterFallsFlow.setLayoutParams(layoutParams); Copy code

That's it.
I also thought about calculating the height in the Adapter and getting the post-processing, but after trying it, the result is always 0. If you have ideas, you can let me know.

Problem 2: NestedScrollView/ScrollView nested RecyclerView waterfall flow double sliding problem

After normal display, NestedScrollView/ScrollView will slide, and the RecyclerView inside can also slide.

Here we need to deal with it, not to let the RecyclerView inside slide, but slide along with the NestedScrollView/ScrollView.
Here, there is an attribute in the official API that can help us solve this problem. This is setNestedScrollingEnabled, which is the switch to start nested scrolling. The default is true.

Of course, it can also be set in the layout file. If it is set in the layout file, it must be set on the RecyclerView. I set it in the code here.

menuHomeBinding.rvWaterFallsFlow.setNestedScrollingEnabled(false); Copy code

Problem 3: RecyclerView is located after opening the page

Based on the above, the effect can be displayed normally, but after opening the App, it will automatically locate the RecyclerView position.

This is because RecyclerView automatically obtains focus by default, so we need to deal with it. There are two ways

The XML method and the method set in the code, let me talk about the difference first:
set in XML, and return after switching other pages, the focus is always at the top (position of the focus);
if set in the code, after switching the page, the position will be Stay at the previously browsed location.

The following is a specific solution.

  1. XML way

    Add a focus attribute on the first child control of NestedScrollView/ScrollView

android:focusable="true" android:focusableInTouchMode="true" Copy code

It needs to be explained here that both NestedScrollView and ScrollView allow only one child control. The first child control mentioned here is the first child control in the only child control.

<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"> <!-- The first child control --> <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"/> Copy code
  1. Processing in code

    The second is to deal with in the code. The method I used is also very simple.

    Since RecyclerView automatically obtains the focus by default, we only need to set it in the code to prevent him from obtaining the focus by default.

menuHomeBinding.rvWaterFallsFlow.setFocusable(false); Copy code

summary

Basically the attributes used are

menuHomeBinding.rvWaterFallsFlow.setHasFixedSize(true); menuHomeBinding.rvWaterFallsFlow.setNestedScrollingEnabled(false); menuHomeBinding.rvWaterFallsFlow.setFocusable(false); Copy code

Key points: determine the height of RecyclerView

Complete code :
XML: please ignore the useless code, just look at the outermost NestedScrollView and the lowermost RecyclerView to be 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"/> <!-- Function menu--> <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"> <!-- Spike--> <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> <!-- Coupon--> <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="100 yuan for every 1,000 full" 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="Only some products can be purchased" 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="100 yuan for every 1,000 full" 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="Only some products can be purchased" 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> <!-- Waterfall stream--> <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> Copy code

Fragment: Please also ignore the useless logic

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; /** * Homepage Horizontal Menu Homepage */ 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() { //Set Adapter HomeWaterFallsFlowAdapter waterFallsFlowAdapter = new HomeWaterFallsFlowAdapter(mContext); waterFallsFlowAdapter.setList(waterFallsFlowBeanArrayList); menuHomeBinding.rvWaterFallsFlow.setAdapter(waterFallsFlowAdapter); //Calculate the required height 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); } } Copy code

Refer to
NestedScrollView nested RecyclerView can not display
the use of NestedScrollView to
solve the nested display incomplete
nesting does not display problem