代码之家  ›  专栏  ›  技术社区  ›  hushed_voice

nestedscrollview内的RecyclerView的onBindViewHolder正在一次为所有项调用

  •  4
  • hushed_voice  · 技术社区  · 6 年前

    我有一个折叠工具栏和一个底部导航栏,如图所示:

    <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:fitsSystemWindows="true"
            app:layout_constraintBottom_toTopOf="@id/nav_view"
            app:layout_constraintTop_toTopOf="parent">
    
            <!-- Scrollable view here -->
    
            <com.google.android.material.appbar.AppBarLayout
                android:id="@+id/appBar"
                android:layout_width="match_parent"
                android:layout_height="@dimen/height335"
                android:background="@drawable/ic_appbar_bg"
                android:fitsSystemWindows="true"
                app:elevation="0dp">
    
                <com.google.android.material.appbar.CollapsingToolbarLayout
                    android:id="@+id/collapsingToolbar"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    app:contentScrim="@color/colorPrimaryDark"
                    app:toolbarId="@+id/toolbar"
                    app:layout_scrollFlags="scroll|exitUntilCollapsed">
    
                    <androidx.appcompat.widget.Toolbar
                        android:id="@+id/toolbar"
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:background="@android:color/transparent"
                        android:contentInsetStart="0dp"
                        android:contentInsetLeft="0dp"
                        android:gravity="center"
                        app:contentInsetEnd="0dp"
                        app:contentInsetEndWithActions="0dp"
                        app:contentInsetLeft="0dp"
                        app:contentInsetRight="0dp"
                        app:contentInsetStart="0dp"
                        app:contentInsetStartWithNavigation="2dp"
                        app:layout_collapseMode="pin"
                        app:theme="@style/ToolbarTheme">
    
                        <include
                            android:id="@+id/toolbar_header_view"
                            layout="@layout/widget_header_view_top"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            bind:cardDetails="@{viewModel}" />
                    </androidx.appcompat.widget.Toolbar>
    
                    <include
                        layout="@layout/widget_header"
                        bind:cardDetails="@{viewModel}" />
    
                </com.google.android.material.appbar.CollapsingToolbarLayout>
            </com.google.android.material.appbar.AppBarLayout>
    
            <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                android:id="@+id/swipe"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
                <!-- just a nestedscrollview
                override fun onTouchEvent(ev: MotionEvent): Boolean {
                    return scrollable && super.onTouchEvent(ev)
                }
    
                override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
                    return scrollable && super.onInterceptTouchEvent(ev)
                }
    
                fun setScrollingEnabled(enabled: Boolean) {
                    scrollable = enabled
                } -->
                <com.android.utils.LockableNestedScrollView
                    android:id="@+id/nestedScrollView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    app:layout_behavior="@string/appbar_scrolling_view_behavior"
                    android:clipChildren="false"
                    android:clipToPadding="false"
                    android:fillViewport="true">
    
                   <LinearLayout>
                        <Some views...
                        <androidx.fragment.app.FragmentContainerView
                            android:id="@+id/nav_host_fragment"
                            android:layout_width="match_parent"
                            app:layout_behavior="@string/appbar_scrolling_view_behavior"
                            android:layout_height="match_parent" />
    
                    </LinearLayout>
    
                </com.android.utils.LockableNestedScrollView>
    
            </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
    
        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->viewModel.fabClicked()}"
            android:src="@drawable/ic_plus"
            app:fabCustomSize="@dimen/fab70"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="1" />
    
        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/nav_view"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="0dp"
            android:layout_marginEnd="0dp"
            android:background="?android:attr/windowBackground"
            android:elevation="@dimen/elevation3"
            android:paddingTop="@dimen/padding10"
            app:itemTextAppearanceActive="@style/BottomNavigationViewTextStyle"
            app:itemTextAppearanceInactive="@style/BottomNavigationViewTextStyle"
            app:labelVisibilityMode="labeled"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:menu="@menu/nav_view" />
    

    单击导航栏项时,碎片容器将替换为碎片。问题是在其中一个片段中我有一个recyclerview。recyclerview中所有项的onBindView一次被全部调用。我需要避免这种情况,主要是因为我试图实现如下分页:

    override fun onBindViewHolder(holder: TopUpViewHolder, position: Int) {
        val item = myDataset[position]
        holder.bind(item)
        if (position == this.itemCount - 1){
            // do your load more task here
            viewModel.fetchTopUpData()
        }
    }
    

    (我尝试附加scroll listener并实现分页,如 this

    以下是我与recyclerview的片段:

    <?xml version="1.0" encoding="utf-8"?>
    

    <data>
    
        <import type="android.view.View" />
    
        <variable
            name="viewmodel"
            type="com.android.ui.topup.viewmodel.TopUpViewModel" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:padding="@dimen/padding15">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipChildren="false"
            android:clipToPadding="false"
            android:orientation="vertical">
    
            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/status_header"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingBottom="@dimen/padding20"
                android:visibility="@{viewmodel.headerVisibility}">
    
                <TextView
                    android:id="@+id/recentLabel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/margin20"
                    android:text="@string/recent_top_ups"
                    android:textAllCaps="true"
                    android:textColor="@color/topup_label_text_color"
                    android:textSize="@dimen/text12"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
                <TextView
                    android:id="@+id/viewAll"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/margin20"
                    android:onClick="@{()->viewmodel.viewAllClicked()}"
                    android:text="@string/view_all"
                    android:textColor="@color/topup_label_color_orenge"
                    android:textSize="@dimen/text14"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
            </androidx.constraintlayout.widget.ConstraintLayout>
    
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/topUpRCView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:nestedScrollingEnabled="false"
                android:clipChildren="false"
                android:clipToPadding="false"
                app:scrollListener="@{viewmodel.scrollListener}" />
    
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="@{viewmodel.fetchingFlag?View.VISIBLE:View.GONE}" />
        </LinearLayout>
        <LinearLayout
            android:id="@+id/empty_list"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="@{viewmodel.listEmpty}"
            android:orientation="vertical">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:src="@drawable/ic_illustration_receipt"/>
            <TextView
                android:id="@+id/empty_list_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/you_have_no_topup_requests"
                android:fontFamily="@font/colfaxregular"
                android:textColor="#333547"
                android:layout_marginTop="36dp"
                android:textSize="@dimen/text16"
                android:alpha=".3"/>
    
        </LinearLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    我尝试过的事情:

    1. 补充 android:nestedScrollingEnabled="false" 在recyclerview中
    2. app:layout_behavior="@string/appbar_scrolling_view_behavior"
    3. 将recyclerview的高度更改为 match_parent wrap_content
    4. https://stackoverflow.com/a/44470106/6341943 =>出于某种原因添加标题视图持有者
    5. https://stackoverflow.com/a/37558761/6341943 =>无法执行此操作,因为我有一个底部导航栏

    现在是奇怪的部分 如果我将片段保存在viewpager中,出于某种原因,问题就不会发生。(即使是这个黑客程序也不可用,因为它弄乱了我的collpsingToolbarLayout)

    0 回复  |  直到 6 年前
        1
  •  1
  •   hushed_voice    6 年前

    我已经浪费了至少一个星期的时间在这件事上,唯一有效的解决办法就是移除 nestedscrollview ,你 必须移除 这个 . 如果你碰巧有多个 view recyclerview ,则必须将它们添加为 回收视图 通过设置不同的viewholder,然后添加

    app:layout_behavior="@string/appbar_scrolling_view_behavior"

    回收视图

    就我而言,要求如下:

      <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:fitsSystemWindows="true"
            app:layout_constraintTop_toTopOf="parent">
    
            <!-- Scrollable view here -->
    
            <com.google.android.material.appbar.AppBarLayout
                ....   >
    
                <com.google.android.material.appbar.CollapsingToolbarLayout
                    ....>
    
                    <androidx.appcompat.widget.Toolbar
                        ....>
    
                        <include
                            android:id="@+id/toolbar_header_view"
                            .... />
                    </androidx.appcompat.widget.Toolbar>
    
                    <include layout="@layout/widget_header" />
                </com.google.android.material.appbar.CollapsingToolbarLayout>
            </com.google.android.material.appbar.AppBarLayout>
    
            <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
                ....>
                <LinearLayout orientation="vertical" ....>
                    <View .../>  <!-- I needed to have these two views along with recyclerview and i wanted them to do nestedscroll along with recyclerview -->
                    <View .../>
                    <androidx.recyclerview.widget.RecyclerView
                    .... />
            </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    我以前需要有两种观点 回收视图 我想让他们一起做nestedscroll . 唯一有效的方法是将它们删除到视图中,并将它们添加为视图的前两项 回收视图 ,然后添加

    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    

    swipetorefresh

    希望这对别人有帮助。如果需要,我会添加更多信息。