参考文章:(讲解更详细) https://blog.csdn.net/tongzhang1314/article/details/79084538
首先贴上效果图: (加载动画转动快是在模拟器的原因,真机并没有那么快)
思路:
1. 创建mBtnView类继承Button类,实现第二个构造方法(因为需要在xml中使用)
2. 通过GradientDrawable来定义按钮的背景,如圆角度颜色等值,(GradientDrawable是shape在代码中的使用,不了解可以百度下)
3. 通过ValueAnimator来实现按钮的缩放(由圆角矩形变为圆形的效果)
4. 通过 canvas.drawArc() 方法来画一个圆弧,并通过ValueAnimator来改变画圆弧时候的开始值,再通过invalidate()重绘界面来实现圆弧的转动
PS: 1,2在初始化时定义好就行,3,4放在点击事件中执行
自定义button的源码:
参考:view坐标系:
package com.example.administrator.mktproject.weight
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.support.annotation.RequiresApi
import android.util.AttributeSet
import android.widget.Button
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
/**
* Created by Administrator on 2019/7/30 0030.
* GradientDrawable Canvas
*/
open class SignInBtn(context: Context?, attrs: AttributeSet?) : Button(context, attrs){
private var mGradientDrawable: GradientDrawable? = null //设置按钮背景样式
private var paint : Paint? =null //画笔
private var mLeft = 0f //按钮左边缩放动画的值
private var mRight = 0f //按钮右边缩放动画的值
private var start : Float = 0f //圆弧开始动画的值
private var isdraw : Boolean = false //是否开始绘制圆弧
private var mValueAnimator2 : ValueAnimator? = null
/**
* 初始化块
*/
init {
initView()//设置按钮的初始样式
}
/**
* 设置按钮的初始样式
*/
private fun initView() {
//初始化画笔
paint= Paint() // 创建画笔
paint!!.isAntiAlias = true // 设置画笔抗锯齿(使线条平滑)
paint!!.color = Color.parseColor("#ffffff") // 设置画笔颜色
paint!!.strokeWidth = 4f // 设置画笔宽度
paint!!.style = Paint.Style.STROKE // 设置画笔风格
//初始化按钮背景样式
mGradientDrawable = GradientDrawable() //shape在代码中的使用方式
mGradientDrawable!!.setColor(Color.argb(100,0,0,255)) //按钮背景颜色
mGradientDrawable!!.cornerRadius = 130f //按钮圆角度
background = mGradientDrawable
}
/**
* 开始按钮变成圆形的动画
*/
open fun mBtnAinim() {
isEnabled = false //设置动画期间按钮不可点击
text = "" //设置按钮文字为空
val mValueAnimator = ValueAnimator.ofInt(width, height) //按钮变形动画,就是把宽度变为和高度一样
mValueAnimator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
override fun onAnimationUpdate(animation: ValueAnimator) {
val value: Int = animation.animatedValue as Int
mLeft = (width-value)/2f
mRight = width-(width-value)/2f
// setBounds(left,top,right,bottom) 这四个参数值不明白可以参考view坐标系
mGradientDrawable!!.setBounds(mLeft.toInt(),0,mRight.toInt(),height)
}
})
mValueAnimator.duration = 500 //设置动画时长500毫秒
mValueAnimator.start()
mValueAnimator.addListener(object : AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) { //动画结束事件的监听
super.onAnimationEnd(animation)
drawArc()//画圆弧 加载圆弧动画
}
})
}
/**
* 开始圆弧旋转的动画
*/
private fun drawArc() {
isdraw = true //改变状态 这样onDraw方法就可以画出圆弧
mValueAnimator2 = ValueAnimator.ofFloat(0f,360f)
mValueAnimator2!!.addUpdateListener(object :ValueAnimator.AnimatorUpdateListener{
override fun onAnimationUpdate(animation: ValueAnimator?) {
start = animation!!.animatedValue as Float
invalidate() // 重绘view
}
})
mValueAnimator2!!.repeatCount = ValueAnimator.INFINITE // 设置动画无限重复
mValueAnimator2!!.duration = 500
mValueAnimator2!!.start()
}
/**
* 结束动画
*/
open fun endAnim(btnText:String){
//把btn改为原来样式
val mValueAnimator = ValueAnimator.ofInt(0,width) //原来按钮的宽度值
mValueAnimator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
override fun onAnimationUpdate(animation: ValueAnimator) {
val value: Int = animation.animatedValue as Int
mGradientDrawable!!.setBounds((width-value)/2,0,width-(width-value)/2,height)
}
})
mValueAnimator.duration = 500
mValueAnimator.start()
mValueAnimator.addListener(object : AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
text = btnText // 改变btn字体
isEnabled = true //设置按钮可点击
}
})
mValueAnimator2!!.end()//停止圆弧旋转
isdraw = false // 不画弧
invalidate() //重绘界面
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (isdraw){ //如果按钮动画完成缩放变形在开始画弧,不让按钮缩放时就会画弧,很难看
val mRectF = RectF(mLeft+10,10f,mRight-10,height-10.toFloat())
canvas!!.drawArc(mRectF,start,160f,false,paint) //画圆弧
}
}
}
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="com.example.administrator.mktproject.MainActivity">
<EditText
android:id="@+id/et"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/btn"
android:layout_centerInParent="true"
android:layout_marginBottom="30dp"
android:background="@drawable/et"
android:ems="10"
android:hint="你是不是个弟弟!"
android:paddingBottom="8dp"
android:paddingStart="5dp"
android:paddingTop="8dp" />
<com.example.administrator.mktproject.weight.SignInBtn
android:id="@+id/btn"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="50dp"
android:textColor="#fff"
android:text="想好再按!"
android:textSize="16sp" />
</RelativeLayout>
Activity代码:
package com.example.administrator.mktproject
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.os.SystemClock
import android.support.annotation.RequiresApi
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn.setOnClickListener {
btn.mBtnAinim()//开始加载动画
val str = et.text.toString()
Thread(Runnable {
Thread.sleep(2000)
Looper.prepare()
if (str == "是") {
runOnUiThread({
btn.endAnim("知道就行!弟弟!")
})
} else {
runOnUiThread({
btn.endAnim("你就是弟弟!")
})
}
Looper.loop()
}).start()
}
}
}