Android---PhotoView

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

目录

准备工作

1、双击放大和缩小

2、惯性滑动

3、双指放大和缩小

4、完整DEMO

准备工作

 \bullet 自定义PhotoView

        自定义 PhotoView 继承(extends)自 View。并在最中间显示后面操作的图片。绘制图片可以重写 onDraw()方法,并在里面通过Canvas.drawBitmap()来要绘制图片。

        drawBitmap()的四个参数:

        \bullet bitmap: 要在 Canvas 中绘制的位图

        \bullet letf: 正在绘制的位图左侧的位置

        \bullet top: 正在绘制的位图顶部的位置

        \bullet 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);
    }
}

\bullet 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>

\bullet 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、双击放大和缩小

\bullet 设置图片的缩放比例

       如下图的三种情况,左边的是原图;中间是小放大(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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别偷我的猪_09

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值