开发者社区> 爆米花9958> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

自定义ImageView实现图片手势滑动、放大缩小效果

简介: 上一节说了通过自定义来加载超大图片,同时实现手指的拖动效果。不过,另一种情况就是,我们希望应用能够加载整张图片,如果图片太大就先压缩,如果小于屏幕就直接显示,同时用户可以拖拽移动和缩放图片大小,梳理下流程: 1.自定义View继承ImageView,重新onDraw方法 2.在onDraw先画图片,图片大于屏幕就把图片缩小后显示,图片小于屏幕就直接显示,显示之前要计算显示图片的Rect,Rect是其实就是四个坐标,用来控制显示图片的范围,这个Rect是根据图片的长宽比例计算而来,显示在屏幕中间。
+关注继续查看
上一节说了通过自定义来加载超大图片,同时实现手指的拖动效果。不过,另一种情况就是,我们希望应用能够加载整张图片,如果图片太大就先压缩,如果小于屏幕就直接显示,同时用户可以拖拽移动和缩放图片大小,梳理下流程:
1.自定义View继承ImageView,重新onDraw方法

2.在onDraw先画图片,图片大于屏幕就把图片缩小后显示,图片小于屏幕就直接显示,显示之前要计算显示图片的Rect,Rect是其实就是四个坐标,用来控制显示图片的范围,这个Rect是根据图片的长宽比例计算而来,显示在屏幕中间。

3.重写onTouchEvent方法,处理View随着手指移动的相关操作:在touchEvent事件中处理好按下和松开事件之后,剩下的就是移动事件,通过不断的改变Rect的坐标,然后不断的调用invalidate(),该方法用来重新绘制我们的View


看下DragImageView.java


public class DragImageView extends ImageView {
    private Drawable mDrawable;
    private Rect mDrawableRect;
    private Context mContext;
    private float mRation_WH = 0;
    private float mOldX = 0;
    private float mOldY = 0;
    private double mD1;
    private boolean isFirst = true;

    private int NONE = 0;// 无操作
    private int SINGAL_MOVE = 1;// 单点移动
    private int MUTIL_MOVE = 2;// 双点拖拽
    private int mStatus = 0;

    public DragImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public DragImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DragImageView(Context context) {
        super(context);
        this.mContext = context;
        mDrawableRect = new Rect();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // getIntrinsicHeight为返回对象的实际高度
        if (mDrawable == null || mDrawable.getIntrinsicHeight() == 0
                || mDrawable.getIntrinsicWidth() == 0) {
            return;
        }
        setBounds(); // 设置图片
        mDrawable.draw(canvas);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mOldX = event.getX();
            mOldY = event.getY();
            break;
        case MotionEvent.ACTION_UP:
            mStatus = NONE;
            checkBounds();
            break;
        case MotionEvent.ACTION_MOVE:
            if (event.getPointerCount() == 1)
                mStatus = SINGAL_MOVE;
            else
                mStatus = MUTIL_MOVE;
            onTouchMove(event);
            break;
        default:
            break;
        }
        return true;
    }

    private void onTouchMove(MotionEvent event) {
        // 判断有几个触摸点
        if (mStatus == SINGAL_MOVE) {
            int offsetWidth = (int) (event.getX() - mOldX);
            int offsetHeight = (int) (event.getY() - mOldY);
            mOldX = event.getX();
            mOldY = event.getY();
            mDrawableRect.offset(offsetWidth, offsetHeight);
            invalidate();
        } else if (mStatus == MUTIL_MOVE) {
            float X0 = event.getX(0);
            float Y0 = event.getY(0);
            float X1 = event.getX(1);
            float Y1 = event.getY(1);
            double mD2 = Math.sqrt(Math.pow(X0 - X1, 2) + Math.pow(Y0 - Y1, 2));

            if (mD1 < mD2) {
                // 放大操作
                if (mDrawableRect.width() < mContext.getResources()
                        .getDisplayMetrics().widthPixels * 2) {
                    int offsetwidth = 10;
                    int offsettop = (int) (offsetwidth / mRation_WH);
                    mDrawableRect.set(mDrawableRect.left - offsetwidth,
                            mDrawableRect.top - offsettop, mDrawableRect.right
                                    + offsetwidth, mDrawableRect.bottom
                                    + offsettop);
                    invalidate();
                }

            } else {
                // 设置为只能缩小为屏幕的1/3,可以根据需要自己调整
                if (mDrawableRect.width() > mContext.getResources()
                        .getDisplayMetrics().widthPixels / 3) {
                    int offsetwidth = 10;
                    int offsettop = (int) (offsetwidth / mRation_WH);
                    mDrawableRect.set(mDrawableRect.left + offsetwidth,
                            mDrawableRect.top + offsettop, mDrawableRect.right
                                    - offsetwidth, mDrawableRect.bottom
                                    - offsettop);
                    invalidate();
                }
            }
            mD1 = mD2;
        }

    }

    /**
     * 设置mDrawable
     */
    public void setBounds() {
        if (isFirst) {
            // 图片宽高比
            mRation_WH = (float) mDrawable.getIntrinsicWidth()
                    / (float) mDrawable.getIntrinsicHeight();
            // 取屏幕宽和图片宽较小的一个
            int px_w = Math.min(getWidth(),
                    dp2px(mContext, mDrawable.getIntrinsicWidth()));
            int px_h = (int) (px_w / mRation_WH);// 获得图片高
            int left = (getWidth() - px_w) / 2;
            int top = (getHeight() - px_h) / 2;
            int right = px_w + left;
            int bottom = px_h + top;
            mDrawableRect.set(left, top, right, bottom);
            isFirst = false;
        }
        mDrawable.setBounds(mDrawableRect);

    }

    /**
     * 检测边框范围
     */
    public void checkBounds() {
        int newLeft = mDrawableRect.left;
        int newTop = mDrawableRect.top;
        boolean isChange = false;
        // 向左移动范围<=屏幕宽度
        if (newLeft < -mDrawableRect.width()) {
            newLeft = -mDrawableRect.width();
            isChange = true;
        }
        // 向上移动范围<=屏幕高度
        if (newTop < -mDrawableRect.height()) {
            newTop = -mDrawableRect.height();
            isChange = true;
        }
        // 向右移动范围<=屏幕宽度
        if (newLeft > getWidth()) {
            newLeft = getWidth();
            isChange = true;
        }
        // 向下移动范围<=屏幕高度
        if (newTop > getHeight()) {
            newTop = getHeight();
            isChange = true;
        }
        if (isChange) {
            mDrawableRect.offsetTo(newLeft, newTop);
            invalidate();
        }
    }

    public Drawable getmDrawable() {
        return mDrawable;
    }

    public void setmDrawable(Drawable mDrawable) {
        this.mDrawable = mDrawable;
    }

    /**
     * 将dp单位换算成px
     * @param context
     * @param value
     * @return
     */
    public int dp2px(Context context, int value) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (value * scale + 0.5f);
    }

}

在java类中直接调用即可

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        DragImageView mView = new DragImageView(this);
        mView.setmDrawable(getResources().getDrawable(R.drawable.bg));
        setContentView(mView);
    }

效果如下:


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
一款简单的缩放拖拽图片控件
本文介绍一个针对 .NET 桌面应用程序的独立图片缩放拖拽显示控件 [SQPhoto](https://www.nuget.org/packages/SQPhoto/)。
0 0
平铺文理+拉伸按钮图片
平铺文理+拉伸按钮图片
0 0
3D立方体图片切换动画
在线演示 本地下载
517 0
自定义ImageView实现图片的单指拖动和两指缩放
MainActivity如下: package cn.testtouchscreentomoveimage; import android.app.
622 0
文章
问答
文章排行榜
最热
最新
相关电子书
更多
3D动画的菜谱式灯光与云渲染
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载