i try to implement programmatically version of MotionLayout by extending it. And i have a base activity ayout using RecyclerView. However, when i add my motion layout as an item of the RecyclerView, the view is not recycled when i try to scrolling up and down. And it works well when i use as a normal view (act as single view).
Here is the preview:
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()
}
}
Below is my adapter:
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
}
}
Am i missing implementation? Thank you