自定义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);
    }

效果如下:


相关文章
|
7月前
|
Android开发
Android通过手势(多点)缩放和拖拽图片
Android通过手势(多点)缩放和拖拽图片
61 4
|
6月前
|
Java Android开发
18. 【Android教程】图片控件 ImageView
18. 【Android教程】图片控件 ImageView
102 4
|
C++
duilib corner属性的贴图技巧——让图片自动贴到控件的的某一边或者一角并自适应控件的大小
转载请说明原出处,谢谢~~          Duilib给控件贴图功能可以附带多个属性,各个属性的配合可以达到许多效果。以下是duilib支持的所有贴图属性: 贴图描述:          Duilib的表现力丰富很大程度上得益于贴图描述的简单强大。
1829 0
|
Android开发
【Android视图效果】仿QQ空间滑动改变标题栏颜色
最近在倒腾公司之前的项目,发现之前的界面是个白色标题栏,不是很美观,所以做了些改进。 先看效果图 165815uykp80g8y3goo5vz.gif 简单说下思路,整个布局大体上是ScrollView里面包含了一个ImageView和RecyclerView,所以先得到ImageView的高度,当ScrollView向上滑动时,设置标题栏的背景色、文字颜色,当超过ImageView的高度时,设置其背景为白色,字体为黑色。
1174 0
|
前端开发 Android开发 Rust
Android - 条纹进度条实现,调整view宽度仿进度条
相关代码请参阅: https://github.com/RustFisher/aboutView/blob/master/app/src/main/java/com/rust/aboutview/activity/RoundCornerActivity.java 美工同学指定了一个进度条样式 这斑斓的进度条,如果要自己画实在是劳民伤财。
3247 0
uwp 图片切换动画 使用帧动画
原文:uwp 图片切换动画 使用帧动画 上一篇博客使用了Timer来实现图片的切换,@lindexi_gd讨论了一下性能,我本人其实对性能这一方面不太熟,但我觉得还是有必要考虑一下,那么今天我们使用帧动画开实现以下 新建项目,添加一个Button和Image 在Page里定义资源 ...
943 0
|
前端开发
利用TextView中的DrawableTop实现图片在文字上方,点击TextView能实现图片旋转
终于建了一个自己个人小站:https://huangtianyu.gitee.io,以后优先更新小站博客,欢迎进站,O(∩_∩)O~~ 在今日头条里面Home按钮点击时候,能出现旋转的动画。这里模仿今日头条的Home按钮效果,通过自定义View来实现该效果。
1517 0
|
Android开发 缓存
Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果
 Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果 附录1简单介绍了Android开源的图片加载框架。
1948 0
|
Android开发
自定义View利用手势检测实现图片放大缩小
上一节我们是通过重写自定义View的onTouchEvent方法来实现我们的图片放大缩小功能的,我们也发现现在app中,图片预览功能很常见的,用户基本已经形成条件反射,看到小图,点击看大图,看到大图两个手指开始进行放大,放大后,开始移动到指定部位,实际上,Android系统本身也是有手势检测这个类来帮助我们实现相关功能的。
1241 0
|
JavaScript Android开发 前端开发