如何實現放大鏡的原理呢?一種方式我們可以採用將原圖中的局部區域提取裁剪,然後在圖片頂層的自定義控件上放大對應的倍數展示即可;另外一個種方式是將整圖都放大相應的倍數,然後截取需要顯示的區域,間接實現放大的效果,我使用的是第二種方法。
當然會涉及到平移,繪製邊框的附加構件。
下面是實現的自定義類,具體註釋見代碼:
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();
}
}
}