Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ItemTouchHelper onChildDraw() in API 28

Tags:

android

I have a strange problem on Android API 28 with the ItemTouchHelper where it doesn't draw one of the icons on swiping. Did they change something in the new version that I'm not aware of?

enter image description here Edit icon is shown in API 27 but not on API 28.

enter image description here Delete icon is shown on both API versions.

The calculated position of the icons is the same on both versions.

Log for delete icon

API 27: D/Position: Left: 938 Top: 100 Right: 1001 Bottom: 163
API 28: D/Position: Left: 938 Top: 100 Right: 1001 Bottom: 163

Log for edit icon

API 27: D/Position: Left: 142 Top: 100 Right: 79 Bottom: 163
API 28: D/Position: Left: 142 Top: 100 Right: 79 Bottom: 163

ItemTouchHelper

abstract class ImageGroupTouchCallback(context: Context) : ItemTouchHelper.Callback() {

[...] -> unimportant code removed

override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
                         dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {

        [...] -> unimportant stuff

        // Calculate position of the icon
        val iconMargin = (itemHeight - intrinsicHeight) / 2
        val iconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
        val iconBottom = iconTop + intrinsicHeight
        val (iconLeft, iconRight) = getIconPositionHorizontal(itemView, iconMargin, dX)

        Log.d("Position", "Left: $iconLeft Top: $iconTop Right: $iconRight Bottom: $iconBottom")

        // swiping from left to right
        if (dX > 0) {
            background.setBounds(itemView.left, itemView.top, itemView.left + dX.toInt(), itemView.bottom)
            background.color = Color.parseColor("#3cca59")
            background.draw(c)

            // Draw the delete icon
            editIcon!!.setBounds(iconLeft, iconTop, iconRight, iconBottom)
            editIcon.draw(c)
        }
        // swiping from right to left
        else if (dX < 0) {
            background.setBounds(itemView.right + dX.toInt(), itemView.top, itemView.right, itemView.bottom)
            background.color = Color.parseColor("#f44336")
            background.draw(c)

            // Draw the delete icon
            deleteIcon!!.setBounds(iconLeft, iconTop, iconRight, iconBottom)
            deleteIcon.draw(c)
        }
    }

    private fun getIconPositionHorizontal(itemView: View, iconMargin: Int, dX: Float): Pair<Int, Int> {
        val iconLeft: Int
        val iconRight: Int

        // swiping from left to right
        if (dX > 0) {
            iconLeft = itemView.left + iconMargin + intrinsicWidth
            iconRight = itemView.left + iconMargin
        } else {
            iconLeft = itemView.right - iconMargin - intrinsicWidth
            iconRight = itemView.right - iconMargin
        }

        return Pair(iconLeft, iconRight)
    }
}
like image 969
Bona Fide Avatar asked Sep 26 '18 19:09

Bona Fide


1 Answers

The left and right bounds on your edit icon are reversed.

// swiping from left to right
if (dX > 0) {
    iconLeft = itemView.left + iconMargin + intrinsicWidth
    iconRight = itemView.left + iconMargin
}

This will return a pair of coordinates where the value for the icon's left side is greater than the value for its right side. Your delete icon, on the other hand, has its coordinates set correctly.

Replace the above code with this:

// swiping from left to right
if (dX > 0) {
    iconLeft = itemView.left + iconMargin
    iconRight = itemView.left + iconMargin + intrinsicWidth
}

To reproduce this problem I created an incredibly simple view class:

public class MyView extends View {

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_bookmark_black_24dp);
        icon.setBounds(getRight(), getTop(), getLeft(), getBottom());
        icon.draw(canvas);
    }
}

And then I just stuck one of these into a layout as the only view in my activity:

<?xml version="1.0" encoding="utf-8"?>
<com.example.stackoverflow.MyView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

When I run the app, I don't see anything.

If I switch this line:

icon.setBounds(getRight(), getTop(), getLeft(), getBottom());

to be this instead:

icon.setBounds(getLeft(), getTop(), getRight(), getBottom());

then everything works as expected, and I see my icon filling the screen.

like image 57
Ben P. Avatar answered Oct 19 '22 08:10

Ben P.