Android自定义控件(二)——支付宝支付成功动画

简介: 读律看书三九年,乌纱头上有青天,男儿欲画凌烟阁,第一功名不爱钱。

不知道大家关注过没有,在你使用支付宝的过程中,有一个支付成功的动画,虽然说很小,但看起来其实还是蛮实用的,涉及的知识点有Android属性动画,Paint的getSegment()函数。

1.png


1.分析动画


首先,我们来分析一下这个动画,如上图所示,我们可以看到,先是圆自己运行闭合,然后在在圆的里面画一个✔,对于圆来说,很简单,无外乎定位圆心与半径就行,难点在于✔的设计,所以我们先用一张图来分析一下,如下图所示:


2.png

假设圆的半径为mRadius,圆心O坐标为(X,Y),我们把对勾的起点放在A点,假设A的坐标为在圆心平行线中间,那么A的坐标就是(X-mRadius/2,Y),同理,我们假设B的坐标也在圆心垂直线下中心,那么B的坐标为(X,Y+mRadius/2),因为在屏幕中,原点在屏幕的右上角,正方向X轴向右,正方向Y轴向下,所以这里是加,同理,C点肯定要接近圆的边缘,所以C的X轴肯定大于mRadius的一半,姑且我们这里设为X+mRadius/2,而Y也相对来说在上边,而Y不能超出圆外,所以我们根据cX = x + r * cos(a * π / 180);cY = y + r * sin(a * π / 180),计算出该X坐标在圆圈的坐标,小于这个坐标的Y轴设置就行,这里小编C点设置为(x+mRadius/2,Y-mRadius/3)。


2.自定义View


原理我们分析清楚了,下面就可以自定义View,来实现支付宝支付成功的动画了,首先,老样子与刮一刮类似,在Android Studio中间创建一个类继承View,实现如下三个构造函数:

public class AlipayView extends View {
    public AlipayView(Context context) {
        super(context);
    }
    public AlipayView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public AlipayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

接着我们定义成员变量,如下图所示:

private Paint paint;//画笔工具
private Path circlePath,dstPath;//圆路径,截取路径
private PathMeasure pathMeasure;//计算路径的参数
private float mCurrentValue;//动画执行的进度
private int X,Y,mRadius;//圆心坐标与半径

这里,我们定义了一个画笔工具,两个路径,以及计算路径个参数的计算器类,以及动画执行的进度,所有用到的成员变量都在这里,接着就是初始化我们的AlipayView。

public AlipayView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速
        this.paint=new Paint(Paint.ANTI_ALIAS_FLAG);//初始化画笔,且设置为抗锯齿
        this.paint.setStrokeWidth(4);//设置画笔宽度
        this.paint.setStyle(Paint.Style.STROKE);//设置描边
        this.dstPath=new Path();//初始化
        this.circlePath=new Path();//初始化
        this.circlePath.addCircle(X,Y,mRadius,Path.Direction.CW);//顺时针画圆
        //下面三行代码画的是勾的路径,对照上面分析图
        this.circlePath.moveTo(X-mRadius/2,Y);
        this.circlePath.lineTo(X,Y+mRadius/2);
        this.circlePath.lineTo(X+mRadius/2,Y-mRadius/3);
        this.pathMeasure=new PathMeasure(this.circlePath,false);//不闭合
        ValueAnimator valueAnimator=ValueAnimator.ofFloat(0,2);//这里分两段动画,一段画圆,一段画勾
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurrentValue=(float)animation.getAnimatedValue();//获取动画进度
                invalidate();//获取到进度后进行重绘,会调用onDraw(Canvas canvas)
            }
        });
        valueAnimator.setDuration(4000);//每次动画时间
        valueAnimator.start();//执行动画
    }

这里我们初始化View主要做了三件事,第一初始化各个成员变量,其二将圆的路径与勾的路径初始化,但并没有绘制,绘制都在onDraw(Canvas canvas)函数里面,第三,初始化动画的参数,第四,获取路径的计算器,计算器包含路径的一些信息(pathMeasure)。


3.onDraw(canvas)绘制动画


初始化各个成员变量以及动画参数后,最后就是要将我们的这些信息,绘制到屏幕上去,而自定义View绘制函数是onDraw(Canvas),代码如下:

private boolean mNext=false;//判断是否指闭合
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);//首先绘制背景色为白色
        if(this.mCurrentValue<1){
            //初始化函数中说过,mCurrentValue是记录动画的进度的,而小编将动画进度设置为2,(0,1)就是画圆圈,(1,2)就是画对勾
            //而且mCurrentValue的进度是随机的,并不一定获取到1,所以别拿等等与1来计算,只要大于1就执行画对勾就行
            float stop=this.pathMeasure.getLength()*this.mCurrentValue;//计算当前进度下路径的百分比,比如,0.25画到圆的4分之一,那么整个圆绘画进度长度就在这里计算得到。
            //前面说过dstPath是截取路径,比如一张图片长200,我截取一半就有100,同样通过pathMeasure.getSegment就可以截取circlePath的当前进度路径。
            this.pathMeasure.getSegment(0,stop,dstPath,true);
        }else{
            if(!mNext){
                this.mNext=true;
                //刚说过了,动画的进度值并不一定会获取到1,有可能直接从0.99跳到1.01,那么没绘制完成的部分,就需要绘制先绘制完成
                this.pathMeasure.getSegment(0,this.pathMeasure.getLength(),dstPath,true);
                this.pathMeasure.nextContour();//因为圆与对勾并没有闭合,所以算两个路径,这句代码就是切换到对勾路径上
            }
            float stop=this.pathMeasure.getLength()*(this.mCurrentValue-1);//每条进度都是按1算百分比的, 但动画设置的是2,所以减去圆的1,单独计算勾的路径百分比
            this.pathMeasure.getSegment(0,stop,dstPath,true);
        }
        canvas.drawPath(dstPath,paint);//把截取到的路径画出来
    }

这段首先绘制自定义控件的背景为白色,然后判断动画的进度,如果小于1,执行圆的生成动画,通过PathMeasure.getSegment将截取的路径存储到dstPath中,而当动画进度不小于1的时候, 因为动画的插值器并不一定会获取到1这个值,所以接下来首先做的就是先闭合这个圆,然后通过next.Contour()切换到勾的路径,在根据动画的值绘制勾出来,最后调用canvas将截取的路径画到自定义View上面,也就是屏幕上。

private int X=500,Y=500,mRadius=250;//圆心坐标

当然照搬上面代码肯定什么都没有,因为X,Y,mRaduis,都没有赋值,所以根据自己的需求调整大小,或者设置一个函数,让外部调用设置灵活的X,Y,半径都行,代码如上。


XML布局文件代码如下:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.liyuanjinglyj.alipayapplication.AlipayView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

本文代码Github下载地址:点击下载

相关文章
|
3月前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的海洋中,自定义控件是那片璀璨的星辰。它不仅让应用界面设计变得丰富多彩,还提升了用户体验。本文将带你探索自定义控件的核心概念、实现过程以及优化技巧,让你的应用在众多竞争者中脱颖而出。
|
27天前
|
搜索推荐 Android开发 开发者
安卓应用开发中的自定义控件实践
在安卓应用开发的广阔天地中,自定义控件如同璀璨的星辰,点亮了用户界面设计的夜空。它们不仅丰富了交互体验,更赋予了应用独特的个性。本文将带你领略自定义控件的魅力,从基础概念到实际应用,一步步揭示其背后的原理与技术细节。我们将通过一个简单的例子——打造一个具有独特动画效果的按钮,来展现自定义控件的强大功能和灵活性。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往更高阶UI设计的大门。
|
3月前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
3月前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件基础与进阶
【10月更文挑战第5天】在Android应用开发中,自定义控件是提升用户体验和界面个性化的重要手段。本文将通过浅显易懂的语言和实例,引导你了解自定义控件的基本概念、创建流程以及高级应用技巧,帮助你在开发过程中更好地掌握自定义控件的使用和优化。
60 10
|
2月前
|
前端开发 Android开发 UED
安卓应用开发中的自定义控件实践
【10月更文挑战第35天】在移动应用开发中,自定义控件是提升用户体验、增强界面表现力的重要手段。本文将通过一个安卓自定义控件的创建过程,展示如何从零开始构建一个具有交互功能的自定义视图。我们将探索关键概念和步骤,包括继承View类、处理测量与布局、绘制以及事件处理。最终,我们将实现一个简单的圆形进度条,并分析其性能优化。
|
3月前
|
前端开发 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的世界里,自定义控件如同画家的画笔,能够绘制出独一无二的界面。通过掌握自定义控件的绘制技巧,开发者可以突破系统提供的界面元素限制,创造出既符合品牌形象又提供卓越用户体验的应用。本文将引导你了解自定义控件的核心概念,并通过一个简单的例子展示如何实现一个基本的自定义控件,让你的安卓应用在视觉和交互上与众不同。
|
4月前
|
缓存 前端开发 Android开发
安卓应用开发中的自定义控件
【9月更文挑战第28天】在安卓应用开发中,自定义控件是提升用户界面和交互体验的关键。本文通过介绍如何从零开始构建一个自定义控件,旨在帮助开发者理解并掌握自定义控件的创建过程。内容将涵盖设计思路、实现方法以及性能优化,确保开发者能够有效地集成或扩展现有控件功能,打造独特且高效的用户界面。
|
4月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义控件
【9月更文挑战第5天】在安卓开发的海洋中,自定义控件如同一艘精致的小船,让开发者能够乘风破浪,创造出既独特又高效的用户界面。本文将带你领略自定义控件的魅力,从基础概念到实战应用,一步步深入理解并掌握这一技术。
|
5月前
|
Android开发 UED 开发者
安卓开发中的自定义控件基础
【8月更文挑战第31天】在安卓应用开发过程中,自定义控件是提升用户界面和用户体验的重要手段。本文将通过一个简易的自定义按钮控件示例,介绍如何在安卓中创建和使用自定义控件,包括控件的绘制、事件处理以及与布局的集成。文章旨在帮助初学者理解自定义控件的基本概念,并能够动手实践,为进一步探索安卓UI开发打下坚实的基础。