Android动画进阶

在Android中,实现动画的方式通常有两种:视图动画和属性动画。然而这两种方式只能实现一些较为简单动画,仅仅通过改变这些控件属性的方式实现一些复杂的动画效果是比较有难度的,那么我们该如何实现复杂的动画。这里介绍两种实现方式:PathMeasure和SVG。

利用PathMeasure实现路径动画

PathMeasure是Android提供给开发者的一个API用于实现一个Path路径点的坐标追踪功能,类似于一个计算器,可以计算出指定路径的一些信息,比如路径总长、指定长度所对应的坐标点等。

常用方法介绍

  • 初始化
    PathMeasure有两种初始化方式:
 PathMeasure pathMeasure = new PathMeasure();
 setPath(Path path, boolean forceClosed)

初始化pathMeasure后,可以通过调用PathMeasure.setPath()函数来将Path和PathMeasure进行绑定。这样就已经初始化完成了,可以调用pathMeasure来返回路径的相关信息。
也可以通过PathMeasure的另一个构造函数直接完成初始化。

PathMeasure(Path path, boolean forceClosed)

在setPath函数和PathMeasure的第二个构造函数中都有一个参数boolean forceClosed,表示Path最终是否需要闭合,如果问true,则不管关联的Path是否是闭合的,都会被闭合。但是forceClosed参数对绑定的Path不会产生任何影响,例如一个折现段的Path,本身没有闭合,当forceClosed设置为true的时候,PathMeasure计算的Path是闭合的,但Path本身绘制出来的是不会闭合的。

  • getLength函数
public float getLength();

PathMeasure.getLength()函数的作用就是获取计算的路径长度。如果forceClosed为false,则测量的是当前Path状态的长度;如果forceClosed为true,则不论Path是否闭合,测量的都是Path的闭合长度。

  • isClosed函数
public boolean isClosed()

该函数用于判断测量Path时是否计算闭合。所以,如果在关联Path的时候设置forceClosed为true,则这个函数的返回值一定为true。

  • nextContour
    Path可以由多条曲线构成,但不论是getLength、getSegment还是其他函数,都只会针对其中第一条线段进行计算。而nextContour就是用于跳转到下一条曲线的函数。如果跳转成功,则返回true;如果跳转失败,则返回false。通过该函数获取得到的曲线的顺序与Path中添加的顺序相同。

  • getSegment

public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

这个API用于截取整个Path中的某个片段,通过参数startD和stopD来控制截取的长度,并将截取后的Path保存到参数dst中。最后一个参数startWithMoveTo表示起始点是否使用moveTo将路径的新起始点移到结果Path的起始点,通常设置为true,以保证每次截取的Path都是正常的、完整的,通常和dst一起使用,因为dst中保存的Path是被不断添加的,而不是每次被覆盖的;如果设置为false,则新增的片段会从上一次Path终点开始计算,这样可以保证截取的Path片段是连续的。
注意:1.如果startD、stopD的数值不在取值范围[0,getLength]内,或者在startD==stopD,则返回值为false,而且不会改变dst中的内容。2.开启硬件加速功能后,绘图会出现问题。因此,在使用getSegment函数时需要禁用硬件加速功能。目前可以在自定义View的构造函数中调用setLayerType(LAYER_TYPE_SOFTWARE,null)函数来禁用硬件加速功能。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • getPosTan
    该函数用于得到路径上某一长度的位置以及该位置的正切值。该函数的声明如下:
    public boolean getPosTan(float distance, float pos[], float tan[]) {
        if (pos != null && pos.length < 2 ||
            tan != null && tan.length < 2) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return native_getPosTan(native_instance, distance, pos, tan);
    }
  1. distance:距离Path起始点的长度,取值范围为[0,getLength]
  2. pos:该点的坐标值。当前点在画布上的位置有两个数值,分别为x,y坐标。pos[0]表示x坐标,pos[1]表示y坐标。
  3. tan:该点的正切值。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • getMatrix
    该函数用于得到路径上某一长度的位置以及该位置的正切值的矩阵。
public boolean getMatrix(float distance, Matrix matrix, int flags) {
        return native_getMatrix(native_instance, distance, matrix.ni(), flags);
    }
  1. distance:距离Path起始点的长度。
  2. matrix:根据flags封装好的matrix会根据flags的设置而存入不同的内容。
  3. flags:用于指定哪些内容会存入matrix中。flags的值有两个:PathMeasure.POSITION_MATRIX_FLAG表示获取位置信息; PathMeasure.TANGENT_MATRIX_FLAG表示获取切边信息,使得图片按Path旋转。可以只指定一个,也可以使用“|”同时指定。
    很明显,getMatrix函数只是getPosTan函数的另一种实现而已。getPosTan函数把获取到的位置信息和切边信息分别保存在pos和tan数组中;而getMatrix函数则直接将其保存到matrix数组中。
  • 案例如下:
package com.mvp.vpnapplication;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class GetPosTanView extends View {
    private Path mCirclePath, mDstPath;
    private Paint mPaint;
    private PathMeasure mPathMeasure;
    private Float mCurAnimValue;
    private Bitmap mArrawBmp;

    public GetPosTanView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        mArrawBmp = BitmapFactory.decodeResource(getResources(), R.drawable.arrow_right);//不能时svg类型的图片,拿不到宽高,必须是位图

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(4);
        mPaint.setColor(Color.BLACK);

        mDstPath = new Path();
        mCirclePath = new Path();
        mCirclePath.addCircle(100, 100, 50, Path.Direction.CW);

        mPathMeasure = new PathMeasure(mCirclePath, true);

        ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurAnimValue = (Float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.setDuration(2000);
        animator.start();
    }

    private float[] pos = new float[2];
    private float[] tan = new float[2];

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);

        float length = mPathMeasure.getLength();
        float stop = length * mCurAnimValue;
        float start = (float) (stop - ((0.5 - Math.abs(mCurAnimValue - 0.5)) * length));

        mDstPath.reset();
        mPathMeasure.getSegment(start, stop, mDstPath, true);
        canvas.drawPath(mDstPath, mPaint);

        //getPosTan方法实现
        //旋转箭头图片,并绘制
        mPathMeasure.getPosTan(stop, pos, tan);
        float degrees = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
        Matrix matrix = new Matrix();
        matrix.postRotate(degrees, mArrawBmp.getWidth() / 2, mArrawBmp.getHeight() / 2);
        matrix.postTranslate(pos[0] - mArrawBmp.getWidth() / 2, pos[1] - mArrawBmp.getHeight() / 2);
        canvas.drawBitmap(mArrawBmp, matrix, mPaint);
    }
}

SVG动画

SVG是矢量图,而且是专门用于网络的矢量图形标准。与矢量图相对应的是位图,Bitmap就是位图,它由一个个像素点组成,当图片放大到一定大小时,就会出现马赛克现象。ps就是常用的位图处理软件。而矢量图则由一个个点组成,经过数学计算利用直线和曲线绘制而成,无论如何放大,都不会出现马赛克现象,Illustrator就是常用的矢量图绘图软件。
在这里插入图片描述
在这里插入图片描述

vector标签与图像显示

在Android中,SVG矢量图是使用标签定义的,并放在res/drawable目录下。

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="24dp"
    android:width="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="#000000"
        android:pathData="M19.35,10.04 C18.67,6.59,15.64,4,12,4 C9.11,4,6.6,5.64,5.35,8.04
C2.34,8.36,0,10.91,0,14 C0,17.31,2.69,20,6,20 L19,20 C21.76,20,24,17.76,24,15
C24,12.36,21.95,10.22,19.35,10.04 Z M19,18 L6,18 C3.79,18,2,16.21,2,14
S3.79,10,6,10 L6.71,10 C7.37,7.69,9.48,6,12,6 C15.04,6,17.5,8.46,17.5,11.5
L17.5,12 L19,12 C20.66,12,22,13.34,22,15 S20.66,18,19,18 Z" />
    <path
        android:strokeColor="#000000"
        android:strokeWidth="2"
        android:pathData="M6.58994,13.1803 C6.58994,13.1803,8.59173,15.8724,12.011,15.8726
C15.2788,15.8728,17.3696,13.2502,17.3696,13.2502" />
</vector>
  • width和height属性:表示该SVG图形的具体大小。
  • viewportWidth与viewportHeight属性:表示SVG图形划分的比例。具体理解的是,定义了一张SVG图片,它的宽度和高度分别是24dp和24dp。在这里,width和height类似于指定画布的大小,而viewportWidth与viewportHeight则是指将画布的宽、高分为多少个点,而Path中的点坐标都是以viewportWidth与viewportHeight的点数为坐标的,而不是dp值。很明显,vector标签指定的是画布大小,而path标签指定的是路径内容。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

动态Vector

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7052.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android配置Jetpack-Compose环境

Android 配置 Jetpack Compose 环境 记录配置Jetpack Compose环境的一些坑~ 本文同步更新于博客&#xff1a; 链接 直接创建kotlin项目或创建java项目后再配置均可 根目录 build.gradle 配置kotlin环境构建脚本 buildscript {ext.kotlin_version 1.4.32dependencies {clas…

大模型时代,AI模型开源还能这么玩?模型空间内测邀请(含重磅福利)

‍人工智能学习与实训社区飞桨 AI Studio自2019年以来&#xff0c;持续吸纳众多开发者于平台内开源贡献、实训提升&#xff0c;分享项目经验、共享自研模型等。 随着 AI Studio 开发者规模的增长、开发者开发能力的提升&#xff0c;我们收到许多期待与建议&#xff0c;经过一段…

企业OA管理系统需具备哪些功能?

OA也就是办公自动化&#xff0c;是通过将计算机、通信等现代化技术运用到传统办公方式而形成的一种新型办公方式。OA办公管理系统能够更加高效优质的处理办公事务以及进行企业管理业务&#xff0c;实现对资源的高效利用&#xff0c;进而达到提高生产力&#xff0c;提升管理水平…

详解vue各种权限控制与管理的实现思路

一、 菜单权限 菜单权限&#xff1a;控制用户在系统中能够看到哪些菜单项菜单权限指的就是后台系统中的左侧的菜单栏&#xff0c;前端可以根据后端接口返回的权限数据结合element-ui菜单组件循环拼接而成即可&#xff0c;有什么权限就展示什么菜单通过vuex持久化插件(本地存储…

Linux系统【centos7】常用基础命令教程

今天我来介绍一下Linux系统的基础知识。 首先&#xff0c;我们需要了解Linux是什么。Linux是一种免费且开放源代码的操作系统&#xff0c;它被广泛用于服务器、移动设备和嵌入式系统。 接下来&#xff0c;我们需要了解基本的Linux命令。其中一些基本命令包括&#xff1a; 1.…

项目 TO 的自我修养

最近作为项目 TO 在公司内完成了一个涉及面比较广的项目&#xff0c;对于如何推动项目上线有一些经验和大家分享。希望刚毕业几年、没有参与过大型项目的同学&#xff0c;从中能学到一些方法&#xff0c;为今后担任项目主力做一些准备。所谓的 TO&#xff0c;是 Technical Owne…

java和mysql进行排序和排名

目录 一、基于java排序和排名 1、数值相同,排名相同,排名连续 2、数值相同,排名相同,排名不连续 3、数值相同,排名不相同,排名连续 二、基于mysql排序和排名 1、准备一张表 2、插入数据 3、设置临时变量,方便后续查询 4、数值相同,排名相同,排名连续 5、数值相同,排名…

天猫食品饮料数据分析:2月份茶饮料品牌销量TOP10排行榜!

近年来&#xff0c;茶饮料品类逐渐丰富&#xff0c;也在潜移默化中激发消费者的购物欲望&#xff0c;茶饮料行业的整体市场规模也不断增长。 根据鲸参谋电商数据显示&#xff0c;2023年2月份在天猫平台上&#xff0c;茶饮料相关产品的月销量将近149万件&#xff0c;环比增长约…

ADAS-GPS定位原理概述

前言 “GPS传感器在无人机、室外物流车以及诸多机器人应用中经常出现&#xff0c;它们机器人的定位、导航中发挥着重要的作用&#xff0c;而今天的L2&#xff5e;L5级别自动驾驶系统更是离不开它们&#xff0c;今天我们走进它们的世界&#xff0c;探索其背后原理以及本质。” …

MySQL之事务和锁机制

文章目录一、事务1.1 事务特征1.2 隔离级别1.3 开启事务二、锁机制2.1 读锁、写锁2.2 全局锁、表锁、行锁2.3 记录锁、间隙锁、临键锁提示&#xff1a;以下是本篇文章正文内容&#xff0c;MySQL 系列学习将会持续更新 一、事务 在数据库里面&#xff0c;我们希望有些操作能够以…

leaflet实现波动的marker效果(131)

第131个 点击查看专栏目录 本示例的目的是介绍如何在vue+leaflet中显示波动的marker效果。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共76行)安装插件相关API参考:专栏目标示例效果 配置方式 1)查看基础设置…

chatgpt 变现思路

教学 为用户提供ChatGPT的培训课程&#xff0c;教授如何使用和掌握ChatGPT的基本功能和高级技巧。课程可以通过在线平台或实体培训形式进行。 各种设计 ChatGPT可以为设计师提供创意灵感&#xff0c;包括平面设计、UI/UX设计、建筑设计等。此外&#xff0c;它还可以协助设计…

MySQL主从复制之多主多从部署流程—2023.04

文章目录一、多主多从实现架构图二、准备工作三、MySQL多主多从搭建流程1、修改2个主节点配置文件2、修改2个从节点配置文件3、2个主节点相互复制4、2个从节点分别复制主节点5、测试记录&#xff1a;一、多主多从实现架构图 这里是2主2从&#xff0c;下图基本例举出来的实现的…

电脑安装Ubuntu系统(非虚拟机)步骤简述

由于我的笔记本电脑比较古老&#xff08;近10年&#xff09;&#xff0c;已经过了质保期&#xff0c;甚至续保时间都过了&#xff0c;所以本着能用则用的想法就在上面改安装Ubuntu系统。下面简单介绍下安装过程&#xff0c;自己留笔记&#xff0c;如果有碰到同样问题的能参考更…

信息收集之WAF绕过

信息收集之WAF绕过前言一、工具进行目录扫描1. 工具的下载2. 工具的使用二、Python代码进行目录扫描前言 对于web安全无WAF的信息收集&#xff0c;大家可以查看如下链接的文章&#xff1a; web安全之信息收集 对于有WAF信息收集&#xff0c;看如下所示&#xff1a;&#xff08;…

opencv学习(二)图像阈值和平滑处理

图像阈值ret, dst cv2.threshold(src, thresh, maxval, type)src&#xff1a; 输入图&#xff0c;只能输入单通道图像&#xff0c;通常来说为灰度图dst&#xff1a; 输出图thresh&#xff1a; 阈值maxval&#xff1a; 当像素值超过了阈值&#xff08;或者小于阈值&#xff0c;…

(数字图像处理MATLAB+Python)第四章图像正交变换-第一节:离散傅里叶变换

文章目录一&#xff1a;一维离散傅里叶变换&#xff08;1&#xff09;定义&#xff08;2&#xff09;实例二&#xff1a;一维快速傅里叶变换&#xff08;1&#xff09;定义&#xff08;2&#xff09;实例三&#xff1a;二维离散傅里叶变换&#xff08;1&#xff09;定义&#x…

Python入门教程+项目实战-7.4节: 程序实战-计算次大值

目录 7.2.1 计算四个中的次大值 7.2.2 使用循环计算次小值 7.2.3 系统学习python 7.2.1 计算四个中的次大值 假设有四个整型变量&#xff0c;该怎么计算四个中的次大值&#xff1f; 初学者解出这道题并不困难&#xff0c;但是将代码写得简洁优雅却是一个不小的挑战。 直接通…

aspnet016计算机组成原理精品课程shfw程序

2网站项目范围 计算机组成原理精品课程系统从两种用户角度进行功能划分。 1、学生部分&#xff1a; 1.1&#xff1a;新闻查看&#xff1b; 1.2&#xff1a;课程公告查看&#xff1b; 1.3&#xff1a;用户注册&#xff1b; 1.4&#xff1a;在线留言&#xff1b; 1.5&#xf…

Spring Boot 配置文件配置自动提示 Configuration Processor

效果 在使用Idea等开发工具时&#xff0c;配置文件中输入前缀就有对应的补全提示&#xff0c;使开发者可以很方便配置相应属性&#xff0c;效果截图如下&#xff1a; 元数据说明 这些提示来自于 spring 自动配置规范中的源数据文件 spring-configuration-metadata.json 和 ad…