美文网首页
android通用缩放滚动容器——ZoomScrollLayou

android通用缩放滚动容器——ZoomScrollLayou

作者: 流沙无形 | 来源:发表于2019-05-22 16:56 被阅读0次

ZoomScrollLayout是一个可以对任意子view进行缩放、滚动查看的控件。类似于图片查看器,支持任何类型的view。

先看效果:


222.gif

上代码:


import android.content.Context;

import android.util.AttributeSet;

import android.view.*;

import android.widget.RelativeLayout;

import com.orhanobut.logger.Logger;

/**

* Created by wg on 2017/4/21.

*/

public class ZoomScrollLayout extends RelativeLayout implements ScaleGestureDetector.OnScaleGestureListener {

    private ScaleGestureDetector mScaleDetector;

    private GestureDetector mGestureDetector;

    private static final float MIN_ZOOM = 0.3f;

    private static final float MAX_ZOOM = 3.0f;

    private Integer mLeft, mTop, mRight, mBottom;

    private int centerX, centerY;

    private float mLastScale = 1.0f;

    private float totleScale = 1.0f;

    // childview

    private View mChildView;

    // 拦截滑动事件

    float mDistansX, mDistansY, mTouchSlop;

    private enum MODE {

        ZOOM, DRAG, NONE

    }

    private MODE mode;

    boolean touchDown;

    public ZoomScrollLayout(Context context) {

        super(context);

        init(context);

    }

    public ZoomScrollLayout(Context context, AttributeSet attrs) {

        super(context, attrs);

        init(context);

    }

    public ZoomScrollLayout(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        init(context);

    }

    public void init(Context context) {

        mScaleDetector = new ScaleGestureDetector(context, this);

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

            @Override

            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

                if (mode == MODE.DRAG) {

                    if (mChildView == null) {

                        mChildView = getChildAt(0);

                        centerX = getWidth() / 2;

                        centerY = getHeight() / 2;

                    }

                    if (mLeft == null) {

                        mLeft = mChildView.getLeft();

                        mTop = mChildView.getTop();

                        mRight = mChildView.getRight();

                        mBottom = mChildView.getBottom();

                    }

                    // 防抖动

                    if (touchDown) {

                        touchDown = false;

                        return true;

                    }

                    Logger.i("distanceX=" + distanceX + ";distanceY=" + distanceY);

                    Logger.i("mLeft=" + mLeft + ";mTop=" + mTop);

                    mLeft = mLeft - (int) distanceX;

                    mTop = mTop - (int) distanceY;

                    mRight = mRight - (int) distanceX;

                    mBottom = mBottom - (int) distanceY;

                    mChildView.layout(mLeft, mTop, mRight, mBottom);

                }

                return true;

            }

            @Override

            public boolean onDown(MotionEvent e) {

                touchDown = true;

                return super.onDown(e);

            }

        });

        // 系统最小滑动距离

        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

    }

    @Override

    public boolean onInterceptTouchEvent(MotionEvent e) {

        int action = e.getActionMasked();

        int currentX = (int) e.getX();

        int currentY = (int) e.getY();

        switch (action) {

            case MotionEvent.ACTION_DOWN:

                //记录上次滑动的位置

                mDistansX = currentX;

                mDistansY = currentY;

                //将当前的坐标保存为起始点

                mode = MODE.DRAG;

                break;

            case MotionEvent.ACTION_MOVE:

                if (Math.abs(mDistansX - currentX) >= mTouchSlop || Math.abs(mDistansY - currentY) >= mTouchSlop) { //父容器拦截

                    return true;

                }

                break;

            //指点杆保持按下,并且进行位移

            //有手指抬起,将模式设为NONE

            case MotionEvent.ACTION_UP:

            case MotionEvent.ACTION_POINTER_UP:

                mode = MODE.NONE;

                break;

        }

        return super.onInterceptTouchEvent(e);

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        mScaleDetector.onTouchEvent(event);

        mGestureDetector.onTouchEvent(event);

        return true;

    }

    @Override

    public boolean onScale(ScaleGestureDetector scaleGestureDetector) {

        Logger.i("MotionEvent.onScale");

        if (mode == MODE.ZOOM) {

            float scaleFactor = scaleGestureDetector.getScaleFactor();

            float tempScale = mLastScale * scaleFactor;

            if (tempScale <= MAX_ZOOM && tempScale >= MIN_ZOOM) {

                totleScale = tempScale;

                applyScale(totleScale);

            }

        }

        return false;

    }

    /**

    * 执行缩放操作

    */

    public void applyScale(float scale) {

        mChildView.setScaleX(scale);

        mChildView.setScaleY(scale);

    }

    @Override

    public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {

        Logger.i("MotionEvent.onScaleBegin");

        mode = MODE.ZOOM;

        if (mode == MODE.ZOOM) {

            if (mChildView == null) {

                mChildView = getChildAt(0);

                centerX = getWidth() / 2;

                centerY = getHeight() / 2;

            }

            mLeft = mChildView.getLeft();

            mTop = mChildView.getTop();

            mRight = mChildView.getRight();

            mBottom = mChildView.getBottom();

        }

        return true;

    }

    @Override

    public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {

        mLastScale = totleScale;

    }

}

注意:ZoomScrollLayout 和ScrollView一样,只能有一个子View

相关文章

网友评论

      本文标题:android通用缩放滚动容器——ZoomScrollLayou

      本文链接:https://www.haomeiwen.com/subject/tbbuzqtx.html