Android 自定义 View _ 扭曲动效,android开发环境搭建教程
Posted m0_64383081
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 自定义 View _ 扭曲动效,android开发环境搭建教程相关的知识,希望对你有一定的参考价值。
drawBitmapMesh(Bitmap bitmap,
int meshWidth,
int meshHeight,
float[] verts,
int vertOffset,
int[] colors,int colorffset,Paint paint)
这个方法可以对bitmap进行扭曲,部分参数说明如下:
- bitmap 需要扭曲的源位图
- meshWidth 控制在横向上把该源位图划成成多少格
- meshHeight 控制在纵向上把该源位图划成成多少格
- verts 长度为(meshWidth + 1) * (meshHeight + 1) * 2的数组,它记录了扭曲后的位图各顶点位置
- vertOffset 控制verts数组中从第几个数组元素开始才对bitmap进行扭曲
3. drawBitmapMesh简单示例
- 根据参数的含义,我们先初始化这些参数:
//将图像分成多少格
private int carBodyWidthPart = 4;
private int carBodyHeightPart = 4;
//交点坐标的个数
private int carBodyPartCount = (carBodyWidthPart + 1) * (carBodyHeightPart + 1);
//用于保存COUNT的坐标
//x0, y0, x1, y1…
private float[] carBodyNewsPos = new float[carBodyPartCount * 2];
private float[] carBodyOrigPos = new float[carBodyPartCount * 2];
/**
- 得到网格点集合
- @param bitmap bitmap
- @param heightPart 纵向分割的份数
- @param widthPart 横向分割的份数
- @param newPos 新点集合
- @param origPos 原始点集合
*/
protected void getBitmapMeshPoints(Bitmap bitmap, int heightPart, int widthPart, float[] newPos, float[] origPos)
//初始化网格点
int index = 0;
float bmWidth = bitmap.getWidth();
float bmHei
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
ght = bitmap.getHeight();
for (int i = 0; i < heightPart + 1; i++)
float fy = bmHeight * i / heightPart;
for (int j = 0; j < widthPart + 1; j++)
float fx = bmWidth * j / widthPart;
//X轴坐标 放在偶数位
newPos[index * 2] = fx;
origPos[index * 2] = newPos[index * 2];
//Y轴坐标 放在奇数位
newPos[index * 2 + 1] = fy;
origPos[index * 2 + 1] = newPos[index * 2 + 1];
index += 1;
- 这里我把初始化数组写成了一个函数,注意的是,数组按照第一个点的x1,y1,然后第二个点的x2,y2,这样的顺序存储。我们先把图给画出来看看效果,我们把这些点集也画出来:
/**
-
绘制网格点
-
@param canvas canvas
-
@param pos 点集
-
@param paint 画笔
/
protected void drawPoint(Canvas canvas, float[] pos, Paint paint)
for (int i = 0; i < pos.length/2; i++)
int x = i2;
int y = x + 1;
canvas.drawPoint(pos[x], pos[y], paint);
-
绘制方法:
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
canvas.setDrawFilter(paintFlagsDrawFilter);
//原始点
canvas.save();
canvas.translate(50,50);
canvas.drawBitmapMesh(bitmapCarBody, carBodyWidthPart, carBodyHeightPart, carBodyOrigPos, 0, null, 0, paint);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
drawPoint(canvas, carBodyOrigPos, paint);
canvas.restore();
//变化点
canvas.save();
canvas.translate(1000,50);
canvas.drawBitmapMesh(bitmapCarBody, carBodyWidthPart, carBodyHeightPart, carBodyNewsPos, 0, null, 0, paint);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
drawPoint(canvas, carBodyNewsPos, paint);
canvas.restore();
- 左边的是原始点所画出来的,右边是变化后所画出来的,因为这里没有对点进行偏移所以左右是一样的。还有要注意的一点,绘制drawBitmapMesh是没有传入绘制的起始点,因为他默认是从原始点开始绘制,所以这里有把坐标移动的代码。
4. 尝试加点扭曲
既然要形变要扭曲,那么我们先对carBodyNewsPos这个点集进行肆意妄为地操作一下:
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
canvas.setDrawFilter(paintFlagsDrawFilter);
//原始点
canvas.save();
canvas.translate(50,50);
canvas.drawBitmapMesh(bitmapCarBody, carBodyWidthPart, carBodyHeightPart, carBodyOrigPos, 0, null, 0, paint);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
drawPoint(canvas, carBodyOrigPos, paint);
canvas.restore();
//遍历交点,修改
for (int i = 0; i < carBodyPartCount; i++)
int x = i * 2;
int y = x + 1;
carBodyNewsPos[x] = carBodyOrigPos[x] * (changeFactor * 1.0f / 100 + 1);
//变化点
canvas.save();
canvas.translate(1000,50);
canvas.drawBitmapMesh(bitmapCarBody, carBodyWidthPart, carBodyHeightPart, carBodyNewsPos, 0, null, 0, paint);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
drawPoint(canvas, carBodyNewsPos, paint);
canvas.restore();
我们对每一个点应用了:carBodyNewsPos[x] = carBodyOrigPos[x] * (changeFactor * 1.0f / 100 + 1)
:
5. 车厢的扭曲实现
仔细观察车厢的动画,发现有几点细节:
- 扭曲可以分解为x,y轴的扭曲,其叠加一起就是车厢的动画
- 车厢和车顶的扭曲一样,不用的是扭曲度
- x轴的扭曲,以车厢的中心轴为分界线,左边向左扭曲,右边向右扭曲
- x轴方向的拉伸,离x中心轴线越近变化越小,离顶部(y=0)越近,变化也越小
- y轴的扭曲,是以y=0为中心轴,离x中心轴线越近变化越大,离顶部(y=0)越近,变化也越小
因为我们是依次遍历点集,就是从i=0一直到i=posCount,那么我们来实现一下上面的变化:
- 设定两个因子:xFactor和yFactor,控制x,y轴方向的最大扭曲度。
- 设定变化因子changeFactor,带动扭曲度随着时间而变化
- 当点的x在x中心轴的左边,其x坐标应该是原始坐标减去扭曲度,反之亦然
大致得到X方向的扭曲度:changeFactor*Math.abs((widthPart+1)/2-i%(widthPart+1))*(origPos[y]/bitmap.getHeight()) * xFactor;
- xFactor是控制整个扭曲度的大小
- 顶部(y=0)越近,变化也越小,而因为是从y=0开始绘制,所以,
bitmap.getHeight()
就是y轴的最大值,那么,origPos[y]/bitmap.getHeight()
就是当前点所占y轴的百分比,也就是,离y=0越近,origPos[y]/bitmap.getHeight()
的值越小。 - 离x周轴线越近变化越小,
Math.abs((widthPart+1)/2-i%(widthPart+1))
如上图,红色为x的中心轴,而我们遍历的i(点的个数)值是从0-N,而,i=0,i=4的时候最大,i=1,i=3次小,如此类推。 (widthPart+1)/2
是算出中心轴的坐标相对位置,例如图中,算出应该是2,那么中心轴的相对位置则为2,而i%(widthPart+1)
,在图中就是,0-4的取值,跟中心轴的相对位置2相减取绝对值,就是一个离中心轴的变化量的大小了。
Y方向的扭曲度,也是一样的。这里就不说了。。。最后得出的扭曲函数如下:
,i=1,i=3次小,如此类推。 (widthPart+1)/2
是算出中心轴的坐标相对位置,例如图中,算出应该是2,那么中心轴的相对位置则为2,而i%(widthPart+1)
,在图中就是,0-4的取值,跟中心轴的相对位置2相减取绝对值,就是一个离中心轴的变化量的大小了。
Y方向的扭曲度,也是一样的。这里就不说了。。。最后得出的扭曲函数如下:
以上是关于Android 自定义 View _ 扭曲动效,android开发环境搭建教程的主要内容,如果未能解决你的问题,请参考以下文章
恭喜发财! -- 手把手教你仿造一个qq下拉抢红包 Android自定义view