一、定义属性
1.在attrXML中编写属性
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="endoffset" format="dimension" /> <attr name="mirror_height" format="dimension" /> <attr name="detach_WidthCount" format="integer" /> <attr name="detach_HeightCount" format="integer" /> <attr name="sinRange" format="float"/> <attr name="flagCount" format="integer"/> <declare-styleable name="MyMirrorView"> <attr name="endoffset" /> <attr name="mirror_height" /> <attr name="detach_WidthCount" /> <attr name="detach_HeightCount" /> <attr name="sinRange"/> <attr name="flagCount"/> </declare-styleable> </resources>2.编写布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:huaihuai="http://schemas.android.com/apk/res/com.huaihuai.mydemolistapp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.imooc.mydeclareView.MyMirrorView android:id="@+id/id_mirrorView" android:layout_width="match_parent" android:layout_height="wrap_content" huaihuai:detach_WidthCount="50" huaihuai:detach_HeightCount="50" huaihuai:flagCount="4" huaihuai:sinRange="15" huaihuai:endoffset="20dp"> </com.imooc.mydeclareView.MyMirrorView> </LinearLayout>3.在自定义View中引用
TypedArray array = getResources().obtainAttributes(attrs, R.styleable.MyMirrorView); endRightOffset = array.getDimension(R.styleable.MyMirrorView_endoffset, 0); mirror_height = array.getDimension( R.styleable.MyMirrorView_mirror_height, mBitmap.getHeight()); detach_WidthCount = array.getInt( R.styleable.MyMirrorView_detach_WidthCount, 200); detach_HeghtCount = array.getInt( R.styleable.MyMirrorView_detach_HeightCount, 200); sinRange = array.getFloat(R.styleable.MyMirrorView_sinRange, 50f); flagCount = array.getInt(R.styleable.MyMirrorView_flagCount, 10); array.recycle(); initView();声明View中属性
/** * 最后的偏移量 */ private float endRightOffset; /** * mirror的高度 */ private float mirror_height; /** * 图片宽度分离的数目 */ private int detach_WidthCount; /** * 图片高度分离的数目 */ private int detach_HeghtCount; /** * sin的变化幅度 */ private float sinRange; /** * 驼峰数量 */ private int flagCount; /** * 图片分割后的坐标存储 */ private float[] verts; private float[] orig; private float k = 1;
二、 初始化View以及数据
1。初始化View
// 默认的图片 int mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; int mScreenHeight = getResources().getDisplayMetrics().heightPixels; Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic_5); float scaleY = (float) mScreenHeight / (2f * mBitmap.getHeight()); float scaleX = (float) mScreenWidth / (mBitmap.getWidth()); // 使图片缩放为屏幕的一半 mBitmapOld = mBitmap = HandleImageUtils.scaleBitmap(mBitmap, scaleX, scaleY);
// 图片Y轴对称 Matrix matrix = new Matrix(); matrix.setScale(1.0f, -1.0f); mBitmapMirror = Bitmap.createBitmap(mBitmapOld, 0, 0, mBitmapOld.getWidth(), (int) mirror_height, matrix, true);2.进行图片的分割
// 进行图片的分割 detachImageView(mBitmapMirror);
/** * 进行图片的分割 */ private void detachImageView(Bitmap bitmap) { // orig偶数存储fx,奇数存储fy verts = new float[2 * (detach_HeghtCount + 1) * (detach_WidthCount + 1)]; orig = new float[2 * (detach_HeghtCount + 1) * (detach_WidthCount + 1)]; float width = bitmap.getWidth(); float heght = bitmap.getHeight(); int index = 0; for (int i = 0; i < detach_HeghtCount + 1; i++) { float fy = heght / detach_HeghtCount * i; for (int j = 0; j < detach_WidthCount + 1; j++) { float fx = width / detach_WidthCount * j; orig[2 * index + 0] = verts[2 * index + 0] = fx; orig[2 * index + 1] = verts[2 * index + 1] = fy; // pos[i][j] = (float) Math.sqrt(Math.pow(fx, 2) + Math.pow(fy, // 2)); index += 1; } } }3.设置画笔
// 设置镜面的渲染 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setShader(new LinearGradient(0, (float) (1.8 * mBitmapOld .getHeight()), 0, mBitmapOld.getHeight(), 0xf0000000, 0x00000000, TileMode.CLAMP)); mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));三、OnDraw()进行绘制
1.绘制屏幕上半层图像
canvas.drawBitmap(mBitmapOld, 0, 0, null);
2.绘制下半层图像
canvas.drawBitmapMesh(mBitmapMirror, detach_WidthCount,
detach_HeghtCount, verts, 0, null, 0, null);
通过verts的坐标改变可以绘制任意变化的图片(关键)
3.在下半层渲染图片(线性渐变)
canvas.drawRect(0, mBitmapOld.getHeight(), mBitmapMirror.getWidth(),
mirror_height + mBitmapOld.getHeight(), mPaint);
4.添加动态效果,使镜像图片像水波波动
/** * 旗帜效果 */ private void sinflagView() { for (int i = 0; i < detach_HeghtCount + 1; i++) { for (int j = 0; j < detach_WidthCount + 1; j++) { verts[(i * (detach_HeghtCount + 1) + j) * 2 + 0] = orig[(i * (detach_HeghtCount + 1) + j) * 2 + 0]; //- 0.3f * mBitmapMirror.getWidth() / 2; float scale = j * flagCount; while (scale > detach_WidthCount) { scale -= detach_WidthCount; } float offsetY = (float) Math.sin((float) scale / detach_WidthCount * Math.PI * 2 + k * 2 * Math.PI); verts[(i * (detach_WidthCount + 1) + j) * 2 + 1] = orig[(i * (detach_WidthCount + 1) + j) * 2 + 1] + sinRange * offsetY + mBitmapOld.getHeight(); Log.i("521huaihuai", "" + (float) i / detach_HeghtCount * endRightOffset); } } }5.不断地进行重绘
invalidate();
k += 0.1f;
demo链接http://pan.baidu.com/s/1c0PEl0W
大概这样,感觉有一些可以改变,可以新建一个类来存储verts的坐标,更容易实现坐标的改变(一维2二维)
感觉这个View改成只剩下动态倒影的bitmap,在修改一下形状,用来做头像倒是还可以,按钮的话,不确定,
今天本想通过这个,做一个,像水滴的波纹,不过,结果一塌糊涂,计算量太大,跑不起来,而且算法还有问题,还是得多多学习别人的经验。