TextView波浪加载效果
2015-12-19 21:52
260 查看
开源框架:https://github.com/RomainPiel/Titanic
效果图:
实现原理:
1.构造一个BitmapShader,通过水平方向上重复排列一张波浪图片使其衔接成一张能水平方向能覆盖整个控件的波浪图片:
(右键查看图像可看到)该图是一个200*300的颜色,上半部分透明色,下半部分灰白色。用上图在水平方向上衔接成一个能覆盖整个控件的波浪图片。
2.给当前TextView的Paint设置该BitmapShader,此时用这个Paint绘制出来的文字就是基于这个BitmapShader绘制的。举个形象一点的例子比喻BitmapShader在这里的作用,桌子上有一幅画(BitmapShader),然后用一层沙子将其完全盖住了(这个沙子就是控件TextView),然后绘制文字的时候相当于你在上面用手在沙子上写一个”Hello Word”,然后这幅画就在你写Hello World的一横一竖的地方部分显示出来了,相当于擦出了部分沙子,显示出了部分图像。
3.然后就是通过重复的属性动画在x方向和y方向去平移BitmapShader达到波浪的效果,就好像桌子上的图像不断的移动一样,当然超出控件的部分就不显示。x方向上做平移运动,y方向上反复的做上下运动。注意:X方向上的图片是通过连接衔接上去的,所以x方向上一次动画的具体必须是图像宽度的整数倍,以保证动画平滑。因为动画一次执行完成之后又是回到圆点重新执行。
我们按照上面步骤分析源码:
第一步:自定义TitanicTextView继承TextView新建createShader()方法
这个函数的作用就是如其名,创建一个BitmapShader。
中间有几行代码:
意思是将b填充成当前字体颜色,然后将wave图片覆盖到这个画布上,这个时候得到b就是一个上部分是字体颜色,下部分是wave原来的颜色
是通过一个wave.png图片,x方向上重复的衔接,y方向上重复边缘颜色
第二步:设置画笔
给当前画笔设置BitmapShader,其实这两步也就是一步。
第三步:通过属性动画不断的invalidate()重绘。
这里是用过自定义maskX,maskY实现齐get和set方法,通过属性动画不断的调用maskX和maskY的set方法,然后在set方法里面调用invalidate进行重绘。maskX, maskY最终会换算成x方向和y方向的平移运动。
第四步:在onDraw方法里面实现重绘
重要的代码就两行:
乘以一个平移矩阵实现平移.下面给一张带有生成BitmapShader的图。
BitmapShader是基于左上角那副图片生成的,上部分是跟字体一样的颜色,下面部分是白色,整个过程其实都是在平移左上角这张图片,而且只有文字覆盖的地方的图片内容才会显示出来,这也是BitmapShader的作用,以实现波浪效果。
效果图:
实现原理:
1.构造一个BitmapShader,通过水平方向上重复排列一张波浪图片使其衔接成一张能水平方向能覆盖整个控件的波浪图片:
(右键查看图像可看到)该图是一个200*300的颜色,上半部分透明色,下半部分灰白色。用上图在水平方向上衔接成一个能覆盖整个控件的波浪图片。
2.给当前TextView的Paint设置该BitmapShader,此时用这个Paint绘制出来的文字就是基于这个BitmapShader绘制的。举个形象一点的例子比喻BitmapShader在这里的作用,桌子上有一幅画(BitmapShader),然后用一层沙子将其完全盖住了(这个沙子就是控件TextView),然后绘制文字的时候相当于你在上面用手在沙子上写一个”Hello Word”,然后这幅画就在你写Hello World的一横一竖的地方部分显示出来了,相当于擦出了部分沙子,显示出了部分图像。
3.然后就是通过重复的属性动画在x方向和y方向去平移BitmapShader达到波浪的效果,就好像桌子上的图像不断的移动一样,当然超出控件的部分就不显示。x方向上做平移运动,y方向上反复的做上下运动。注意:X方向上的图片是通过连接衔接上去的,所以x方向上一次动画的具体必须是图像宽度的整数倍,以保证动画平滑。因为动画一次执行完成之后又是回到圆点重新执行。
我们按照上面步骤分析源码:
第一步:自定义TitanicTextView继承TextView新建createShader()方法
private void createShader() { if (wave == null) { wave = getResources().getDrawable(R.drawable.wave); } int waveW = wave.getIntrinsicWidth(); int waveH = wave.getIntrinsicHeight(); final Bitmap b = Bitmap.createBitmap(waveW, waveH, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); c.drawColor(getCurrentTextColor()); wave.setBounds(0, 0, waveW, waveH); wave.draw(c); shader = new BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); getPaint().setShader(shader); offsetY = (getHeight() - waveH) / 2; }
这个函数的作用就是如其名,创建一个BitmapShader。
中间有几行代码:
Canvas c = new Canvas(b); c.drawColor(getCurrentTextColor()); wave.setBounds(0, 0, waveW, waveH); wave.draw(c);
意思是将b填充成当前字体颜色,然后将wave图片覆盖到这个画布上,这个时候得到b就是一个上部分是字体颜色,下部分是wave原来的颜色
shader = new BitmapShader(b,Shader.TileMode.REPEAT,Shader.TileMode.CLAMP);
是通过一个wave.png图片,x方向上重复的衔接,y方向上重复边缘颜色
第二步:设置画笔
getPaint().setShader(shader);
给当前画笔设置BitmapShader,其实这两步也就是一步。
第三步:通过属性动画不断的invalidate()重绘。
final Runnable animate = new Runnable() { @SuppressLint("NewApi") @Override public void run() { textView.setSinking(true); // horizontal animation. 200 = wave.png width 一定要是图片的宽度 ObjectAnimator maskXAnimator = ObjectAnimator.ofFloat(textView, "maskX", 0, 400*4); maskXAnimator.setRepeatCount(ValueAnimator.INFINITE); maskXAnimator.setDuration(1000*4); maskXAnimator.setStartDelay(0); int h = textView.getHeight(); // vertical animation // maskY = 0 -> wave vertically centered // repeat mode REVERSE to go back and forth ObjectAnimator maskYAnimator = ObjectAnimator.ofFloat(textView, "maskY", h / 2, -h / 2); maskYAnimator.setRepeatCount(ValueAnimator.INFINITE); maskYAnimator.setRepeatMode(ValueAnimator.REVERSE); maskYAnimator.setDuration(8000); maskYAnimator.setStartDelay(0); // now play both animations together animatorSet = new AnimatorSet(); animatorSet.playTogether(maskXAnimator, maskYAnimator); animatorSet.setInterpolator(new LinearInterpolator()); animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { textView.setSinking(false); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { textView.postInvalidate(); } else { textView.postInvalidateOnAnimation(); } animatorSet = null; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); animatorSet.start(); } }; // 如果没有布局好 if (!textView.isSetUp()) { textView.setAnimationSetupCallback(new TitanicTextView.AnimationSetupCallback() { @Override public void onSetupAnimation(final TitanicTextView target) { animate.run(); } }); } else { animate.run(); }
这里是用过自定义maskX,maskY实现齐get和set方法,通过属性动画不断的调用maskX和maskY的set方法,然后在set方法里面调用invalidate进行重绘。maskX, maskY最终会换算成x方向和y方向的平移运动。
第四步:在onDraw方法里面实现重绘
// modify text paint shader according to sinking state if (sinking && shader != null) { // first call after sinking, assign it to our paint if (getPaint().getShader() == null) { getPaint().setShader(shader); } // translate shader accordingly to maskX maskY positions // maskY is affected by the offset to vertically center the wave shaderMatrix.setTranslate(maskX, maskY + offsetY); // assign matrix to invalidate the shader shader.setLocalMatrix(shaderMatrix); } else { getPaint().setShader(null); }
重要的代码就两行:
shaderMatrix.setTranslate(maskX, maskY + offsetY); // assign matrix to invalidate the shader shader.setLocalMatrix(shaderMatrix);
乘以一个平移矩阵实现平移.下面给一张带有生成BitmapShader的图。
BitmapShader是基于左上角那副图片生成的,上部分是跟字体一样的颜色,下面部分是白色,整个过程其实都是在平移左上角这张图片,而且只有文字覆盖的地方的图片内容才会显示出来,这也是BitmapShader的作用,以实现波浪效果。
相关文章推荐
- 【J】BaseAdapter的使用与优化
- 事务的并发控制big picture
- 一些想说的话,无关技术
- win7旗舰版(64位)环境下oracle11g的安装方法
- Office Visio简介
- MFC 填充系统 方法记录
- c++静态成员与静态函数
- putty 如何退出鼠标选中状态
- hdoj--1312--Red and Black(dfs)
- 开发该选择Blocks还是Delegates
- hdoj--1312--Red and Black(dfs)
- ASP.NET页面周期
- LeetCode-2-Add Two Numbers(链表)-Medium
- 每天一个Linux之ls命令
- 关于商城购物车的总结---删除功能
- 枚举和结构的学习
- Oracle问题记录(一)
- c++基础语法 构造函数 析构函数 类的组合
- 推荐书籍
- rails use devise