hga010手机版网址

手机如何下hga010图形操作系列 —(1)手势缩放图片功能

十月 1st, 2018  |  手机如何下hga010

概述

品类开支中,大家APP开发一般还见面为此到上污染图片,比如是上传了上下一心的生活照,然后于某界面处查看上传的图样,这时候一般在斯查看详情的界面,会发出手势放大缩小功能,手势进行盘功能,双击放大图片等等。

偏偏,我原先也有亟待以此要求的当儿,而且特别指出了使用手势进行图纸的选项功能。

乃我翻看了BiliBili的开源库:

Boxing

image

以了这个Demo后发觉里头有手势控制图片大小,手势控制图转等力量,看了代码后自发觉BiliBili这个demo中呢是用了第三着的库房:

RotatePhotoView

image

image

咱得以看来介绍:在PhotoView的功底及添加了经二个手指来转图片的作用,所以是库房又是为此了别样的老三方库:

PhotoView

咱得以看到是PhotoView的堆栈发生一万大多单star了。说明还是生是的。

从而经过这次。我便来拘禁PhotoView如何进行落实那么基本上力量。


正题

大家以羁押正文之前若对Matrix不是坏了解的,可以先瞧:
android matrix
最咸道详解与进阶(完整首)
Android
Matrix
Float中之那些常量
Infinity、NaN

本来是怀念直接将在PhotoView
的源码,贴上源码分析一个个切实可行的职能,但是坐源码是考虑到不少功力,所以发生无数代码量,而且最多看在大乱,所以自己的方案是一直自己写个demo,然后因我们如果上课的成效,仿照PhotoView的源码,在融洽一个个现实的效益demo分别实现。所以本文自先来贯彻实现基于手势来落实图片的缩放功能:

1.添加图片布局

PhotoView是累了ImageView,然后径直当layout中运用<PhotoView/>,为了重新便宜之授课,我虽直接或者使用<ImageView/>,然后叫大家张是怎么样对ImageView做拍卖实现相应的力量。

事先添补加我们只要之demo布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.dialog.photoviewdemo.MainActivity">

    <ImageView
        android:id="@+id/photo_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"
        />

</LinearLayout>

2. 对图片设置手势监听

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //对我们的ImageView设置相应的一张图片
    ivPhoto = (ImageView) findViewById(R.id.photo_view);
    drawable = ContextCompat.getDrawable(this, R.mipmap.ic_launcher);
    ivPhoto.setImageDrawable(drawable);

    //对我们的ImageView设置触摸事件监听,并且把监听交给了GestureDetector.
    ivPhoto.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
           return scaleGestureDetector.onTouchEvent(event);
        }
    }); 

    //GestureDetector的实例生成
    scaleGestureDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.OnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scaleFactor = detector.getScaleFactor();
            float focusX = detector.getFocusX();
            float focusY = detector.getFocusY();
            if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) {
                return false;
            }

            mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
            if(checkMatrixBounds()) {
                ivPhoto.setImageMatrix(getDrawMatrix());
            }

            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
        }
    });
}    

依据地方的代码我们同样来分析:

1.GestureDetector和ScaleGestureDetector

当用户触摸屏幕的时,会发出不少手势,例如down,up,scroll,filing等等。
诚如情形下,我们懂得View类有只View.OnTouchListener内部接口,通过重新写他的onTouch(View
v, MotionEvent
event)方法,我们可以处理局部touch事件,但是是法极其过粗略,如果欲处理局部犬牙交错的手势,用之接口就会大辛苦(因为咱们只要和谐根据用户触摸的轨道去看清是啊手势)。
Android
sdk给咱们提供了GestureDetector(Gesture:手势Detector:识别)类,通过这个类似我们得辨认很多之手势,主要是透过他的onTouchEvent(event)方法成功了不同手势的辨认。虽然他能辨别手势,但是差之手势而怎么处理,应该是提供给程序员实现的。
实际现实可拘留即首文章,写的很详细:用户手势检测-GestureDetector使用详解

如若此我们因为做的效用是经过手势来缩放图片,所以我们即便假设监听二单手指缩放动作,所以我们采取的是ScaleGestureDetector

ScaleGestureDetector介绍:</br>用于拍卖缩放的工具类,用法与GestureDetector类似,都是由此onTouchEvent()关联相应的MotionEvent的。使用该类时,用户需要传入一个圆的连年不停地motion事件(包含ACTION_DOWN,ACTION_MOVE和ACTION_UP事件)。

咱看上面的代码就见面发觉ScaleGestureDetector有三个点子:

@Override
public boolean onScale(ScaleGestureDetector detector) {
    return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
    return true;
}

@Override
public void onScaleEnd(ScaleGestureDetector detector) {}

onScaleBegin:缩放开始会实施之方法,但是我们发现此法子需要回到一个Boolean价值,这个价值决定是否处理后的缩放事件,返回false常常,不见面执行onScale()

onScaleEnd:缩放结束执行

onScale:缩放时候实施的法,用来做实际的逻辑处理。

我们具体来看望onScale方法:

@Override
public boolean onScale(ScaleGestureDetector detector) {
    return true;
}

咱得以看来这里是返Boolean值,那这里归true和false有啊界别吗。

float scaleFactor = detector.getScaleFactor();

咱们好透过是方法赢得到缩放因子,缩放因子会冲你的手势的变大会越来越不行,如果你回去了true,那就是印证这次的缩放行为就是已经终结了,如果你回到了false,那即便证明没有收,然后缩放因子越来越好。

public boolean onScale(ScaleGestureDetector detector) {  
    if(detector.getScaleFactor()< 2){  
        return false;  
    }  
    return true;  
}  

image

俺们可见到,我们装了超越2才返回true,(前提二单手指头是举行扩坏手势)那么缩放因子就会一直变充分到2,才见面看这次缩放行为了了,就再也从1初始了。

(PS:如果二独手指头做缩小的手势,那么是缩放因子就见面低于1,如果回去false,那么即便会见自1开头更粗。)

2.图片初始化呈现状态

而我们现在之ImageView设置的是全屏,我们发出只稍图,ImageView设置了图片后是这般的:

image

俺们发现默认是当左上角,而且为我们的ImageView设置的是全屏,而图片以特意有些,这样的开端显现方式特别无谐和。
因此我们要做如下操作:
<1>把图片居中显示。
<2>图片以及ImageView相适应(我们这里是把图纸适当的放开,来适应这样好的ImageView.)

就此呢就是我们地方提到了之代码:

drawableWidth = drawable.getIntrinsicWidth();
drawableHeight = drawable.getIntrinsicHeight();

viewWidth = ivPhoto.getWidth() - ivPhoto.getPaddingLeft() - ivPhoto.getPaddingRight();
viewHeight = ivPhoto.getHeight() - ivPhoto.getPaddingLeft() - ivPhoto.getPaddingRight();
RectF mTempScr = new RectF(0, 0, drawableWidth, drawableHeight);
RectF mTempDst = new RectF(0, 0, viewWidth, viewHeight);
mBaseMatrix.setRectToRect(mTempScr, mTempDst, Matrix.ScaleToFit.CENTER);
mDrawableMatrix.set(mBaseMatrix);
ivPhoto.setImageMatrix(mDrawableMatrix);

获得图片的实际宽高和ImageView用来显示图片的充盈高我不怕非多说了。重点是setRectToRect方法:

public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf)

拿rect变换成rect,通过stf参数来决定。

ScaleToFit 有如下四只价:
FILL: 可能会见变矩形的长宽比,保证易和对象矩阵长宽一致。
START:保持坐标变换前矩形的长宽比,并无限酷限度的填充变换后的矩形。至少发生一面跟目标矩形重叠。左上对齐。
CENTER:
保持坐标变换前矩形的长宽比,并极老限度的填充变换后的矩形。至少发生一面与对象矩形重叠。
END:保持坐标变换前矩形的丰富宽比,并尽可怜限度的填充变换后的矩形。至少发生一面与对象矩形重叠。右下本着一头。

这边用谷歌的api demo的图作为例子:

image

咱们挺明朗发现,那个蓝色的小球的变不纵是咱们怀念使之变化么,并且我们是如从中,所以用之凡Matrix.ScaleToFit.CENTER

咱俩看下我们最终之成效:

image

3.图实时手势缩放

咱俩面前都清楚了。手势变化之上会接触onScale艺术,所以我们而拿图纸的实际的加大缩小的逻辑在onScale里头即可。

@Override
public boolean onScale(ScaleGestureDetector detector) {
    //缩放因子
    float scaleFactor = detector.getScaleFactor();
    //返回组成该手势的两个触点的中点在组件上的x和y轴坐标,单位为像素。
    float focusX = detector.getFocusX();
    float focusY = detector.getFocusY();
    //如果为nan或者无强大,则无效
    if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) {
        return false;
    }
    //进行缩放,传入x轴缩放比例,y轴缩放比例,缩放中心点的x和y值
    mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
    if(checkMatrixBounds()) {
        ivPhoto.setImageMatrix(getDrawMatrix());
    }

    return true;
}

世家应看到了自当即边有只checkMatrixBounds道,本来其实只有的缩放就是先postScale然后以直setImageMatrix哪怕足以了。

mSuppMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY);
ivPhoto.setImageMatrix(getDrawMatrix());

只是如此产生啊坏的地方吗。我来具体和大家说下:

  • 缩放跟手势的次只触点的基本关于,而且图片会随着大样子移动

image

论自己是次只红点分别是自我之手指头,然后不歇的缩小图片动作,图片不仅易多少,而且会趁着大样子开活动。放大则反。这不是咱怀念使之,我们想只要的凡如出一辙是举行缩放,同时,图片还于中间。

既然如此我们领略了图于举行缩小放大的又还于倒,那咱们便开相应的反方向的移位处理不纵吓了

我们分为二种场面:

1— 图片于缩放过程中,宽或者高没有超ImageView的丰饶或者高:

假如图片再缩放过程遭到并未过ImageView的大大小小。我们才待为图片一直位于中实际即可。所以比较简单:

image

比方算有我们于头里第二只大步里面的初始化后的图纸的开状态后(即与ImageView相适应以居中),相应的图样的矩阵的富裕和高是未是超过ImageView。如果没过,我们可见见我们愿意的图放大和紧缩都是想于正中间的职,但是现在变成了绿色的地方,我们只是需要拿绿色的地方活动到咖啡色的地方即尽。

坐Y轴为例(X轴同样处理):

image

望离开是(实际图片的Top值) – (2分之一的ImageView的可观) +
(2分之一之骨子里图片高度),因为是于上移步,所以Y轴实际上是如果抽值的,所以最终我们若被实际的图形减去相应的距离值即可。

  • 骨子里图片的TOP值(先得相应的莫过于图片的矩阵Rect,在取得top属性):

    private RectF getDisplayRect(Matrix matrix) {
      Drawable d = drawable;
      if (d != null) {
          mDisplayRect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
          matrix.mapRect(mDisplayRect);
          return mDisplayRect;
      }
      return null;
    }
    
  • ImageView的高度:

viewHeight = ivPhoto.getHeight() - ivPhoto.getPaddingLeft() - ivPhoto.getPaddingRight();
  • 实则变化后的图样的惊人(rect也者得到之实际上图片的Rect):
    final float height = rect.height(), width = rect.width();

从而我们这边只有待:

private boolean checkMatrixBounds() {
    RectF rect = getDisplayRect(getDrawMatrix());
    if (rect == null) {
        return false;
    }

    final float height = rect.height(), width = rect.width();
    float deltaX = 0, deltaY = 0;

    if (height <= viewHeight) {
        deltaY = (viewHeight - height) / 2 - rect.top;
    }

    if (width <= viewWidth) {
        deltaX = (viewWidth - width) / 2 - rect.left;
    }

     mSuppMatrix.postTranslate(deltaX, deltaY);
    return true;
}

2— 图片在缩放过程中,宽或者高过ImageView的宽或者高:

本条时段咱们尽管好简单的在核心岗位就好了。因为这不可知反而不受他以中心岗位,为什么????我们现在之图形是一个安卓机器人,比如我本要拓宽它的图片查看她的右眼,我们以右侧上角用手机不充分放大。变成这样:

})ZABEPQ(1V_}6461ME{O{N.png

此时就说了。那我啊还无处理,放大这边就是这作用啊。说之科学的确这样,但是论现在就放大成这个样子了。我压缩它,但是自未是自右边上比赛来进展压缩,而是在左手进行缩小,大家明白我们无开处理,这时候缩小的当儿是本我们手势的职位展开,所以头像在缩小时候先是向左边方向,然后当小于ImageView的万丈时,又突然居中,效果非常不好。

因而我们这个事例手机如何下hga010里处理方式是:如果涨幅都超出ImageView并且图片的右侧边界还不曾起于ImageView中之时光,先随好原来的艺术缩小,当图片的下手边界出现在了ImageView的限制外了,让它逐渐向右边边倒(也尽管是ImageView的升幅

Rect.right的离),这时候就会见大和谐。最后宽度小于ImageView的时居于中间。

PS:还有同栽正好反过来。我们加大的图纸是左眼!!(这时候移动的去是
-rect.left)

用最终成为这样:

private boolean checkMatrixBounds() {
    RectF rect = getDisplayRect(getDrawMatrix());
    if (rect == null) {
        return false;
    }

    final float height = rect.height(), width = rect.width();
    float deltaX = 0, deltaY = 0;

    if (height <= viewHeight) {
        deltaY = (viewHeight - height) / 2 - rect.top;
    } else if (rect.top > 0) {
        deltaY = -rect.top;
    } else if (rect.bottom < viewHeight) {
        deltaY = viewHeight - rect.bottom;
    }


    if (width <= viewWidth) {
        deltaX = (viewWidth - width) / 2 - rect.left;
    } else if (rect.left > 0) {
        deltaX = -rect.left;
    } else if (rect.right < viewWidth) {
        deltaX = viewWidth - rect.right;
    }

    mSuppMatrix.postTranslate(deltaX, deltaY);
    return true;
}

结尾

或老样子,希望大家不要吐槽。有题目留言哈哈。。O(∩_∩)O哈哈~

附上Demo地址:ScaleImageVewDemo

标签:,

Your Comments

近期评论

    功能


    网站地图xml地图