Como criar um botão de carregamento personalizado estendendo o ViewClass no Android?
Neste artigo, vamos criar um botão de carregamento personalizado, estendendo a classe View e animar as propriedades do botão personalizado depois de clicado. Havíamos nos encontrado muitas vezes durante o download de qualquer arquivo e mantendo nossos olhos no progresso do download. Aqui, criaremos apenas aquele botão personalizado com animação. Um exemplo de GIF é fornecido abaixo para se ter uma ideia sobre o que faremos neste artigo. Observe que vamos implementar este projeto usando a linguagem Kotlin .
Implementação passo a passo
Etapa 1: Criar um novo projeto
Para criar um novo projeto no Android Studio, consulte Como criar / iniciar um novo projeto no Android Studio . Observe que selecione Kotlin como a linguagem de programação.
Etapa 2: Crie uma classe Sealed, ButtonState , que descreve o estado (como clicado, carregando e concluído) do botão personalizado. Abaixo está o código para o arquivo ButtonState.kt .
package com.gfg.article.customloadingbutton
// describes the state of the custom button
sealed class ButtonState() {
object Clicked : ButtonState() // when button is clicked for downloading
object Loading : ButtonState() // when downloading is in progress
object Completed : ButtonState() // when downloading is finished
}
Passo 3: Crie outra classe, LoadingButton , na qual tudo relacionado ao botão como cor, texto, animação, etc será definido. Faça um construtor anotando-o com JvmOverloads . Abaixo está o código para o arquivo LoadingButton.kt .
import android.animation.AnimatorInflater
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Typeface
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import com.gfg.article.customloadingbutton.ButtonState
import kotlin.properties.Delegates
class LoadingButton @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
private var bgColor: Int = Color.BLACK
private var textColor: Int = Color.BLACK // default color
// tells the compiler that the value of a variable
// must never be cached as its value may change outside
@Volatile
private var progress: Double = 0.0
private var valueAnimator: ValueAnimator
// observes the state of button
private var buttonState: ButtonState by Delegates.observable(ButtonState.Completed) { p, old, new ->
}
private val updateListener = ValueAnimator.AnimatorUpdateListener {
progress = (it.animatedValue as Float).toDouble()
invalidate() // redraw the screen
requestLayout() // when rectangular progress dimension changes
}
// call after downloading is completed
fun hasCompletedDownload() {
// cancel the animation when file is downloaded
valueAnimator.cancel()
buttonState = ButtonState.Completed
invalidate()
requestLayout()
}
// initialize
init {
isClickable = true
valueAnimator = AnimatorInflater.loadAnimator(
context,
// properties for downloading progress is defined
R.animator.loading_animation
) as ValueAnimator
valueAnimator.addUpdateListener(updateListener)
// initialize custom attributes of the button
val attr = context.theme.obtainStyledAttributes(
attrs,
R.styleable.LoadingButton,
0,
0
)
try {
// button back-ground color
bgColor = attr.getColor(
R.styleable.LoadingButton_bgColor,
ContextCompat.getColor(context, R.color.purple_200)
)
// button text color
textColor = attr.getColor(
R.styleable.LoadingButton_textColor,
ContextCompat.getColor(context, R.color.white)
)
} finally {
// clearing all the data associated with attribute
attr.recycle()
}
}
// set attributes of paint
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.FILL
textAlign = Paint.Align.CENTER // button text alignment
textSize = 55.0f //button text size
typeface = Typeface.create("", Typeface.BOLD) // button text's font style
}
override fun performClick(): Boolean {
super.performClick()
if (buttonState == ButtonState.Completed) buttonState = ButtonState.Loading
animation()
return true
}
// start the animation when button is clicked
private fun animation() {
valueAnimator.start()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
paint.strokeWidth = 0f
paint.color = bgColor
// draw custom button
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
// to show rectangular progress on custom button while file is downloading
if (buttonState == ButtonState.Loading) {
paint.color = Color.parseColor("#004349")
canvas.drawRect(
0f, 0f,
(width * (progress / 100)).toFloat(), height.toFloat(), paint
)
}
// check the button state
val buttonText = if (buttonState == ButtonState.Loading)
resources.getString(R.string.loading) // We are loading as button text
else resources.getString(R.string.download)// download as button text
// write the text on custom button
paint.color = textColor
canvas.drawText(buttonText, (width / 2).toFloat(), ((height + 30) / 2).toFloat(), paint)
}
}
Etapa 4: Trabalhando com o arquivo XML
Navegue até app> res> layout> activity_main.xml e adicione o código abaixo a esse arquivo. Abaixo está o código para o arquivo activity_main.xml .
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--Custom Button-->
<com.example.customloadingbutton.LoadingButton
android:id="@+id/custom_button"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="10dp"
android:layout_marginTop="100dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:textColor="@color/white" />
</androidx.constraintlayout.widget.ConstraintLayout>
attrs.xml (em res -> valores )
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LoadingButton">
<!--create custom attributes for the view-->
<attr name="bgColor" format="integer" />
<attr name="textColor" format="integer" />
</declare-styleable>
</resources>
loading_animation.xml (em res -> animador , crie o diretório do animador em res)
<?xml version="1.0" encoding="utf-8"?>
<animator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:valueFrom="0f"
android:valueTo="100f"
android:valueType="floatType" />
Etapa 5: Trabalhar com o arquivo MainActivity.kt
Acesse o arquivo MainActivity.kt e consulte o código a seguir. Abaixo está o código para o arquivo MainActivity.kt . Os comentários são adicionados dentro do código para entender o código em mais detalhes.
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
lateinit var loadingButton: LoadingButton
private var complete = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadingButton = findViewById(R.id.custom_button)
loadingButton.setOnClickListener {
Toast.makeText(this, "File is downloading", Toast.LENGTH_LONG).show()
complete = true
}
if (complete) {
// call when download completed
loadingButton.hasCompletedDownload()
}
}
}
Saída:
Código Fonte: Link
As postagens do blog Acervo Lima te ajudaram? Nos ajude a manter o blog no ar!
Faça uma doação para manter o blog funcionando.
70% das doações são no valor de R$ 5,00...
Diógenes Lima da Silva