目录
准备工作
自定义PhotoView
自定义 PhotoView 继承(extends)自 View。并在最中间显示后面操作的图片。绘制图片可以重写 onDraw()方法,并在里面通过Canvas.drawBitmap()来要绘制图片。
drawBitmap()的四个参数:
bitmap: 要在 Canvas 中绘制的位图
letf: 正在绘制的位图左侧的位置
top: 正在绘制的位图顶部的位置
paint: 画笔
其中 (left, top) 是要绘制图片的起始坐标。要将图片绘制在中间,我们就需要计算 left/top 的位置。我们重写 onSizeChanged() 函数,该函数在onDraw之前调用,且尺寸改变时也要调用。
其中:(下面代码中是用 originalOffsetX/originalOffsetY 来代替的)
left = (getWidth() - bitmap.getWidth()) / 2;
top = (getHeight() - bitmap.getHeight()) / 2;

public class PhotoView extends View {
private static final float IMAGE_WIDTH = Utils.dpToPixel(300);
private Bitmap bitmap;
private Paint paint; // 画笔
private float originalOffsetX;
private float originalOffsetY;
public PhotoView(Context context) {
this(context, null);
}
public PhotoView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PhotoView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* 初始化操作
*/
private void init() {
bitmap = Utils.getPhoto(getResources(), (int) IMAGE_WIDTH); // 获取到图片
paint = new Paint();
}
/**
* TODO 在onDraw之前调用,且尺寸改变时也要调用
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
originalOffsetX = (getWidth() - bitmap.getWidth()) / 2f;
originalOffsetY = (getHeight() - bitmap.getHeight()) / 2f;
}
/**
* 画出图片
* @param canvas 画布
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint);
}
}
xml 布局
xml 布局中最外层是 FragmeLayout,里面只有一个自定义的 PhotoView 用来展示图片。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.photoview2.PhotoView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
Utils 工具类
Utils 工具类里主要有两个函数。dpToPixel() 将 dp 转换为像素;getPhot() 加载 Drawable 下的图片,并返回为 bitmap 类型。
public class Utils {
public static float dpToPixel(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
public static Bitmap getPhoto(Resources res, int width) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, R.drawable.photo, options);
options.inJustDecodeBounds = false;
options.inDensity = options.outWidth;
options.inTargetDensity = width;
return BitmapFactory.decodeResource(res, R.drawable.photo, options);
}
}
1、双击放大和缩小

设置图片的缩放比例
如下图的三种情况,左边的是原图;中间是小放大(smallScale),即图片左右两边贴进屏幕;右边是大放大(bigScale),即图片沾满整个屏幕。

根据上面的描述,设置两个变量即 smallScale 和 bigScale 分别代表上图"中"和“右”的缩放比例,smallScale 是初始样式,bigSmall 是双击后的样式。将 smallScale 和 bigScale 的设置放在 onSizeChanged() 函数里设值。如下图所示

/**
* TODO 在onDraw之前调用,且尺寸改变时也要调用
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
originalOffsetX = (getWidth() - bitmap.getWidth()) / 2f;
originalOffsetY = (getHeight() - bitmap.getHeight()) / 2f;
// TODO 判断 bitmap 是扁的还是长的
if ((float)bitmap.getWidth() / bitmap.getHeight() > (float) getWidth() / getHeight()) {
// bitmap 的 width > height
smallScale = (float) getWidth() / bitmap.getWidth();
bigScale = (float) getHeight() / bitmap.getHeight() * OVER_SCALE_FACTOR;
}else {
// bitmap 的 height > widt

本文详细介绍了如何在Android中自定义一个PhotoView组件,支持双击放大、惯性滑动和双指缩放功能。通过GestureDetector和ScaleGestureDetector实现手势检测,结合属性动画实现平滑缩放效果,以及通过计算边界值防止图片滑出屏幕。

4074

被折叠的 条评论
为什么被折叠?



