效果图
(ps: 其实就两个半径和透明度一起变化的小圆, 本项目中用来指示指尖位置)
实现原理
监听点击的位置,在父布局中动态增加 自定义的动画View
代码实现
(1)activity
点击监听及添加View
// 触屏点击位置
private var pointX: Int = 0
private var pointY: Int = 0
private var circleView: SpreadCircleView?= null
// 触摸点击
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event!!.action) {
MotionEvent.ACTION_DOWN -> {
pointX = event.x.toInt()
pointY = event.y.toInt()
}
MotionEvent.ACTION_MOVE -> { }
MotionEvent.ACTION_UP ->{ addPointCircle() }
else -> { }
}
return true
}
fun addPointCircle(){
if(circleView == null){
circleView = SpreadCircleView(this);
circleView?.let{
lifecycle.addObserver(it)
}
}
binding.rootLayout.removeView(circleView)
circleView?.let{
// 宽度和高度相同
val width = it.maxRadius.toInt() * 2
var lp = FrameLayout.LayoutParams(width, width )
lp.marginStart = pointX - width/2
lp.topMargin = pointY - width/2
binding.rootLayout.addView(it, lp)
it.startAnimation()
}
}
(2)圆点View
实现(属性动画,根据动画进度来确定圆的当前半径,利用LifecycleObserver
绑定周期)
class SpreadCircleView : View, LifecycleObserver {
private var paint: Paint = Paint()
// 圆圈最大半径
val maxRadius = 25.toPx()
// 圆圈中心点
var centerX:Int = 0
var centerY:Int = 0
private var animator : ObjectAnimator? = null
// 是否已开始绘制第二个圆
var hasDrawCicle2 = false
// 动画进度
private var progress = 0f
set(value){
field = value
// 刷新界面
invalidate()
}
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context,
attrs,
defStyleAttr)
init{
paint.style = Paint.Style.FILL
paint.color = ContextCompat.getColor(context, R.color.rect_orange) // #ffa200
paint.strokeWidth = 3.toPx()
paint.isAntiAlias = true // 防锯齿
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
//圆心位置
centerX = w / 2;
centerY = h / 2;
}
override fun draw(canvas: Canvas?) {
super.draw(canvas)
// 第一个圆
drawCircle(canvas, progress)
// 第二个圆
if(hasDrawCicle2 || progress > 0.5f ){
// 第一个圆的进度第一次达到 0.5 时,开始绘制第二个圆,
hasDrawCicle2 = true
var progress2 = progress + 0.5f
if(progress2 > 1){
progress2 = progress2 - 1
}
drawCircle(canvas, progress2)
}
}
fun drawCircle(canvas: Canvas?, animProgress: Float){
// 透明度 0 - 255
var alpha = 255 * (1 - animProgress)
paint.alpha = alpha.toInt()
var radius = maxRadius * animProgress
// 绘制圆
canvas?.drawCircle(centerX.toFloat(), centerY.toFloat(), radius, paint )
}
private fun getAnimator(): ObjectAnimator?{
if(animator == null){
animator = ObjectAnimator.ofFloat(this,
"progress", 0f, 0.99f)
animator?.duration = 1500
animator?.repeatCount = -1 //-1代表无限循环
animator?.interpolator = LinearInterpolator()
}
return animator
}
fun startAnimation() {
// 开始动画
getAnimator()?.start()
hasDrawCicle2 = false
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun resume() {
// 开始动画
animator?.start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun pause() {
animator?.pause()
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun destory() {
// 清除动画,避免内存泄漏,
animator?.cancel()
clearAnimation()
}
}
补充一个用到的扩展函数
fun Int.toPx(): Float{
val resources = Resources.getSystem()
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
this.toFloat(),
resources.displayMetrics
)
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。