重学 Android 自定义 View 系列(七):仿58同城加载动画

前言

本文将实现早期58同城一个带有弹跳效果的加载动画,且结合图形变换(圆形变正方形、正方形变三角形等)实现一种动态、富有表现力的加载效果。

最终效果如下:
在这里插入图片描述

1. 效果分析


  • 形状切换: 显示一个不断变化的形状,例如圆形、正方形、三角形之间的变换。
  • 弹跳效果: 加载图标会有上下弹跳的动画,增加动感。
  • 阴影效果: 动画中随着形状变化,添加一个阴影效果,随着形状变化而收缩或放大。

效果展示:

  1. 初始状态: 显示一个圆形图标,伴随初始弹跳。
  2. 动画过程: 随着动画的进行,圆形变为正方形,再变为三角形,每次形状变换后都会触发一次上下弹跳。
  3. 动画结束: 当动画完成时,图标将继续上下弹跳,直至用户操作或停止。

2. 结构分析


由上面GIF图可知,加载动画组合布局分为 上 中 下 三部分:分别是上面一个ShapeView 负责切换不同形状,中间一个View 用于模拟阴影效果,底部是加载文字,至于所有动效全部由各种动画实现。

为了方便控制上中下三部分内容,需要自定义一个LoadingView,用于包含这三部分View,其内部实现各个View的动画效果。

3. 技术实现


3.1 ShapeView

用于绘制三种图形:圆形、矩形、三角形。且具有形状切换功能,比如 先绘制圆形,圆形展示完绘制矩形,矩形展示完绘制三角形,三角形展示完再绘制圆,首尾相连。

首先我们要确保ShapeView 是个正方形,才能保证绘制出的三种图形都比较规则。

   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        //确保是正方形
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int size = Math.min(width, height);

        setMeasuredDimension(size, size);
    }

接着,要定义三种图形的枚举类,方便切换使用:

    public void exchangeShape(){
   
   
        switch (currentShapeType){
   
   
            case CIRCLE:
                currentShapeType = ShapeType.SQUARE;
                break;
            case SQUARE:
                currentShapeType = ShapeType.TRIANGLE;
                break;
            case TRIANGLE:
                currentShapeType = ShapeType.CIRCLE;
                break;
        }
        invalidate();
    }

    public ShapeType getCurrentShapeType() {
   
   
        return currentShapeType;
    }

    public enum ShapeType{
   
   
        CIRCLE, //圆形
        SQUARE, //正方形
        TRIANGLE //三角形
    }

然后,在onDraw中绘制三种图形,其中圆和矩形最简单,有现成的方法canvas.drawCirclecanvas.drawRect在此不做介绍了,三角形需要介绍一下,因为三角形要使用Path进行绘制,且为了美观要绘制一个等边三角形:
在这里插入图片描述
要绘制三角形,我们首先要知道三角形的三个顶点的坐标,才能进行绘制,由于ShapeView我们已经保证是正方形了,所以顶点坐标就是(getWidth() / 2,0),左边顶点坐标不能是(0,getHeight()) 因为这样绘制的三角形就是等边三角形了,影响美观,而要实现等边三角形的话就要重新计算Y轴坐标,由上面草图可知,大三角形分成开两个小三角形,我们知道底边和斜边是1/2的关系,由三角定理可知,一份二份根号三份,所以长的直角边就是根号三的getWidth(),此时我们就拿到了三个顶点坐标了。

  if (mPath == null) {
   
   
                    mPath = new Path();
                    mPath.moveTo(getWidth() / 2,0);
                    mPath.lineTo((float) 0, (float) ((getHeight() / 2) * Math.sqrt(3)));
                    mPath.lineTo(getWidth(),(float) ((getHeight() / 2) * Math.sqrt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值