日拱一卒, 功不唐捐
一, 背景
这个特效来源于有一天逛网站的时候, 一家网站实现了这样的一个效果: 在你向下滚动页面的时候, 他的背景的图片随着你的滑动, 以窗口的方式展示着图片的某一部分. 浏览完就想着以 Android 的方式能不能实现, 也就演变成了以下的效果.
Telescope
二, 知识点 BitmapShader
[官方] Shader 用于绘制位图作为纹理. 位图可以设置模式为重复或镜像或平铺.
简单来说, Shader 可以用来实现一些渐变, 反转, 镜像, 重复等效果. 本文的效果核心使用的是 Shader 中的 BitmapShader-- 位图 Shader.
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
从构造方法可以看出, 第一个参数为位图 bitmap, 第二个和第三个参数分别为横方向和纵方向的平铺模式.
平铺模式有如下几种模式:
CLAMP : 拉伸, 水平拉伸图片左右方向最后一个像素,, 垂直拉伸图片上下方向的最后一个像素.
MIRROR: 镜像, 水平和垂直方向重复图像, 交替镜像, 使相邻的图像始终相连.
REPEAT: 重复, 水平和垂直方向不断重复图片.
三, 基本思路
1, 创建一张图片, 将画笔设置为带有图像填充功能;
2, 根据获取手指所点击位置的坐标, 根据获得的坐标绘制圆形或者其他图形.
四, 实现
从上述基本思路来看, 步骤还是很简单, 那么接下来分析实现的代码.
- mPaint = new Paint();
- mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.photo2);
首先就是初始化画笔和创建一张位图. 接下来为核心内容.
- mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
- canvas.drawCircle(400,400,300,mPaint);
BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)新创建一个 BitmapShader, 并将水平和垂直方向的平铺模式设置为 CLAMP 拉伸模式, 将 BitmapShader 属性设置给画笔, 使画笔具有图像填充功能, 这是后面画笔可以绘制出一个带有图片的圆形的原因. 接着利用 Canvas 在坐标 (400,400) 处绘制出一个半径为 300 的圆形.
目前基本的绘制已经结束, 运行代码可以看出会有圆形图片在界面显示, 如下图:
Paint.jpeg
从上面的图片来看, 是不是发现其实这就是一个圆形的头像, 到这里我们可以想到前面有一篇 Android 自定义菱形图片使用 PorterDuffXfermode 的相关属性绘制菱形的头像, 其实这里我们也可以使用 BitmapShader 进行操作, 代码相比较更加简洁.
目前实现的是静态的图像, 接下来实现随着手指动态移动的效果.
- private float mTouchEventY = -1;
- private float mTouchEventX = -1;
- ......
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mTouchEventX = event.getX();
- mTouchEventY = event.getY();
- return true;
- case MotionEvent.ACTION_MOVE:
- mTouchEventX = event.getX();
- mTouchEventY = event.getY();
- postInvalidate();
- break;
- }
- postInvalidate();
- return super.onTouchEvent(event);
- }
首先我们创建两个全局变量 mTouchEventX,mTouchEventY. 在 onTouchEvent 事件中, 手指 MotionEvent.ACTION_DOWN 的时候, 动态获取手指的位置, 在 ACTION_DOWN 的代码中记得 return true, 这涉及到事件的分发机制, 当 return false 时, 代表手指的 down 事件未完成, 那么事件将不会继续向下传递, 也就是说 ACTION_DOWN 动作后的 ACTION_MOVE 是不会触发的.
同样的, 我们在 MotionEvent.ACTION_MOVE 中也动态获取手指的位置, 也就是随着手指动态调整圆形的位置.
最后在 Canvas 绘制圆形的时候, 将获取到的位置设置进去, 随着手指的不断移动, 不断获取到位置值, 也就实现了动态绘制图像的效果.
canvas.drawCircle(mTouchEventX,mTouchEventY,300,mPaint);
五, 最后
在上述的过程中, 发现 BitmapShader 可以很容易的实现不规则头像. 另外, 上述也只使用了 BitmapShader 的拉伸模式, 还有镜像和重复模式可以实现更多的特效, 有待发掘.
文章同步个人博客: https://fuusy.github.io/
项目地址: https://github.com/fuusy/ShaderTelescope.git
公众号: 小猿说
小猿说. jpg
来源: http://www.jianshu.com/p/076c3755ee71