Bohsen
Bohsen

Reputation: 4350

Android: Outline of viewitems in recyclerview overlaps recyclerview border

In my current project I have a RecyclerView with a rounded rectangle as its border. I set it using the background view tag in my layout xml and it produces the correct effect:

<androidx.recyclerview.widget.RecyclerView
    ...
    android:background="@drawable/layout_sample_view_background"
    ....
    />

Image of recyclerview with border

The problem arises when I longclick() one of the view items and open a floating action mode menu using ActionMode.Callback2. This selection overlaps the borders of my RecyclerView:

Image of recyclerview with selected view overlapping border

Btw. Not sure this is important, but the viewitems inside my RecyclerView/ListAdapter are using a custom view:

/**
 * Custom view for each [RecyclerView] list item in the list inside a [SampleView]
 */
class SampleListItem(context: Context, attrs: AttributeSet, @AttrRes defStyleAttr: Int) : ConstraintLayout(context, attrs, defStyleAttr), View.OnLongClickListener {
    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)

    init {
        setOnLongClickListener(this)
        clipToOutline = false
    }

    private val binding: LayoutSampleListItemBinding = LayoutSampleListItemBinding.inflate(LayoutInflater.from(context), this)

    var sample: Sample? = null
        set(value) {
            field = value
            fun Long.toTimeString(): String {
                val date = ZonedDateTime.ofInstant(Instant.ofEpochMilli(this), ZoneId.systemDefault())
                val formatter =  DateTimeFormatter.ofPattern("HH:mm")
                val time = date.format(formatter)
                Timber.d("With $this time was: $time")
                return time
            }
            checkNotNull(value)
            binding.id.text = value.sampleNumber.toString()
            binding.timestamp.text = value.sampleTime.toTimeString()
            binding.comment.text = SpannableStringBuilder(value.comment)

        }
    private var sampleItemClickListener = object : SampleItemClickListener {
        override fun onSampleEditClick(sample: Sample) {
            Timber.d("ActionMode edit icon clicked. Please edit $sample")
            isSelected = !isSelected
        }

        override fun onSampleDeleteClick(sample: Sample) {
            Timber.d("ActionMode delete icon clicked. Please delete $sample")
            isSelected = !isSelected
        }

    }

    interface SampleItemClickListener {
        fun onSampleEditClick(sample: Sample)
        fun onSampleDeleteClick(sample: Sample)
    }

    override fun onLongClick(v: View?): Boolean {
        Toast.makeText(context,"longClick $sample", Toast.LENGTH_LONG).show()
        // Start floating ActionMode
        isSelected = true
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val floatingActionModeCallback = SampleViewItemActionModeCallback(this, sampleItemClickListener, R.menu.sampleviewitem_menu_actions)
        }
        return true
    }
}

I set the ripple effect of this custom view using the following drawable:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorPrimaryLight">
    <item
        android:id="@android:id/mask"
        android:drawable="@color/icon_inactive_light_background" />

    <item>
    <selector>
        <item android:state_selected="true">
            <color android:color="@color/colorPrimaryLight"/>
        </item>
        <item android:state_activated="true">
            <color android:color="@color/colorPrimaryLight"/>
        </item>
        <item>
            <color android:color="@android:color/transparent"/>
        </item>
    </selector>
    </item>
</ripple>

The layout of the custom view:

<?xml version="1.0" encoding="utf-8"?>
<merge
    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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/id"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        app:layout_constraintEnd_toStartOf="@+id/timestamp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/comment"
        app:layout_constraintWidth_percent="0.10"
        tools:text="@sample/samples.json/data/sampleId" />

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/timestamp"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textAlignment="center"
        app:layout_constraintEnd_toStartOf="@+id/comment"
        app:layout_constraintStart_toEndOf="@+id/id"
        app:layout_constraintTop_toTopOf="@+id/comment"
        app:layout_constraintWidth_percent="0.20"
        tools:text="@sample/samples.json/data/timestamp" />

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/comment"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/sampleviewitem_optional_icon"
        app:layout_constraintStart_toEndOf="@id/timestamp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="0.60"
        tools:hint="Kommentar"
        tools:text="@sample/samples.json/data/comment" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/sampleviewitem_optional_icon"
        style="@style/IconOnlyButton"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:icon="@drawable/ic_edit_white_24dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@+id/layout_sample_item_sample_comment"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintWidth_percent="0.10" />

</merge>

Does anyone know what causes this effect and how to avoid this behavior? I know of ViewOutlineProvider, but I'm just not familiar with it. Could it maybe solve this issue?

Upvotes: 2

Views: 1878

Answers (2)

Bohsen
Bohsen

Reputation: 4350

For others that might come across this problem. The solution to this was to wrap the RecyclerView in a MaterialCardView (a regular CardView could also work).

Like this:

<com.google.android.material.card.MaterialCardView
    android:id="@+id/sample_container"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    app:cardElevation="0dp"
    app:cardCornerRadius="4dp"
    app:strokeColor="@color/icon_active_unfocused_light_background"
    app:strokeWidth="1dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@id/layout_sample_view_icon"
    app:layout_constraintTop_toTopOf="@id/layout_sample_view_icon"
    >
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/layout_sample_view_recyclerview"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        tools:itemCount="4"
        tools:listitem="@layout/layout_patientsample_listitem"
        />

</com.google.android.material.card.MaterialCardView>

Here's a screenshot of the outcome:

Recyclerview without border overlap

Upvotes: 5

Md. Asaduzzaman
Md. Asaduzzaman

Reputation: 15433

Use padding in your RecyclerView

<androidx.recyclerview.widget.RecyclerView
    ...
    android:background="@drawable/layout_sample_view_background"
    android:padding="5dp"
    ....
/>

Upvotes: 0

Related Questions