Skip to content

Instantly share code, notes, and snippets.

@fanjavaid
Last active December 3, 2021 04:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fanjavaid/38d52ce6d16072f58923a623b60f26cb to your computer and use it in GitHub Desktop.
Save fanjavaid/38d52ce6d16072f58923a623b60f26cb to your computer and use it in GitHub Desktop.
Swipe Button using Motion Layout
package com.tempercube.motionlayout.motions
import android.animation.ObjectAnimator
import android.animation.ValueAnimator.REVERSE
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Gravity
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.AccelerateInterpolator
import android.view.animation.BounceInterpolator
import android.view.animation.LinearInterpolator
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.constraintlayout.motion.widget.*
import androidx.constraintlayout.motion.widget.MotionLayout.DEBUG_SHOW_PATH
import androidx.constraintlayout.motion.widget.MotionLayout.DEBUG_SHOW_PROGRESS
import androidx.constraintlayout.motion.widget.OnSwipe.*
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.*
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textview.MaterialTextView
import com.tempercube.motionlayout.R
import kotlinx.android.synthetic.main.activity_sample7.*
class SampleActivity7 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample7)
val constraintLayout = createMotionLayout()
activity7_root.addView(
constraintLayout,
RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
).apply {
addRule(RelativeLayout.ALIGN_PARENT_START)
addRule(RelativeLayout.ALIGN_PARENT_TOP)
addRule(RelativeLayout.ALIGN_PARENT_END)
}
)
}
private fun createMotionLayout(): MotionLayout {
val label = createLabel()
val swipeButton = createButtonView()
val main = MotionLayout(this).apply {
id = R.id.constraint_container
layoutParams = ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
setBackgroundResource(R.drawable.shape_circle_black)
setDebugMode(DEBUG_SHOW_PATH and DEBUG_SHOW_PROGRESS)
}
main.setTransitionListener(object : MotionLayout.TransitionListener {
override fun onTransitionStarted(
motionLayout: MotionLayout?,
startId: Int,
endId: Int
) {
}
override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
}
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
if (currentId == motionLayout?.endState) {
motionLayout.progress = 1f
motionLayout.isInteractionEnabled = false
Snackbar.make(
this@SampleActivity7,
main,
"Creating transaction",
Snackbar.LENGTH_SHORT
).show()
}
}
override fun onTransitionTrigger(
motionLayout: MotionLayout?,
triggerId: Int,
positive: Boolean,
progress: Float
) {
}
})
main.addView(label)
main.addView(
swipeButton,
ConstraintLayout.LayoutParams(
150,
150
)
)
// Initial Layout
createConstraint(label, swipeButton, main)
// Start
val startSet = createStartSet(label, swipeButton, main)
// End
val endSet = createEndSet(label, swipeButton, main)
// Create motion transition
val motionScene = MotionScene(main)
val transition = createTransition(motionScene, startSet, endSet)
transition.addOnSwipeEvent(swipeButton)
// Update alpha of the label on Progress position 70%
val key = KeyAttributes().apply {
this.framePosition = 70
this.setValue(Key.ALPHA, 0f)
this.setViewId(label.id)
}.clone()
transition.addKeyFrame(
KeyFrames().apply {
addKey(key)
}
)
motionScene.addTransition(transition)
main.scene = motionScene
main.setTransition(transition.id)
// Additional animation when user open screen bounce the circle image
Handler(Looper.getMainLooper()).postDelayed({
ObjectAnimator.ofFloat(swipeButton, View.TRANSLATION_X, 100f).apply {
repeatMode = REVERSE
repeatCount = 1
duration = 200
interpolator = AccelerateDecelerateInterpolator()
}.start()
}, 500)
return main
}
private fun createLabel(): MaterialTextView {
return MaterialTextView(this).apply {
id = R.id.default_text
text = "Setuju dan Bayar"
gravity = Gravity.CENTER_HORIZONTAL
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setTextAppearance(R.style.TextAppearance_MaterialComponents_Headline6)
} else {
textSize = 20f
}
setTextColor(Color.parseColor("#EEEEEE"))
}
}
private fun createButtonView(): ImageView {
return AppCompatImageView(this).apply {
id = R.id.default_button
setImageResource(R.drawable.ic_right_arrow_circle)
}
}
private fun createConstraint(text: TextView, button: ImageView, layout: ConstraintLayout) {
createStartSet(text, button, layout)
}
private fun createStartSet(
text: TextView,
button: ImageView,
layout: ConstraintLayout
): ConstraintSet {
return ConstraintSet().apply {
clone(layout)
connect(text.id, START, layout.id, START)
connect(text.id, END, layout.id, END)
connect(text.id, TOP, layout.id, TOP)
connect(text.id, BOTTOM, layout.id, BOTTOM)
connect(button.id, START, layout.id, START)
connect(button.id, TOP, layout.id, TOP)
connect(button.id, BOTTOM, layout.id, BOTTOM)
applyTo(layout)
}
}
private fun createEndSet(
text: TextView,
button: ImageView,
layout: ConstraintLayout
): ConstraintSet {
return ConstraintSet().apply {
clone(layout)
clear(button.id, START)
connect(button.id, END, layout.id, END)
connect(button.id, TOP, layout.id, TOP)
connect(button.id, BOTTOM, layout.id, BOTTOM)
setAlpha(text.id, 0f)
applyTo(layout)
}
}
private fun createTransition(
scene: MotionScene,
startSet: ConstraintSet,
endSet: ConstraintSet
): MotionScene.Transition {
val startSetId = R.id.start_id
val endSetId = R.id.end_id
val transitionId = View.generateViewId()
return TransitionBuilder.buildTransition(
scene,
transitionId,
startSetId,
startSet,
endSetId,
endSet
)
}
}
private fun MotionScene.Transition.addOnSwipeEvent(view: View) {
setOnSwipe(
OnSwipe().apply {
dragDirection = DRAG_RIGHT
touchAnchorId = view.id
touchAnchorSide = SIDE_RIGHT
onTouchUp = ON_UP_AUTOCOMPLETE_TO_START
setMaxAcceleration(20)
}
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment