多点触控图片 自定义View

来源:互联网 发布:超级基因优化液好看吗 编辑:程序博客网 时间:2024/05/29 17:28

多点触控图片  查看自定义View

详情看hongyang大牛的视频

import android.content.Context;import android.graphics.Matrix;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewTreeObserver;import android.widget.ImageView;/** * Created by warden on 16/3/24. * <p/> * 1.初始化,缩小放大图片 {@link #onGlobalLayout} */public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, View.OnTouchListener{    /**     * 控制初始化操作的变量     */    private boolean isFirst;    /**     * 初始化显示的值,also 显示最小值     */    private float mInitScale;    /**     * 双击放大的值     */    private float mMidScale;    /**     * 显示的最大值     */    private float mMaxScale;    /**     * 矩阵     */    private Matrix mScaleMartix;    /**     * 捕获多地触控的缩放比例     */    private ScaleGestureDetector mScaleGestureDetector;    /**     * 缩放监听     */    private SimpleOnScaleGesture mOnScaleGesture;    //------------ 分割线    /**     * 记录上一次多点触控的 数量     */    private int mLastPointerCount;    /**     * 记录上一次手指触控的中心点 x 坐标     */    private float mLastX;    /**     * 记录上一次手指触控的中心点 y 坐标     */    private float mLastY;    /**     * 获取系统的值,用于比较是移动的值达到了 移动图片的需求     */    private int mTouchSlop;    private boolean isCanDrag;    //检查用    /**     * 检查是否 left 或者 right     */    private boolean isCheckLeftAndRight;    /**     * 检查是否  top or bottom     */    private boolean isCheckTopBottom;    //------双击放大    private GestureDetector mGestureDetector;    /**     * 用户已经在双击了     */    private boolean isAutoScale;    public ZoomImageView(Context context)    {        this(context, null);    }    public ZoomImageView(Context context, AttributeSet attrs)    {        this(context, attrs, 0);    }    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr)    {        super(context, attrs, defStyleAttr);        mScaleMartix = new Matrix();        setScaleType(ScaleType.MATRIX);        mScaleGestureDetector = new ScaleGestureDetector(context, mOnScaleGesture = new SimpleOnScaleGesture());        setOnTouchListener(this);        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()        {            @Override            public boolean onDoubleTap(MotionEvent e)            {                if (isAutoScale)                    return true;                //获取点击坐标                float x = e.getX();                float y = e.getY();//                //获取当前的缩放比例//                //如果小于 缩放中心值,就放大到中心值//                if (getScale() < mMidScale)//                {//                    mScaleMartix.postScale(mMidScale / getScale(), mMidScale / getScale(), x, y);//                } else//                {//                    //反之就是大于等于中心值,缩小//                    mScaleMartix.postScale(mInitScale / getScale(), mInitScale / getScale(), x, y);//                }//                setImageMatrix(mScaleMartix);                //获取当前的缩放比例                //如果小于 缩放中心值,就放大到中心值                if (getScale() < mMidScale)                {                    postDelayed(new AutoScaleRunnable(mMidScale, x, y), 18);                    isAutoScale = true;                } else                {                    //反之就是大于等于中心值,缩小                    postDelayed(new AutoScaleRunnable(mInitScale, x, y), 18);                    isAutoScale = true;                }                return true;            }        });    }    private class AutoScaleRunnable implements Runnable    {        /**         * 缩放的目标值         */        private float mTargetScale;        private float x;        private float y;        private final float BIGGER = 1.07f;        private final float SMALL = 0.93f;        private float tmpScale;        public AutoScaleRunnable(float mTargetScale, float x, float y)        {            this.mTargetScale = mTargetScale;            this.x = x;            this.y = y;            //比目标小 就放大            if (getScale() < mTargetScale)            {                tmpScale = BIGGER;            } else if (getScale() > mTargetScale)            {                //比目标大就缩小                tmpScale = SMALL;            }        }        @Override        public void run()        {            mScaleMartix.postScale(tmpScale, tmpScale, x, y);            checkBorderAndCenterWhenScale();            setImageMatrix(mScaleMartix);            float currentScale = getScale();            if ((tmpScale > 1.0f && currentScale < mTargetScale)                    || (tmpScale < 1.0f && currentScale > mTargetScale))            {                postDelayed(this, 18);            } else            {                //达到效果                float scale = mTargetScale / currentScale;                mScaleMartix.postScale(scale, scale, x, y);                checkBorderAndCenterWhenScale();                setImageMatrix(mScaleMartix);                isAutoScale = false;            }        }    }    /**     * 添加到绘图     */    @Override    protected void onAttachedToWindow()    {        super.onAttachedToWindow();        getViewTreeObserver().addOnGlobalLayoutListener(this);    }    /**     * 移除绘图     */    @Override    protected void onDetachedFromWindow()    {        super.onDetachedFromWindow();        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)        {            getViewTreeObserver().removeOnGlobalLayoutListener(this);        } else        {            getViewTreeObserver().removeGlobalOnLayoutListener(this);        }    }    /**     * 绘图完成,全局的布局完成之后会回调这个方法     * <p/>     * OnGlobalLayoutListener     */    @Override    public void onGlobalLayout()    {        if (isFirst) return;        /**         * 获取控件的宽度和高度,         * 为什么没有使用屏幕的宽度和高度.         * 比如你又一个ToolBar         */        int width = getWidth();        int height = getHeight();        //获取图片        Drawable d = getDrawable();        if (d == null) return;        int dw = d.getIntrinsicWidth();        int dh = d.getIntrinsicHeight();        float scale = 0;        //需要缩小        if (dw > width || dh > height)        {            float w = width * 1.0f / dw;            float h = height * 1.0f / dh;            scale = Math.min(w, h);        }        //放大        if (dw < width || dh < height)        {            float w2 = width * 1.0f / dw;            float h2 = height * 1.0f / dh;            scale = Math.min(w2, h2);        }        //初始化值        mInitScale = scale;        mMidScale = scale * 2;        mMaxScale = scale * 4;        //移动坐标        int dx = getWidth() / 2 - dw / 2;        int dy = getHeight() / 2 - dh / 2;        //移动到中心点        mScaleMartix.postTranslate(dx, dy);        //放大缩小 后两个参数为 缩放中心点的坐标        mScaleMartix.postScale(mInitScale, mInitScale, width / 2, height / 2);        setImageMatrix(mScaleMartix);        isFirst = true;    }    @Override    public boolean onTouch(View v, MotionEvent event)    {        if (mGestureDetector.onTouchEvent(event)) return true;        //将触摸时间传递给 多点触控进行处理        mScaleGestureDetector.onTouchEvent(event);        //移动代码        float x = 0;        float y = 0;        //获取触控点        int pointerCount = event.getPointerCount();        //遍历触控点        for (int i = 0; i < pointerCount; i++)        {            x += event.getX(i);            y += event.getY(i);        }        // x=x/pointerCount        x /= pointerCount;        y /= pointerCount;        //触控数量发生了改变        if (mLastPointerCount != pointerCount)        {            //记录 数量            mLastX = x;            mLastY = y;            mLastPointerCount = pointerCount;            isCanDrag = false;        }        RectF rectF = getMatrixRectF();        switch (event.getAction())        {            case MotionEvent.ACTION_DOWN:                //这个状态下不希望 父控件拦截我们的事件                if (rectF.width() > getWidth() + 0.01 || rectF.height() > getHeight() + 0.01)                {                    if (getParent() != null)                        getParent().requestDisallowInterceptTouchEvent(true);                }                break;            case MotionEvent.ACTION_MOVE:                //这个状态下不希望 父控件拦截我们的事件                if (rectF.width() > getWidth() + 0.01 || rectF.height() > getHeight() + 0.01)                {                    if (getParent() != null)                        getParent().requestDisallowInterceptTouchEvent(true);                }                //计算偏移量                //当前中心点的位置 - 记录中心点的位置                float dx = x - mLastX;                float dy = y - mLastY;                if (!isCanDrag)                {                    isCanDrag = isMoveAction(dx, dy);                }                if (isCanDrag)                {                    //图片的移动                    // RectF rectF = getMatrixRectF();                    if (getDrawable() != null)                    {                        isCheckLeftAndRight = isCheckTopBottom = true;                        //如果 下雨空间的宽度,不允许横向移动                        if (rectF.width() < getWidth())                        {                            //这种情况就不需要检查了, 应为图片已经小宇空间的                            isCheckLeftAndRight = false;                            dx = 0;                        }                        // 同理,条件不满足不允许纵向移动                        if (rectF.height() < getHeight())                        {                            isCheckTopBottom = false;                            dy = 0;                        }                        mScaleMartix.postTranslate(dx, dy);                        checkBorderWhenTranslate();                        setImageMatrix(mScaleMartix);                    }                }                mLastX = x;                mLastY = y;                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                mLastPointerCount = 0;                break;        }        return true;    }    private void checkBorderWhenTranslate()    {        RectF rectF = getMatrixRectF();        float deltaX = 0;        float deltaY = 0;        int width = getWidth();        int height = getHeight();        if (rectF.top > 0 && isCheckTopBottom)        {            deltaY = -rectF.top;        }        if (rectF.bottom < height && isCheckTopBottom)        {            deltaY = height - rectF.bottom;        }        if (rectF.left > 0 && isCheckLeftAndRight)        {            deltaX = -rectF.left;        }        if (rectF.right < width && isCheckLeftAndRight)        {            deltaX = width - rectF.right;        }        mScaleMartix.postTranslate(deltaX, deltaY);    }    /**     * 判断是否达到了移动图片的 需求     *     * @param dx     * @param dy     * @return     */    private boolean isMoveAction(float dx, float dy)    {        return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;    }    /**     * 获取图片的缩放值     *     * @return     */    public float getScale()    {        float[] values = new float[9];        mScaleMartix.getValues(values);        return values[Matrix.MSCALE_X];//理论上x 和 y是一样的 TODO断点    }    /**     * 获取图片放大 或者 缩小以后的宽和高,以及left,right,top,bottom等属性     *     * @return     */    public RectF getMatrixRectF()    {        RectF rectF = new RectF();        Drawable d = getDrawable();        if (d != null)        {            rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());            mScaleMartix.mapRect(rectF);        }        return rectF;    }    /**     * 缩放监听     */    private class SimpleOnScaleGesture implements ScaleGestureDetector.OnScaleGestureListener    {        /**         * 缩放 进行中         *         * @param detector         * @return         */        @Override        public boolean onScale(ScaleGestureDetector detector)        {            if (getDrawable() == null) return true;//return true ?//TODO            //缩放值            float scaleFactor = detector.getScaleFactor();            //缩放区间 mInitScale ~ mMaxScale            //获取当前的 Scale * 缩放比例 在进行判断            float scale = getScale();            //当前的缩放值 没有 放大到 最大值 并且 缩放比例 大于 1.0,证明想放大,批准            //当前的缩放值 没有 缩小到 最小值 且   缩小比例 小  1.0 ,批准            if ((scale < mMaxScale && scaleFactor > 1.0f) || (scale > mInitScale && scaleFactor < 1.0f))            {                //缩小比例超过了 最小值                if (scale * scaleFactor < mInitScale)                {                    //让他等于最小值                    //mInitScale=scale*scaleFactor 最小值                    //mInitScale 和 scale 都是固定的,而scaleFactor是手势改变的。                    scaleFactor = mInitScale / scale;                }                //超过最大值                if (scale * scaleFactor > mMaxScale)                {                    scaleFactor = mMaxScale / scale;                }                Log.d("warden", this.getClass().getName() + "scaleFactor:" + scaleFactor);                mScaleMartix.postScale(scaleFactor, scaleFactor, detector.getFocusX() / 2, detector.getFocusY() / 2);                checkBorderAndCenterWhenScale();                setImageMatrix(mScaleMartix);            }            return true;        }        /**         * 缩放开始时         *         * @param detector         * @return         */        @Override        public boolean onScaleBegin(ScaleGestureDetector detector)        {            return true;        }        /**         * 缩放结束         *         * @param detector         */        @Override        public void onScaleEnd(ScaleGestureDetector detector)        {        }    }    private void checkBorderAndCenterWhenScale()    {        RectF rect = getMatrixRectF();        float deltaX = 0;        float deltaY = 0;        int width = getWidth();        int height = getHeight();        //万恶的数学        if (rect.width() >= width)        {            if (rect.left > 0)            {                deltaX = -rect.left;            }            if (rect.right < width)            {                deltaX = width - rect.right;            }        }        if (rect.height() >= height)        {            if (rect.top > 0)            {                deltaY = -rect.top;            }            if (rect.bottom < height)            {                deltaY = height - rect.bottom;            }        }        //居中        if (rect.width() < width)        {            deltaX = width / 2 - rect.width() / 2 - rect.left;//        deltaX=width/2-rect.right+rect.width()/2;        }        if (rect.height() < height)        {            deltaY = height / 2 - rect.bottom + rect.height() / 2;        }        //TODO 下和右边?这种算法 ?        mScaleMartix.postTranslate(deltaX, deltaY);    }}




0 0
原创粉丝点击