【问题标题】:MotionLayout not recyclable as a child of RecyclerViewMotionLayout 作为 RecyclerView 的子项不可回收
【发布时间】:2021-12-27 05:32:48
【问题描述】:

我尝试通过扩展 MotionLayout 以编程方式实现它。我有一个使用 RecyclerView 的基本活动。 但是,当我将我的动作布局添加为 RecyclerView 的一个项目时,当我尝试上下滚动时,视图不会被回收。 当我用作普通视图(作为单一视图)时,它工作得很好。

这是预览:

class SimpleMotionLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr) {

    private val motionScene = MotionScene(this)
    private var _simpleTransition: MotionScene.Transition? = null

    private lateinit var squareView: View

    init {
        layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
        initDefaultConstraint(this)
        setMotion()
    }

    fun setMotion() {
        _simpleTransition = createPlaceholderTransition(motionScene)
        setDebugMode(DEBUG_SHOW_PATH)

        /**
         * The order matters here.
         * [MotionScene.addTransition] adds the transition to the scene while
         * [MotionScene.setTransition] sets the transition to be the current transition.
         */
        motionScene.addTransition(_simpleTransition)
        motionScene.setTransition(_simpleTransition)
        
        scene = motionScene
        setTransition(_simpleTransition!!.id)

        animateView()
    }

    fun setSquareColor(color: Int) {
        squareView.setBackgroundColor(color)
    }

    fun initDefaultConstraint(motionLayout: ConstraintLayout) {
        // View
        squareView = View(context).apply {
            id = R.id.default_button
            setBackgroundColor(Color.BLACK)
        }
        motionLayout.addView(
            squareView,
            LayoutParams(
                fromDp(context, 52),
                fromDp(context, 52)
            )
        )

        val set = ConstraintSet()
        set.clone(motionLayout)

        // Setup constraint set to TOP, LEFT to the Parent
        set.connect(
            squareView.id,
            TOP,
            PARENT_ID,
            TOP
        )
        set.connect(
            squareView.id,
            START,
            PARENT_ID,
            START
        )

        set.applyTo(motionLayout)
    }

    private fun setToEnd() {
        val endSet = getConstraintSet(_simpleTransition?.endConstraintSetId ?: return)
        endSet.clear(R.id.default_button, START)
        endSet.connect(
            R.id.default_button,
            END,
            PARENT_ID,
            END
        )
    }

    fun animateView() {
        setToEnd()
        _simpleTransition?.setOnSwipe(
            OnSwipe().apply {
                dragDirection = DRAG_END
                touchAnchorId = R.id.default_button
                touchAnchorSide = SIDE_START
                onTouchUp = ON_UP_AUTOCOMPLETE_TO_START
                setMaxAcceleration(500)
            }
        )
        setTransition(_simpleTransition!!.id)
    }

    // Placeholder transition??
    fun createPlaceholderTransition(motionScene: MotionScene): MotionScene.Transition? {
        val startSetId = View.generateViewId()
        val startSet = ConstraintSet()
        startSet.clone(this)

        val endSetId = View.generateViewId()
        val endSet = ConstraintSet()
        endSet.clone(this)

        val transitionId = View.generateViewId()

        return TransitionBuilder.buildTransition(
            motionScene,
            transitionId,
            startSetId, startSet,
            endSetId, endSet
        )
    }

    /**
     * Get px from dp
     */
    private fun fromDp(context: Context, inDp: Int): Int {
        val scale = context.resources.displayMetrics.density
        return (inDp * scale).toInt()
    }
}

下面是我的适配器:

class SimpleMotionLayoutAdapter : RecyclerView.Adapter<SimpleMotionLayoutAdapter.ViewHolder>() {

    val items = mutableListOf<Int>() // colors

    class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
        fun setColor(color: Int) {
            (view as SimpleMotionLayout).setSquareColor(color)
        }
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = SimpleMotionLayout(parent.context)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.setColor(items[position])
    }

    override fun getItemCount(): Int = items.size

    companion object {
        const val TYPE_NORMAL = 0
        const val TYPE_EXCEPTIONAL = 1
    }
}

我是否缺少实施? 谢谢

【问题讨论】:

    标签: android kotlin android-recyclerview android-motionlayout


    【解决方案1】:

    一般来说,当 MotionLayout 被回收时,您需要缓存和恢复它的状态。 现在在 onBindViewHolder 你只设置颜色。 记住 RecyclerView 只保留一个屏幕价值(+ 大约 3)的 ViewHolder 并使用 onBindViewHolder 重用它们 至少您需要设置 MotionLayout 的进度。 由于时间上的差异,您可能需要在 onPost 中设置进度

    【讨论】:

      猜你喜欢
      • 2021-11-20
      • 1970-01-01
      • 2021-04-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      相关资源
      最近更新 更多