Android Shimmer学习

来源:互联网 发布:javascript 现状 编辑:程序博客网 时间:2024/05/29 19:00

Android Shimmer学习

Shimmer

Facebook在Android上实现了Shimmer的效果,如上图,可以针对所有的View,地址:http://facebook.github.io/shimmer-android/

我就学习一下该如何制作出类似的简易效果,现实的核心部分是使用线性渐变LinearGradient,然后在绘图的时候不断将渐变平移来达到效果。


LinearGradient

根据开发者文档,有两种构造方法:

Public constructors
LinearGradient(float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile)
LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)

首先来看看几个共同的属性:

  • x0, y0 渐变线起点的x,y坐标
  • x1, y1 渐变线终点的x,y坐标
  • tile Shader.TileMode 平铺模式

前两个都很好理解,平铺模式又是什么呢?根据开发者文档,有三种平铺模式:

  1. CLAMP 如果着色器渲染越过了原始的边界,复制边缘的颜色渲染
  2. MIRROR 垂直和水平地重复着色器图片,交替复制的镜像图片以保证相邻的图片总是能够接上
  3. REPEAT 垂直和水平地重复着色器图片

从上面的三行话中已经透露出了一个很关键的东西,渐变也是一个着色器,在来看开发者文档,也标明了这一点,这也是之后的平移过程的基础。

更多关于Shader着色器的知识可以参考博文:http://blog.csdn.net/iispring/article/details/50500106

再来看看两个构造函数不同的地方主要是颜色的决定,第一个函数使用的是一个数组并配上位置来决定颜色所在的位置,第二个函数则简单粗暴地多,设置起点和终点的位置即可。这里需要注意一点,对于第一个函数中的位置参数可以为null,如果设置为null的话,颜色会均匀分布在渐变线上。

现在一切准备就绪,所以根据效果,我们可以构造出一个LinearGradient

mLinearGradient = new LinearGradient(-mViewWidth, 0, 0, 0,                        new int[] { 0x33ffffff, 0xffffffff, 0x33ffffff },                        new float[] { 0, 0.5f, 1 }, Shader.TileMode.CLAMP);

可以看出我们构建了一个和View一样长的渐变,而位置就在View的左侧紧贴着,我们接下来需要做的就是将这个渐变从左侧慢慢平移到右侧,这样就能达到闪动的效果。(需要自定义颜色的在此处修改)

那该如何平移这个渐变呢?需要使用到属性动画了

平移

可能很多人都已经学过了安卓中的动画,但这里着色器的平移有一些不同,它是使用矩阵来进行移动,通过查阅开发者文档,我们可以知道有这么一个函数 setLocalMatrix 可以用来设置着色器的矩阵。所以我们还需要一个矩阵来控制着色器的位置。(注意是使用android.graphics.Matrix)

mGradientMatrix = new Matrix();  

在本例中我是每次移动宽度的1/10,如果平移完了再回到左侧重新平移

 mTranslate += mViewWidth / 10;   if (mTranslate > 2 * mViewWidth) {       mTranslate = 0;   }  

然后给矩形赋值然后将着色器平移

mGradientMatrix.setTranslate(mTranslate, 0);  mLinearGradient.setLocalMatrix(mGradientMatrix);  postInvalidateDelayed(50);  

由于是个安卓新手,本着凡是不懂得就去查查文档,我在这里卡了很久,setTranslate 到底是怎样的运作方式,是控制平移量还是直接控制位置,经过实验后我发现该函数所做的操作都是在原位置上进行平移,左负右正,它做完平移后,不会改变原位置,虽然在视觉上现位置已经有了改变,所以我们需要在每一次都递增mTranslate变量。postInvalidateDelay里设置每一帧绘制的时间,也就是控制闪动的快慢。

综上

有了着色器应该如何使用上呢?这里就需要提到一个Paint类,它来决定如何绘制,习惯称为“画笔”,这个就很生动了,我们换了画笔,那画出来的东西就是我们想要的。

mPaint.setShader(mLinearGradient);

因为我们是继承一个TextView来进行操作,之前也一直在用到View的宽度,这个我们应该在哪里获取?答案就是 onSizeChanged这个回调函数,我们在这里完成大部分的初始化功能。所以这个自定View代码如下:

public class MyTextView extends TextView {    private LinearGradient mLinearGradient;    private Matrix mGradientMatrix;    private Paint mPaint;    private int mViewWidth = 0;    private int mTranslate = 0;    private boolean mAnimating = true;    public MyTextView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        if (mViewWidth == 0) {            mViewWidth = getMeasuredWidth();            if (mViewWidth > 0) {                mPaint = getPaint();                mLinearGradient = new LinearGradient(-mViewWidth, 0, 0, 0,                        new int[] { 0x33ffffff, 0xffffffff, 0x33ffffff },                        new float[] { 0, 0.5f, 1 }, Shader.TileMode.CLAMP);                mPaint.setShader(mLinearGradient);                mGradientMatrix = new Matrix();            }        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if (mAnimating && mGradientMatrix != null) {            mTranslate += mViewWidth / 10;            if (mTranslate > 2 * mViewWidth) {                mTranslate = 0;            }            mGradientMatrix.setTranslate(mTranslate, 0);            mLinearGradient.setLocalMatrix(mGradientMatrix);            postInvalidateDelayed(80);        }    }}
0 0
原创粉丝点击