抖音短視頻系統開發圖片局部放大鏡,可在大圖上下左右移動並放大對應的區域

如何實現放大鏡的原理呢?一種方式我們可以採用將原圖中的局部區域提取裁剪,然後在圖片頂層的自定義控件上放大對應的倍數展示即可;另外一個種方式是將整圖都放大相應的倍數,然後截取需要顯示的區域,間接實現放大的效果,我使用的是第二種方法。

當然會涉及到平移,繪製邊框的附加構件。

下面是實現的自定義類,具體註釋見代碼:

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();
		}
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章