Android实现流光和光影移动效果代码
作者:红尘、困住我年少 发布时间:2023-09-24 23:57:55
标签:Android,流光,光影
概述:
开发过程中,看到有些界面用到一道光线在屏幕中掠过的效果,觉得挺炫的。所以查找相关资料自己实现了一遍。
先上个预览图:
实现思路:
简单来说就是在一个view中绘制好一道光影,并不断改变光影在view中的位置。
1.首先我们先了解一下光影怎么绘制
在了解如何绘制之前,我们先看一下LinearGradient的构造方法
/**
* Create a shader that draws a linear gradient along a line.
*
* @param x0 The x-coordinate for the start of the gradient line
* @param y0 The y-coordinate for the start of the gradient line
* @param x1 The x-coordinate for the end of the gradient line
* @param y1 The y-coordinate for the end of the gradient line
* @param colors The sRGB colors to be distributed along the gradient line
* @param positions May be null. The relative positions [0..1] of
* each corresponding color in the colors array. If this is null,
* the the colors are distributed evenly along the gradient line.
* @param tile The Shader tiling mode
*
*
* 翻译过来:
* x0,y0为渐变起点,x1,y1为渐变的终点
*
* colors数组为两点间的渐变颜色值,positions数组取值范围是0~1
* 传入的colors[]长度和positions[]长度必须相等,一一对应关系,否则报错
* position传入null则代表colors均衡分布
*
* tile有三种模式
* Shader.TileMode.CLAMP: 边缘拉伸模式,它会拉伸边缘的一个像素来填充其他区域
* Shader.TileMode.MIRROR: 镜像模式,通过镜像变化来填充其他区域
* Shader.TileMode.REPEAT:重复模式,通过复制来填充其他区域
*/
LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int[] colors,
@Nullable float[] positions, @NonNull TileMode tile)
colors[]和positions[]的说明结合下图,这样理解起来应该就比较明朗了
回到正题,如何绘制光影。我们看到的那道光可以参照下图:
根据分析得到我们的着色器是线性着色器(其他着色器请查询相关api):
LinearGradient(a的x坐标, a的y坐标, c的x坐标, c的y坐标, new int[]{Color.parseColor("#00FFFFFF"), Color.parseColor("#FFFFFFFF"), Color.parseColor("#00FFFFFF")}, new float[]{0f, 0.5f, 1f}, Shader.TileMode.CLAMP)
2.给画笔上色。设置着色器mPaint.setShader(mLinearGradient)
3.给定一个数值范围利用数值生成器ValueAnimator产生数值,监听数值变化。每次回调都将该数值传入光影的起点和终点并进行绘制
代码如下:
/**
* author: caoyb
* created on: 2021/12/20 15:13
* description:
*/
public class ConfigLoadingView extends View {
private Paint mPaint;
private Path mPath;
private LinearGradient mLinearGradient;
private ValueAnimator mValueAnimator;
public ConfigLoadingView(Context context) {
this(context, null);
}
public ConfigLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ConfigLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint();
mPath = new Path();
}
private void initPointAndAnimator(int w, int h) {
Point point1 = new Point(0, 0);
Point point2 = new Point(w, 0);
Point point3 = new Point(w, h);
Point point4 = new Point(0, h);
mPath.moveTo(point1.x, point1.y);
mPath.lineTo(point2.x, point2.y);
mPath.lineTo(point3.x, point3.y);
mPath.lineTo(point4.x, point4.y);
mPath.close();
// 斜率k
float k = 1f * h / w;
// 偏移
float offset = 1f * w / 2;
// 0f - offset * 2 为数值左边界(屏幕外左侧), w + offset * 2为数值右边界(屏幕外右侧)
// 目的是使光影走完一遍,加一些时间缓冲,不至于每次光影移动的间隔都那么急促
mValueAnimator = ValueAnimator.ofFloat(0f - offset * 2, w + offset * 2);
mValueAnimator.setRepeatCount(-1);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.setDuration(1500);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mLinearGradient = new LinearGradient(value, k * value, value + offset, k * (value + offset),
new int[]{Color.parseColor("#00FFFFFF"), Color.parseColor("#1AFFFFFF"), Color.parseColor("#00FFFFFF")}, null, Shader.TileMode.CLAMP);
mPaint.setShader(mLinearGradient);
invalidate();
}
});
mValueAnimator.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
initPointAndAnimator(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath, mPaint);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mValueAnimator.cancel();
}
}
注意点:
LinearGradient里参数之一:
color[]参数只能是16进制的RGB数值,不能传R.color.xxx。R.color.xxx虽然是int型,但拿到的是资源ID,并不是16进制RGB
来源:https://blog.csdn.net/weixin_44270195/article/details/122069448
0
投稿
猜你喜欢
- TubeMQ总体介绍TubeMQ是腾讯大数据在2013年开始研发的分布式消息中间件系统(MQ),专注服务大数据场景下海量数据的高性能存储和传
- 1、修改application.properties新建 Mapper、实体类 相应的文件夹,将不同数据源的文件保存到对应的文件夹下# te
- 图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-edit
- 在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的:责任链模式是一种对象的行为
- 本文主要介绍Java Date 日期类型,以及Calendar的怎么获取时间,然后写成时间工具类里面有下面这些方法:- 时间转字符串(有默认
- 目录:DioManager:Dio辅助类NWMethod:请求方法,get、post等NWApi:大家都知道EntityFactory:js
- json格式的字符串与对象的互相转换Jackson 简介Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转
- 简介本文用示例介绍SpringBoot如何解决雪花算法主键ID传到前端后精度丢失问题。问题描述Java后端Long类型的范围-2^63~2^
- 写本文章的目的是为了记录工作中遇到的问题,方便以后遇到可以迅速解决问题我使用的NPOI版本是2.2.1.0版本需要用到的命名空间using
- 本文实例为大家分享了Android实现简单计时器的具体代码,供大家参考,具体内容如下布局在res/layout 下进行布局<?xml
- Android部分手机会有虚拟按键,而没有实体按键,例如华为系列的手机。然而在开发过程中,有时候会涉及底部视图的开发,最终的结果却因为虚拟按
- 为了是java中的对象便于理解,我们可以使用一款比较好用的数据格式,在数据解析的时候也会经常用到,它就是JSON。在这里我们转换对象和字符串
- 看了网上关于记事本的查找替换很多,但都没有达到我想要的结果,然后自己学习总结了以下的方法:统计字符串(汉字,字母,数字,字符)先上效果图定义
- Collectors.toMap空指针问题在工作中遇到了一个List转Map的时候的一个NullPointException.情形很简单,问
- 什么是RecyclerView关于RecyclerView,是一个主要用于展示和回收View的有一个控件,在官用了一句话来概括Recycle
- 在Android开发中,我们经常会需要在Android界面上弹出一些对话框,比如询问用户或者让用户选择。这些功能我们叫它Android Di
- //方法一//须添加对System.Web的引用//using System.Web.Security;/// <summary>
- 问题是这样的,我用eclipse发送httpclient请求如下没有问题,但是在idea中就返回400,为毛呢???excuse me?pa
- 智能终端上的游戏目前风头正劲,试问哪个智能手机上没有几款企鹅公司出品的游戏呢!之前从未涉猎过游戏开发,但知道游戏开发前要挑选一款合适的游戏引
- Spring Boot如何实现配置文件的自动加载和刷新?在使用Spring Boot开发应用程序时,配置文件是非常重要的组成部分。在不同的环