在Android实现光影移动效果【流光效果】

2024-02-06 01:36

本文主要是介绍在Android实现光影移动效果【流光效果】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

说明

本文是在Android实现光影移动效果【流光效果】

效果如下

图1 ShimmerView
图2 ShimmerTextView

ShimmerView.kt


import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Point
import android.graphics.RectF
import android.graphics.Shader
import android.util.AttributeSet
import android.view.View
import android.view.animation.LinearInterpolatorclass ShimmerView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {private var mWidth = -1private var mSlope: Float = -1Fprivate var mAnimMode = 0private var mDuration = 1600Lprivate var mRepeatCount = 0private var mColors = intArrayOf(0x00FFFFFF, 0x5AFFFFFF, 0x5AFFFFFF, 0x00FFFFFF)private var mPositions = floatArrayOf(0f, 0.5f, 0.51f, 1f)private var mRadius = 0private var mPaint: Paint = Paint()private var mPath: Path? = nullprivate var mClipPath: Path? = nullprivate var mValueAnimator: ValueAnimator? = nullinit {attrs?.let {context.obtainStyledAttributes(attrs, R.styleable.ShimmerView).apply {try {mWidth = getDimensionPixelSize(R.styleable.ShimmerView_csWidth, mWidth)mSlope = getFloat(R.styleable.ShimmerView_csSlope, mSlope)mRadius = getDimensionPixelSize(R.styleable.ShimmerView_csRadius, mRadius)mAnimMode = getInt(R.styleable.ShimmerView_csAnimMode, mAnimMode)mDuration =getInt(R.styleable.ShimmerView_csDuration, mDuration.toInt()).toLong()mRepeatCount = getInt(R.styleable.ShimmerView_csRepeat, mRepeatCount)val colorsStr = getString(R.styleable.ShimmerView_csColors)val positionsStr = getString(R.styleable.ShimmerView_csPositions)if (!colorsStr.isNullOrBlank() && !positionsStr.isNullOrBlank()) {val colorArr =colorsStr.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()val positionArr =positionsStr.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()val size = colorArr.sizeif (size == positionArr.size) {mColors = IntArray(size)mPositions = FloatArray(size)for (i in 0 until size) {mColors[i] = Color.parseColor(colorArr[i])mPositions[i] = positionArr[i].toFloat()}}}} finally {recycle()}}}}public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)val widthSize = MeasureSpec.getSize(widthMeasureSpec)val heightSize = MeasureSpec.getSize(heightMeasureSpec)initSetup(widthSize, heightSize)if (mAnimMode == 0) {showAnimation(widthSize, heightSize, mRepeatCount, mDuration)}}private fun initSetup(width: Int, height: Int) {if (mRepeatCount < 0) {mRepeatCount = -1}if (mWidth < 0) {mWidth = width / 3}if (mSlope < 0) {mSlope = height / width.toFloat()}val point1 = Point(0, 0)val point2 = Point(width, 0)val point3 = Point(width, height)val point4 = Point(0, height)mPath = Path()mPath?.moveTo(point1.x.toFloat(), point1.y.toFloat())mPath?.lineTo(point2.x.toFloat(), point2.y.toFloat())mPath?.lineTo(point3.x.toFloat(), point3.y.toFloat())mPath?.lineTo(point4.x.toFloat(), point4.y.toFloat())mPath?.close()mClipPath = Path()val mRect = RectF()mRect[0f, 0f, width.toFloat()] = height.toFloat()mClipPath?.addRoundRect(mRect, mRadius.toFloat(), mRadius.toFloat(), Path.Direction.CW)}public override fun onDraw(canvas: Canvas) {super.onDraw(canvas)//绘制圆角mClipPath?.let { canvas.clipPath(it) }//绘制流光mPath?.let { canvas.drawPath(it, mPaint) }}private fun showAnimation(width: Int, height: Int, repeatCount: Int, duration: Long) {val offset = mWidth.toFloat()mValueAnimator?.cancel()mValueAnimator = ValueAnimator.ofFloat(0f - offset * 2, width + offset * 2)mValueAnimator?.repeatCount = repeatCountmValueAnimator?.interpolator = LinearInterpolator()mValueAnimator?.duration = durationmValueAnimator?.addUpdateListener { animation: ValueAnimator ->val value = animation.animatedValue as FloatmPaint.shader = LinearGradient(value,mSlope * value,value + offset,mSlope * (value + offset),mColors,mPositions,Shader.TileMode.CLAMP)invalidate()}mValueAnimator?.start()}public override fun onDetachedFromWindow() {super.onDetachedFromWindow()mValueAnimator?.cancel()mValueAnimator = null}fun setColorAndPositions(colors: IntArray, positions: FloatArray) {if (colors.size != positions.size) {throw RuntimeException("colors&positions的Array.size必须一致")}this.mColors = colorsthis.mPositions = positions}fun setSlope(mSlope: Float) {this.mSlope = mSlope}fun setWidth(mWidth: Int) {this.mWidth = mWidth}fun startLightingAnimation(duration: Long = mDuration, repeatCount: Int = mRepeatCount) {showAnimation(width, height, repeatCount, duration)}}

ShimmerView定义的 attrs:

<declare-styleable name="ShimmerView"><!--自动还是手动--><attr name="csAnimMode" format="enum"><enum name="auto" value="0" /><enum name="manual" value="1" /></attr><!--光影宽度--><attr name="csWidth" format="dimension" /><!--光影斜率 范围【-1 ~ 1--><attr name="csSlope" format="float" /><!--控件的圆角大小--><attr name="csRadius" format="dimension" /><!-- -1:无限循环,0:其他代表重复执行几次--><attr name="csRepeat" format="integer" /><!--动画时长 单位ms--><attr name="csDuration" format="integer" /><!--颜色值 举例:{0x00FFFFFF, 0x88FFFFFF, 0x00FFFFFF}--><attr name="csColors" format="string" /><!--颜色值对应的位置数组  (值范围0~1) 举例:[0f,0.5f,1f]  与csAngle数组大小必须一致--><attr name="csPositions" format="string" /></declare-styleable>

ShimmerTextView.kt


import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Shader
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextViewclass ShimmerTextView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {private var mLinearGradient: LinearGradient? = nullprivate var mGradientMatrix: Matrix? = nullprivate var mViewWidth = 0private var mTranslate = 0private var mAnimating = trueprivate val speed = 50private var mPaint: Paint? = nullprivate var textColor = 0private var shimmerColor = 0init {attrs?.let {context.obtainStyledAttributes(attrs, R.styleable.ShimmerTextView).apply {try {textColor = getColor(R.styleable.ShimmerTextView_stvTextColor, Color.BLACK)shimmerColor =getColor(R.styleable.ShimmerTextView_stvShimmerColor, Color.WHITE)mPaint = paintmGradientMatrix = Matrix()} finally {recycle()}}}}fun setShimmer(isShimmer: Boolean) {mAnimating = isShimmer}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)mViewWidth = measuredWidth}fun initLinearGradient() {mLinearGradient = LinearGradient(0f,0f,mViewWidth.toFloat(),0f,intArrayOf(textColor, shimmerColor, textColor),null,Shader.TileMode.CLAMP)mPaint?.shader = mLinearGradient}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)if (mAnimating) {if (mGradientMatrix != null && mLinearGradient != null) {mTranslate += mViewWidth / 10if (mTranslate > 2 * mViewWidth) {mTranslate = -mViewWidth}mGradientMatrix?.setTranslate(mTranslate.toFloat(), 0f)mLinearGradient?.setLocalMatrix(mGradientMatrix)} else {initLinearGradient()}postInvalidateDelayed(speed.toLong())}}
}

ShimmerTextView 定义的 attrs:

    <declare-styleable name="ShimmerTextView"><attr name="stvTextColor" format="color" /><attr name="stvShimmerColor" format="color" /></declare-styleable>

DEMO

  1. Demo.apk 点击下载

项目和演示效果可以去Github查看

项目地址: https://github.com/logan0817/shinningview 。

如果你有任何疑问可以留言。

如果这篇文章对你有帮助,可以赏个赞支持一下作者。

这篇关于在Android实现光影移动效果【流光效果】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/682791

相关文章

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

pytorch自动求梯度autograd的实现

《pytorch自动求梯度autograd的实现》autograd是一个自动微分引擎,它可以自动计算张量的梯度,本文主要介绍了pytorch自动求梯度autograd的实现,具有一定的参考价值,感兴趣... autograd是pytorch构建神经网络的核心。在 PyTorch 中,结合以下代码例子,当你

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient