如何以编程方式(在运行时)刷一行RecyclerView?

时间:2015-12-21 17:23:25

标签: android android-layout android-activity android-animation android-recyclerview

我有一个带有像这样的项目的RecyclerView:

enter image description here

我使用ItemTouchHelper.SimpleCallback来监听swipe,并使用onChildDraw()在刷子项时绘制画布:

enter image description here

再刷一下:

enter image description here

我的问题:

我想在项目列表中的第一个项目上模拟滑动(在运行时);我需要在X轴上(或多或少)-100像素的第一个项目,然后回到原始位置。怎么做到这一点?

3 个答案:

答案 0 :(得分:2)

我创建了一些实用程序方法,以防有人需要

import android.animation.ValueAnimator
import android.os.SystemClock
import android.view.MotionEvent
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView

/**
 * @author Oleh Haidaienko
 * @since 29.07.2020
 */
object SwipeUtils {
    /**
     * Programmatically swipe RecyclerView item
     * @param recyclerView RecyclerView which item will be swiped
     * @param index Position of item
     * @param distance Swipe distance
     * @param direction Swipe direction, can be [ItemTouchHelper.START] or [ItemTouchHelper.END]
     * @param time Animation time in milliseconds
     */
    fun swipeRecyclerViewItem(
        recyclerView: RecyclerView,
        index: Int,
        distance: Int,
        direction: Int,
        time: Long
    ) {
        val childView = recyclerView.getChildAt(index) ?: return
        val x = childView.width / 2F
        val viewLocation = IntArray(2)
        childView.getLocationInWindow(viewLocation)
        val y = (viewLocation[1] + childView.height) / 2F
        val downTime = SystemClock.uptimeMillis()
        recyclerView.dispatchTouchEvent(
            MotionEvent.obtain(
                downTime,
                downTime,
                MotionEvent.ACTION_DOWN,
                x,
                y,
                0
            )
        )
        ValueAnimator.ofInt(0, distance).apply {
            duration = time
            addUpdateListener {
                val dX = it.animatedValue as Int
                val mX = when (direction) {
                    ItemTouchHelper.END -> x + dX
                    ItemTouchHelper.START -> x - dX
                    else -> 0F
                }
                recyclerView.dispatchTouchEvent(
                    MotionEvent.obtain(
                        downTime,
                        SystemClock.uptimeMillis(),
                        MotionEvent.ACTION_MOVE,
                        mX,
                        y,
                        0
                    )
                )
            }
        }.start()
    }
}

答案 1 :(得分:0)

我想您可以通过RecyclerViewDataObserver注册Adapter来实现这一目标, adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { super.onChanged(); adapter.unregisterAdapterDataObserver(this);//unregister the adapter since no longer needed. } }); 会在项目被删除,插入或更改时通知您。让我们考虑一下这个场景

recyclerView.getChildAt(0).translateX(-100);
上面代码中的

会在插入项目后通知您,然后您可以使用recyclerView.getChildAt(0).translateX(0);来模拟滑动,只需reposition X view onChanged() { {1}}返回方法{{1}}。

答案 2 :(得分:0)

此扩展功能可以为您提供帮助:

fun ViewGroup.performSwipeToLeft(target: View, distance: Float) {
    this.performSwipe(target, distanceX = -distance, distanceY = 0f)
}
fun ViewGroup.performSwipeToRight(target: View, distance: Float) {
    this.performSwipe(target, distanceX = +distance, distanceY = 0f)
}

fun ViewGroup.performSwipe(target: View, distanceX: Float, distanceY: Float) {
    val parentCoords = intArrayOf(0, 0)
    this.getLocationInWindow(parentCoords)

    val childCoords = intArrayOf(0, 0)
    target.getLocationInWindow(childCoords)

    val initGlobalX = childCoords[0].toFloat() + 1f
    val initGlobalY = childCoords[1].toFloat() + 1f

    val initLocalX = (childCoords[0] - parentCoords[0]).toFloat() + 1f
    val initLocalY = (childCoords[1] - parentCoords[1]).toFloat() + 1f

    val downTime = SystemClock.uptimeMillis()
    var eventTime = SystemClock.uptimeMillis()

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            eventTime,
            MotionEvent.ACTION_DOWN,
            initGlobalX,
            initGlobalY,
            0
        ).apply {
            setLocation(initLocalX, initLocalY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )

    val steps = 20
    var i = 0
    while (i in 0..steps) {
        val globalX = initGlobalX + i * distanceX / steps
        val globalY = initGlobalY + i * distanceY / steps
        val localX = initLocalX + i * distanceX / steps
        val localY = initLocalY + i * distanceY / steps
        if (globalX <= 10f || globalY <= 10f) {
            break
        }
        this.dispatchTouchEvent(
            MotionEvent.obtain(
                downTime,
                ++eventTime,
                MotionEvent.ACTION_MOVE,
                globalX,
                globalY,
                0
            ).apply {
                setLocation(localX, localY)
                source = InputDevice.SOURCE_TOUCHSCREEN
            }
        )
        i++
    }

    this.dispatchTouchEvent(
        MotionEvent.obtain(
            downTime,
            ++eventTime,
            MotionEvent.ACTION_UP,
            initGlobalX + i * distanceX,
            initGlobalY + i * distanceY,
            0
        ).apply {
            setLocation(initLocalX + i * distanceX, initLocalY + i * distanceY)
            source = InputDevice.SOURCE_TOUCHSCREEN
        }
    )
}

在您的情况下,您可以按以下方式使用它:

recylerView.performSwipeToLeft(recyclerView.getChildAt(0), 100f)