I'm a beginner in kotlin
, but I know java
. So I've created a program, where I have one textview
. It will change it's test every 1sec with fade animation. So my program works fine, but as I'm beginner in kotlin
, can you help me or give a feedback related to my code. Also if I wrote something wrong, you can edit it without any problem :)
class MainActivity : AppCompatActivity() {
private lateinit var fadeInAnimation: Animation
private lateinit var fadeOutAnimation: Animation
private lateinit var handler: Handler
private lateinit var myRunnable: Runnable
private val textArray: Array<String> = arrayOf("This", "is", "fading", "text")
private var textPosition: Int = 0
companion object {
private const val ANIM_DURATION: Long = 1000L
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
fadeOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out)
handler = Handler()
initRunnable()
}
override fun onResume() {
super.onResume()
startAnimation()
}
override fun onPause() {
super.onPause()
stopAnimation()
}
private fun initRunnable() {
myRunnable = Runnable {
text_view.animation = fadeOutAnimation
fadeOutAnimation.start()
fadeOutAnimation.setAnimationListener(object : AnimationListener() {
override fun onAnimationEnd(animation: Animation?) {
textPosition = when (textPosition) {
textArray.size - 1 -> 0
else -> ++textPosition
}
startAnimation()
}
})
}
}
private fun startAnimation() {
text_view.text = textArray[textPosition]
text_view.animation = fadeInAnimation
fadeInAnimation.start()
handler.postDelayed(myRunnable, ANIM_DURATION)
}
private fun stopAnimation() {
handler.removeCallbacksAndMessages(null)
fadeInAnimation.cancel()
fadeOutAnimation.cancel()
}
}
Please leave feedback related to my code, how can I make it more clear, or maybe something I've done not right, or maybe something is not a practice? Thank you.
I would create one single animation in XML that does the fade in, delay, and fade out. Then you wouldn't need to use the handler to post the fade-out or juggle two animations. But since we're just looking at the Kotlin code:
- There's no reason for the Runnable to even have a property if you're never using it again. Also, there's a
postDelayed
extension function that swaps the argument order so you can use a trailing lambda. (You could alternatively store the Runnable in aval
so it's only instantiated once like in the comment from @Mostafa, but in my opinion it's trivially small and the code is clearer if you keep it at the location it's used.) - You can simplify decrementing
textPosition
with the remainder operator (also would apply to Java). - If your companion object has nothing but private constants, it's better to move it outside the class because companion objects get compiled as a new class and have an instance.
- You only need to set the animation listener once.
private const val ANIM_DURATION: Long = 1000L
class MainActivity : AppCompatActivity() {
private lateinit var fadeInAnimation: Animation
private lateinit var fadeOutAnimation: Animation
private lateinit var handler: Handler
private val textArray: Array<String> = arrayOf("This", "is", "fading", "text")
private var textPosition: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
fadeOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out).apply {
setAnimationListener(object : AnimationListener() {
override fun onAnimationEnd(animation: Animation?) {
textPosition = (textPosition - 1 + textArray.size) % textArray.size
startAnimation()
}
})
}
handler = Handler()
}
override fun onResume() {
super.onResume()
startAnimation()
}
override fun onPause() {
super.onPause()
stopAnimation()
}
private fun startAnimation() {
text_view.text = textArray[textPosition]
text_view.animation = fadeInAnimation
fadeInAnimation.start()
handler.postDelayed(ANIM_DURATION) {
text_view.animation = fadeOutAnimation
fadeOutAnimation.start()
}
}
private fun stopAnimation() {
handler.removeCallbacksAndMessages(null)
fadeInAnimation.cancel()
fadeOutAnimation.cancel()
}
}
Also, if you define your animations using ObjectAnimator instead of the older Animations API, you can use doOnEnd
instead of the more clunky anonymous AnimationListener.