Vince
Vince

Reputation: 1664

Android View Binding: Custom View shows duplicate SwipeRefreshLayout progress indicators

In my fragment, I am displaying a list of items using a Custom View that contains a SwipeRefreshLayout.

When I swipe to refresh, I can see two refreshing indicators and one of them never disappears.

See it here

I obviously have only one SwipeRefreshLayout in my hierarchy and this appeared when I migrated my code to View Binding.


Here are the details of my code and of the behaviour.

I have a fragment that displays a list of items, I'm using a Custom View com.myapp.ItemsListView I built for this purpose.

<?xml version="1.0" encoding="utf-8"?>
<com.myapp.ItemsListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myItems"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

In order to access this custom view, I am using View Binding. In my fragment, that's what it looks like:

// ItemsFragment.kt
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
  ): View? {
    binding = FragmentItemsBinding.inflate(inflater, container, false)
    return binding?.root
}

and I then access anything in this custom view via binding?.myItems.

And my custom view uses a SwipeRefreshLayout as its root and contains a RecyclerView:

<?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"
    android:id="@+id/swipeToRefresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/items"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical" />

        <TextView
            android:id="@+id/missingContent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:text="@string/missing_content_message"
            app:drawableTopCompat="@drawable/ic_missing_content_24dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

Following this question I'm using this piece of code to inflate the custom view:

// ItemsListView.kt
class ItemsListView(context: Context, attrs: AttributeSet) : SwipeRefreshLayout(context, attrs) {
  private var b: ItemsListBinding? = null

  init {
    b = ItemsListBinding.inflate(LayoutInflater.from(context), this, true)
  }
}

From the code, I customized my SwipeRefreshLayout to look different than the default:

b?.swipeToRefresh?.setSize(LARGE)
b?.swipeToRefresh?.setColorSchemeResources(
  R.color.colorPrimary,
  R.color.colorPrimaryDark
)

And I access b?.swipeToRefresh to set a listener, display or hide the progress indicator.

fun setListener(listener: OnRefreshListener) {
  b?.swipeToRefresh?.setOnRefreshListener(listener)
}
fun showProgress() {
  b?.swipeToRefresh?.isRefreshing = true
}
fun hideProgress() {
  b?.swipeToRefresh?.isRefreshing = false
}

However, as you can see on the video clip, there is a black progress indicator that sticks and never goes away. I have tried to access the SwipeRefreshLayout via b?.root and it results in the same behaviour.

In the end, I just do not understand why there are two SwipeRefreshLayout displayed on my screen. I noticed this problem when I introduced View Binding (I previously used Kotlin Synthetics). I'd like to inflate only one SwipeRefreshLayout in the hierarchy.

Upvotes: 0

Views: 260

Answers (0)

Related Questions