按下按钮后做扩大(扩散)动画

Posted 夜尽天明89

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了按下按钮后做扩大(扩散)动画相关的知识,希望对你有一定的参考价值。

需求
1、录音按钮,按住后,做扩散动画,显示:录音中;
2、默认状态,显示:按住录音;
3、松手后,控件做反向收缩动画

UI规定
1、默认,按钮有个背景色(纯色),尺寸为:116 * 40;
2、按住后控件扩散,扩散过程中,出现一条描边,扩散到最远处,且,背景色变成透明;
3、控件扩散后,最大尺寸为124 * 44;
4、动效时长250毫秒;
5、松手后,控件做收缩动画,效果与上面相反

效果图示例(静态图):


分析:
1、尺寸分析:
扩散前后对比:124/116= 1.0689… ;44/40 = 1.1 。为了方便实现,这里定为1.1。即,做动画时,从原始尺寸,扩大1.1倍。116 * 1.1=127.6>124;124/1.1=112.7 ;113 * 1.1=124.3 最接近125
2、在设置布局的时候,一开始,就设置为最大尺寸,这样,可以避免其他控件挤占录音控件的位置,或者,录音控件扩大时,挤占其他控件,引起界面其他控件的不必要重绘。
3、经过上面的计算,结论:(1)在误差允许范围内,默认尺寸为:113 * 40,扩大比例为1.1,控件最大区域:125 * 44

思路:
拆分3层:1、描边;2、纯色背景;3、文字和小图片。
因为动画时间很短,且,扩大比例不大,纯色背景,就只做透明度变化。没有随着描边扩散。一般也看不出来,这里“取巧”简化了。

代码不多,也简单,就直接上源码了
代码:
用到的颜色

<color name="line_color">#55ff0000</color>
<color name="bg_color">#5500ff00</color>

<color name="color_trans">#00000000</color>
<color name="color_white">#ffffff</color>
<color name="color_black">#000000</color>

1、工具类


import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.GradientDrawable;

public class UiUtils 

    public static int dip2px(Context context, float dpValue) 
        final float scale = getResources(context).getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    

    /**
     * 获得资源
     */
    public static Resources getResources(Context context) 
        return context.getResources();
    

    /**
     * 获取drawable 边框的自定义方法,不用每次去新建drawable文件
     * @param solidColor       实体颜色
     * @param cornerRadiusInDp dp表示的边角半径
     * @param strokeWidthInDp  dp表示的边线宽度
     * @param strokeColor      边线颜色
     * @return GradientDrawable
     */
    public static GradientDrawable getGradientDrawable(Context context, int solidColor, int cornerRadiusInDp, float strokeWidthInDp, int strokeColor) 
        GradientDrawable drawable = new GradientDrawable();
        drawable.setCornerRadius(UiUtils.dip2px(context,cornerRadiusInDp));
        drawable.setStroke(UiUtils.dip2px(context,strokeWidthInDp), strokeColor);
        drawable.setColor(solidColor);
        return drawable;
    

    /**
     * 获取drawable 边框的自定义方法,适用于边线颜色与实体颜色相同的,不用每次去新建drawable文件
     * @param solidColor       实体颜色
     * @param cornerRadiusInDp dp表示的边角半径
     * @return GradientDrawable
     */
    public static GradientDrawable getGradientDrawable(Context context, int solidColor, int cornerRadiusInDp) 
        return getGradientDrawable(context,solidColor, cornerRadiusInDp, 0, solidColor);
    


2、布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    android:background="#eeeeee"
    tools:context=".MainActivity">

    <!-- 44/40=1.1,113*1.1=124.3 -->
    <RelativeLayout
        android:background="@color/color_white"
        android:id="@+id/voice_rl"
        android:layout_width="125dp"
        android:layout_height="44dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="50dp">

        <!--线的view-->
        <View
            android:id="@+id/line_view"
            android:layout_width="113dp"
            android:layout_height="40dp"
            android:layout_centerInParent="true"
            android:visibility="invisible" />

        <!--背景view-->
        <View
            android:id="@+id/bg_view"
            android:layout_width="113dp"
            android:layout_height="40dp"
            android:layout_centerInParent="true" />

        <LinearLayout
            android:id="@+id/str_ll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv"
                android:layout_width="15dp"
                android:layout_height="15dp"
                android:src="@mipmap/ic_default" />

            <TextView
                android:id="@+id/str_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="15dp"
                tools:text="录音" />

        </LinearLayout>


    </RelativeLayout>

</LinearLayout>

3、功能代码:

import android.animation.Animator
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() 

    //是否拦截动画
    private var isInterceptAnim: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        iv.setImageResource(R.mipmap.ic_default)
        str_tv.setTextColor(getColor(R.color.color_white))
        str_tv.text = "按住录音"

        line_view?.background = UiUtils.getGradientDrawable(
            this,
            ContextCompat.getColor(this, R.color.color_trans),
            50,
            1f,
            ContextCompat.getColor(this, R.color.line_color)
        )

        bg_view?.background = UiUtils.getGradientDrawable(
            this,
            ContextCompat.getColor(this, R.color.bg_color),
            50
        )

        voice_rl?.setOnTouchListener(object : View.OnTouchListener 
            override fun onTouch(p0: View?, p1: MotionEvent?): Boolean 

                when (p1?.action) 

                    MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> 

                        if (isInterceptAnim.not()) 
                            toAnim(true)
                        
                        isInterceptAnim = true
                    

                    MotionEvent.ACTION_UP -> 

                        isInterceptAnim = false

                        toAnim(false)
                    

                

                return true

            

        )

    


    private val maxScale = 1.1f
    private val minScale = 1f

    private var lineAnim: ValueAnimator? = null
    private var bgAnim: ObjectAnimator? = null

    private var duration: Long = 250L

    private fun toAnim(isDown: Boolean) 

        Log.e("lineAnim ", "isDown = $isDown")

        if (isDown) 
            lineAnim = ValueAnimator.ofFloat(minScale, maxScale)
            bgAnim = ObjectAnimator.ofFloat(
                bg_view,
                "alpha",
                1f, 0f
            )
         else 
            lineAnim = ValueAnimator.ofFloat(maxScale, minScale)
            bgAnim = ObjectAnimator.ofFloat(
                bg_view,
                "alpha",
                0f, 1f
            )
        

        lineAnim?.duration = duration
        bgAnim?.duration = duration

        lineAnim?.addUpdateListener 
            var scale = it.animatedValue as Float

            line_view.scaleX = scale
            line_view.scaleY = scale

        

        bgAnim?.addListener(object : Animator.AnimatorListener 
            override fun onAnimationStart(animator: Animator) 
                bg_view.visibility = View.VISIBLE
                line_view.visibility = View.VISIBLE
                Log.e("bgAnim ", "onAnimationStart")
            

            override fun onAnimationEnd(animator: Animator) 
                Log.e("bgAnim ", "onAnimationEnd ; isDown = $isDown")
                if (isDown) 

                    line_view.visibility = View.VISIBLE
                    bg_view.visibility = View.GONE

                    iv.setImageResource(R.mipmap.ic_down)
                    str_tv.setTextColor(getColor(R.color.color_black))
                    str_tv.text = "录音中"


                 else 
                    bg_view.visibility = View.VISIBLE
                    line_view.visibility = View.GONE

                    iv.setImageResource(R.mipmap.ic_default)
                    str_tv.setTextColor(getColor(R.color.color_white))
                    str_tv.text = "按住录音"
                
            

            override fun onAnimationCancel(animator: Animator) 

            

            override fun onAnimationRepeat(animator: Animator) 

            
        )

        lineAnim?.start()
        bgAnim?.start()

    


以上是关于按下按钮后做扩大(扩散)动画的主要内容,如果未能解决你的问题,请参考以下文章

按钮停止上的按下(波纹)动画

按下按钮时停止动画

按下按钮后如何动画显示 UIPickerView?

每次按下按钮“WPF动画”时,我如何重播相同的动画

Swift - 按下按钮时,如果动画已经在播放,则将其重置为开始

在动画期间检测按钮按下