Android 实现不规则ImageView布局

来源:互联网 发布:网络固定电话怎么装 编辑:程序博客网 时间:2024/05/20 19:29

不啰嗦,直接上代码!注释已经在代码里写的比较详细了!不懂的地方欢迎提问。

import java.io.IOException;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.Path;import android.graphics.PointF;import android.util.AttributeSet;import android.util.FloatMath;import android.util.Log;import android.view.MotionEvent;import android.view.View;//自定义类继承View@SuppressLint({"NewApi", "DrawAllocation" })public class CustomFourImageView extends View {//用于判断只在第一次绘制才初始化一些资源数据private int state = -1;private final int START = 1;private Bitmap topImage;private Bitmap bottomImage;private Bitmap leftImage;private Bitmap rightImage;private Paint paint;private Matrix topMatrix;private Matrix bottomMatrix;private Matrix leftMatrix;private Matrix rightMatrix;private float padding = 14;//边框的大小(实则为10px)private Path top;private Path bottom;private Path left;private Path right;/** 记录是拖拉照片模式还是放大缩小照片模式 */private int mode = 0;// 初始状态/** 拖拉照片模式 */private static final int MODE_DRAG = 1;/** 放大缩小照片模式 */private static final int MODE_ZOOM = 2;/** 用于记录开始时候的坐标位置 */private PointF startPoint = new PointF();/** 两个手指的开始距离 */private float startDis;/** 两个手指的中间点 */private PointF midPoint;private static int TYPE = 0;public CustomFourImageView(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);}public CustomFourImageView(Context context, AttributeSet attrs) {super(context, attrs);}public CustomFourImageView(Context context) {super(context);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);if (state > 0) {return;}state = START;init();}//初始化private void init() {setLayerType(View.LAYER_TYPE_SOFTWARE, null);// 软件加速try {topImage = BitmapFactory.decodeStream(getContext().getAssets().open("m1.jpg"));bottomImage = BitmapFactory.decodeStream(getContext().getAssets().open("m2.jpg"));leftImage = BitmapFactory.decodeStream(getContext().getAssets().open("m3.jpg"));rightImage = BitmapFactory.decodeStream(getContext().getAssets().open("m4.jpg"));} catch (IOException e) {e.printStackTrace();}paint = new Paint();paint.setAntiAlias(true);paint.setDither(true);// 防抖动paint.setFilterBitmap(true);// 过滤initMatrix();// 缩小图片initPath();}// 初始化矩阵(3X3)并缩放图片为原图的2分之1private void initMatrix() {topMatrix = new Matrix();bottomMatrix = new Matrix();leftMatrix = new Matrix();rightMatrix = new Matrix();float w = getWidth();float h = getWidth();// 第一个图片float scale = 1;// 缩放量float scaleX = w / topImage.getWidth();float scaleY = h / topImage.getHeight();scale = scaleX > scaleY ? scaleX : scaleY;topMatrix.setScale(scale, scale);// 开始缩放比例// 第二个图片scaleX = w / bottomImage.getWidth();scaleY = h / bottomImage.getHeight();scale = scaleX > scaleY ? scaleX : scaleY;bottomMatrix.setScale(scale, scale);// 第三个图片scaleX = w / leftImage.getWidth();scaleY = h / leftImage.getHeight();scale = scaleX > scaleY ? scaleX : scaleY;leftMatrix.setScale(scale, scale);// 第四个图片scaleX = w / rightImage.getWidth();scaleY = h / rightImage.getHeight();scale = scaleX > scaleY ? scaleX : scaleY;rightMatrix.setScale(scale, scale);}// 画好矩阵模块private void initPath() {float cpad = padding / 2;// padding = 10// 视图宽高float w = getWidth();float h = getWidth();float bx = w / 2;//float by = h / 2;// 相当于中心点float bxx = bx / 2;//float byy = by / 2;top = new Path();bottom = new Path();left = new Path();right = new Path();// 上图top.moveTo(padding, padding);top.lineTo(w -bxx-cpad, padding);top.lineTo(bx - cpad, by - cpad);top.lineTo(padding, byy - cpad);top.close();// 左图left.moveTo(padding, byy + cpad);left.lineTo(bx - cpad, by+cpad);left.lineTo(bxx - cpad, h - padding);left.lineTo(padding, h - padding);left.close();// 下图bottom.moveTo(bxx+cpad, h-padding);bottom.lineTo(w -padding, h-padding);bottom.lineTo(w - padding, h - byy+cpad);bottom.lineTo(bx+cpad, by+cpad);bottom.close();// 右图right.moveTo(w - bxx+cpad, padding);right.lineTo(w -padding, padding);right.lineTo(w - padding, h - byy-cpad);right.lineTo(bx+cpad, by-cpad);right.close();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (topImage != null) {// 设置抗锯齿PaintFlagsDrawFilter pfd = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);canvas.setDrawFilter(pfd);canvas.save();canvas.clipPath(top);// 先画好模块canvas.drawBitmap(topImage, topMatrix, paint);// 再画图canvas.restore();canvas.save();canvas.clipPath(left);canvas.drawBitmap(leftImage, leftMatrix, paint);canvas.restore();canvas.save();canvas.clipPath(bottom);canvas.drawBitmap(bottomImage, bottomMatrix, paint);canvas.restore();canvas.save();canvas.clipPath(right);canvas.drawBitmap(rightImage, rightMatrix, paint);canvas.restore();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:// 当第一个手指按下时mode = MODE_DRAG;if (isInsideTop(event)) {// 上图TYPE = 1;startPoint.set(event.getX(), event.getY());} else if (isInsideBottom(event)) {// 下图TYPE = 2;startPoint.set(event.getX(), event.getY());} else if (isInsideLeft(event)) {// 左图TYPE = 3;startPoint.set(event.getX(), event.getY());}else if(isInsideRight(event)){// 右图TYPE = 4;startPoint.set(event.getX(), event.getY());}break;case MotionEvent.ACTION_MOVE:// 移动或缩放if (mode == MODE_DRAG) {// 拖拉图片float dx = event.getX() - startPoint.x;// 减去第一次的移动距离float dy = event.getY() - startPoint.y;startPoint.x = event.getX();startPoint.y = event.getY();// 在没有移动之前的位置上进行移动getCurrentMatrix().postTranslate(dx, dy);} else if (mode == MODE_ZOOM) {// 放大缩小图片float endDis = distance(event);// 结束距离if (endDis > 10f) {// 两个手指并拢在一起的时候素大于10float scale = endDis / startDis;startDis = endDis;// 得到缩放倍数进行缩放getCurrentMatrix().postScale(scale, scale, midPoint.x,midPoint.y);}}break;case MotionEvent.ACTION_UP:// 当触点离开屏幕,但是屏幕上还有触点(手指)break;case MotionEvent.ACTION_POINTER_UP:mode = 0;break;case MotionEvent.ACTION_POINTER_DOWN:// 当屏幕上已经有触点(手指),再有一个触点压下屏幕mode = MODE_ZOOM;startDis = distance(event);if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10midPoint = mid(event);// 记录当前ImageView的缩放倍数}break;}invalidate();// 重绘return true;}private Matrix getCurrentMatrix() {switch (TYPE) {case 1:return topMatrix;case 2:return bottomMatrix;case 3:return leftMatrix;default:return rightMatrix;}}//计算上图的焦点范围private boolean isInsideTop(MotionEvent event) {float x = event.getX();float y = event.getY();float w = getWidth();return y < (-2*x + 3*w/2) && y < (x/2 + w/4);}//计算下图的焦点范围private boolean isInsideBottom(MotionEvent event) {float x = event.getX();float y = event.getY();float w = getWidth();return y > (-2*x + 3*w/2) && y > (x/2 + w/4);}//计算左图的焦点范围private boolean isInsideLeft(MotionEvent event) {float x = event.getX();float y = event.getY();float w = getWidth();return y < (-2*x + 3*w/2) && y > (x/2 + w/4);}//计算右图的焦点范围private boolean isInsideRight(MotionEvent event) {<span style="white-space:pre"></span>float x = event.getX();float y = event.getY();float w = getWidth();return y > (-2*x + 3*w/2) && y < (x/2 + w/4);}/** 计算两个手指间的距离 */private float distance(MotionEvent event) {float dx = event.getX(1) - event.getX(0);float dy = event.getY(1) - event.getY(0);/** 使用勾股定理返回两点之间的距离 */return FloatMath.sqrt(dx * dx + dy * dy);}/** 计算两个手指间的中间点 */private PointF mid(MotionEvent event) {float midX = (event.getX(1) + event.getX(0)) / 2;float midY = (event.getY(1) + event.getY(0)) / 2;return new PointF(midX, midY);}}



效果图:



以上仅供学习参考!如有不好的地方欢迎提供建议和讨论!



2 0
原创粉丝点击