抖音短视频系统开发图片局部放大镜,可在大图上下左右移动并放大对应的区域

如何实现放大镜的原理呢?一种方式我们可以采用将原图中的局部区域提取裁剪,然后在图片顶层的自定义控件上放大对应的倍数展示即可;另外一个种方式是将整图都放大相应的倍数,然后截取需要显示的区域,间接实现放大的效果,我使用的是第二种方法。

当然会涉及到平移,绘制边框的附加构件。

下面是实现的自定义类,具体注释见代码:

package com.example.zoompicview;
 
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
 
/**
 * @Description TODO 图片放大镜控件实现
 */
public class ZoomToolView extends View {
	private Path path;
	private Matrix matrix;
	private Paint paint;
	private Bitmap bitmap;
	private static final int RADIUS = 80;// 放大镜半径
	private static final int FACTOR = 3; // 放大系数
	private static final int STROKE = 4; // 附加线条宽度
	private float currentX, currentY;
	
	public ZoomToolView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init();
	}
	
	public ZoomToolView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public ZoomToolView(Context context) {
		super(context);
		init();
	}
	
	private void init() {
		path = new Path();
		path.addCircle(RADIUS, RADIUS, RADIUS, Direction.CW);
		matrix = new Matrix();
		matrix.setScale(FACTOR, FACTOR);
		paint = new Paint();
		paint.setAntiAlias(true);
		paint.setDither(true);
		paint.setStrokeWidth(STROKE);
		paint.setColor(Color.WHITE);
		paint.setStyle(Paint.Style.STROKE);
	}
	
	public Bitmap getBitmap() {
		return bitmap;
	}
	
	// 设置Bitmap
	public void setBitmap(Bitmap bitmap) {
		if (null != bitmap) {
			this.bitmap = bitmap;
		} else {
			try {
				throw new Exception("bitmap can't be null");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@SuppressLint("ClickableViewAccessibility")
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (null == bitmap) {
			return super.onTouchEvent(event);
		}
		currentX = event.getX();
		currentY = event.getY();
		// 控制不会移动出图片边界
		if (currentX > bitmap.getWidth()) {
			currentX = bitmap.getWidth();
		} else if (currentX < 0) {
			currentX = 0;
		}
		if (currentY > bitmap.getHeight()) {
			currentY = bitmap.getHeight();
		} else if (currentY < 0) {
			currentY = 0;
		}
		invalidateView();
		return true;
	}
	
	@SuppressLint("DrawAllocation")
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (null == bitmap) {
			try {
				throw new Exception("please setBitmap, bitmap can't be null");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// 底图
		canvas.drawBitmap(bitmap, 0, 0, null);
		// 剪切
		canvas.translate(currentX - RADIUS, currentY - RADIUS);
		canvas.clipPath(path);
		
		// 移动到path剪切部分显示
		canvas.translate(RADIUS - currentX * FACTOR, RADIUS - currentY * FACTOR);
		canvas.drawBitmap(bitmap, matrix, null);
		// 反向平移并绘制十字和外边框
		canvas.translate(currentX * FACTOR - RADIUS, currentY * FACTOR - RADIUS);
		Path line = new Path();
		line.moveTo(0, RADIUS);
		line.lineTo(RADIUS * 2, RADIUS);
		line.moveTo(RADIUS, 0);
		line.lineTo(RADIUS, RADIUS * 2);
		canvas.drawPath(line, paint);
		canvas.drawCircle(RADIUS, RADIUS, RADIUS - STROKE, paint);
	}
	
	private void invalidateView() {
		if (Looper.getMainLooper() == Looper.myLooper()) {
			invalidate();
		} else {
			postInvalidate();
		}
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章