Android 实现不规则ImageView布局

这只是一个给大家学习参考的例子而已,还是有许多问题存在的。看代码吧,注释已经在里面了。

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);
	}
	
	@Override
	protected 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分之1
	private 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();
	}
	
	@Override
	protected 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();
		}
	}
	
	@Override
	public 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) {
					// 两个手指并拢在一起的时候素大于10
					float 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) { // 两个手指并拢在一起的时候像素大于10
				midPoint = 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) {
		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);
	}
}



 
  

效果图:

Android 实现不规则ImageView布局_第1张图片

以上内容仅供学习和参考,如有不好的地方欢迎指正和提供建议,谢谢!



你可能感兴趣的:(Android开发)