我是靠谱客的博主 英俊手套,最近开发中收集的这篇文章主要介绍Android手势检测 带你打造支持图片缩放、平移预览(下),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前面一片博客讲解和支持图片缩放的预览,但是那个缩放的缩放中心是固定的都是屏幕中心,这显然不能满足用户的需求,我们需要的是缩放焦点能够随着手势变化,还能够双击缩放,并且可以平移,本片博客就带大家来实现这些功能。这篇文章是基于 Android手势检测 带你打造图片缩放预览(上)的。


首先给出效果图:

贴出源代码,然后再对每个部分进行分析

class ScaleMoveImageViewer extends ImageView implements OnTouchListener,OnScaleGestureListener{
private ScaleGestureDetector sgc;
private GestureDetector gd;
private float SOURCE_SCALE;
private	Matrix matrix=new Matrix();
private float[] values=new float[9];
private boolean once=true;
private float preX,preY,currentX,currentY;
private int prePointerCount;
private static final int REQUESTCODE_BIGER=1;
private static final int REQUESTCODE_SMALLER=2;
private static final float BIGER_TMP_SCALE=1.06f;
private static final float SMALLER_TMP_SCALE=0.94f;
private static final float MAX_SCALE=4.0F;
private static final float MIN_SCALE=0.2F;
public ScaleMoveImageViewer(Context context) {
this(context,null);
}
public ScaleMoveImageViewer(Context context, AttributeSet attrs) {
super(context, attrs);
super.setScaleType(ScaleType.MATRIX);
this.setOnTouchListener(this);
sgc=new ScaleGestureDetector(context, this);
gd=new GestureDetector(context, new SimpleOnGestureListener(){
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i("TAG","onDoubleTap");
float x=e.getX();
float y=e.getY();
setDobleTapScale(x, y);
return true;
}
});
}
//手指缩放
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor=detector.getScaleFactor();
float currentScale=getScale();//相对原图的缩放比例
if(currentScale>MAX_SCALE && scaleFactor<1.0f || currentScale<MIN_SCALE
&& scaleFactor>1.0f || currentScale<MAX_SCALE && currentScale>MIN_SCALE){
matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
}
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
return true;
}
//移动
@Override
public boolean onTouch(View v, MotionEvent event) {
currentX=0;currentY=0;
int pointerCount=event.getPointerCount();
for(int i=0;i<pointerCount;i++){
currentX+=event.getX();
currentY+=event.getY();
}
currentX/=pointerCount;
currentY/=pointerCount;
if (pointerCount!=prePointerCount) {
preX=currentX;
preY=currentY;
prePointerCount=pointerCount;
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx=currentX-preX;
float dy=currentY-preY;
ImagePositonManager.setMovePosition(getDrawable(), matrix, dx, dy, getWidth(), getHeight());
setImageMatrix(matrix);
preX=currentX;
preY=currentY;
break;
case MotionEvent.ACTION_UP://有多根手指触摸屏幕时,只有当所有的手指抬起时这里才执行
prePointerCount=0;
break;
}
gd.onTouchEvent(event);
return sgc.onTouchEvent(event);
}
//双击缩放
public void setDobleTapScale(float px,float py){
float currectScale=getScale();
if(currectScale<SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_BIGER), 10);
}
if(currectScale==SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(MAX_SCALE-1, px, py,REQUESTCODE_BIGER), 10);
}
if(currectScale>SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_SMALLER), 10);
}
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
private class AutoScaleRunnable implements Runnable{
float targetScale=0;
float px=0;
float py=0;
int requestCode=0;
public AutoScaleRunnable(float targetScale,float px,float py,int requestCode){
this.targetScale=targetScale;
this.px=px;
this.py=py;
this.requestCode=requestCode;
}
@Override
public void run() {
if(requestCode==REQUESTCODE_BIGER){
matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
float currentScale = getScale();
if (currentScale<targetScale) {
ScaleMoveImageViewer.this.postDelayed(this, 10);
}else {
while(getScale()!=targetScale){
matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
}
}
else if (requestCode==REQUESTCODE_SMALLER) {
matrix.postScale(SMALLER_TMP_SCALE, SMALLER_TMP_SCALE, px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
float currentScale = getScale();
if(currentScale>targetScale){
ScaleMoveImageViewer.this.postDelayed(this, 10);
}else {
while(getScale()!=targetScale){
matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
}
}
}
}
@Override
protected void onDraw(Canvas canvas) {
if(once){
matrix=getImageMatrix();
once=false;
Drawable drawable=getDrawable();
//获取图片的宽和高
int dw=drawable.getIntrinsicWidth();
int dh=drawable.getIntrinsicHeight();
int w=getWidth();
int h=getHeight();
float scale=Math.min(1.0f*w/dw, 1.0f*h/dh);
SOURCE_SCALE=scale;
matrix.postTranslate(w/2-dw/2, h/2-dh/2);
matrix.postScale(scale, scale, w/2, h/2);
setImageMatrix(matrix);
}
super.onDraw(canvas);
}
private float getScale(){
matrix.getValues(values);
return values[Matrix.MSCALE_X];
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
}
第二部分工具类,来控制图片的位置
public class ImagePositonManager {
//缩放图片时控制其显示位置
public static void setShowPosition(Drawable drawable,Matrix matrix,int w,int h){
RectF rectF=new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
float rw=rectF.width();
float rh=rectF.height();
float moveX=0,moveY=0;
if(rw<=w){
moveX=w/2-rw/2-rectF.left;
}
if (rh<=h) {
moveY=h/2-rh/2-rectF.top;
}
if(rw>w && rectF.left>0){
moveX=-rectF.left;
}
if(rw>w && rectF.right<w){
moveX=w-rectF.right;
}
if(rh>h && rectF.top>0){
moveY=-rectF.top;
}
if(rh>h && rectF.bottom<h){
moveY=h-rectF.bottom;
}
matrix.postTranslate(moveX, moveY);
}
//移动图片时控制显示位置
public static void setMovePosition(Drawable drawable,Matrix matrix,float dx,float dy,int w,int h){
RectF rectF=new RectF(0,0,drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
matrix.mapRect(rectF);
float rw=rectF.width();
float rh=rectF.height();
if(rw>w && rectF.left+dx<=0 && rectF.right+dx>=w){
matrix.postTranslate(dx, 0);
}
if(rh>h && rectF.top+dy<=0 && rectF.bottom+dy>=h){
matrix.postTranslate(0, dy);
}
}
}


最后就是主函数和布局文件,这个很简单不贴代码了

现在对每个部分进行分析
//移动
@Override
public boolean onTouch(View v, MotionEvent event) {
currentX=0;currentY=0;
int pointerCount=event.getPointerCount();
for(int i=0;i<pointerCount;i++){
currentX+=event.getX();
currentY+=event.getY();
}
currentX/=pointerCount;
currentY/=pointerCount;
if (pointerCount!=prePointerCount) {
preX=currentX;
preY=currentY;
prePointerCount=pointerCount;
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx=currentX-preX;
float dy=currentY-preY;
ImagePositonManager.setMovePosition(getDrawable(), matrix, dx, dy, getWidth(), getHeight());
setImageMatrix(matrix);
preX=currentX;
preY=currentY;
break;
case MotionEvent.ACTION_UP://有多根手指触摸屏幕时,只有当所有的手指抬起时这里才执行
prePointerCount=0;
break;
}
gd.onTouchEvent(event);
return sgc.onTouchEvent(event);
}
关于图片的移动,代码挺简单相信大家都能看的懂,但是有几点需要注意的地方
1、图片的一定是一个多点操作,所以触摸点的位置我们去所有手指位置的平均值
2、要特别注意这段代码
if (pointerCount!=prePointerCount) {
preX=currentX;
preY=currentY;
prePointerCount=pointerCount;
}当触摸点的数量发生变化时,即有手指抬起或按下时,这是我们为了保证图片不移动,需要将前一次的x,y值赋值为当前的x,y值。如果不这样做,当我们的手放在屏幕上不动,r然后突然抬起(按下)一根手指,这是照片就会移动。

public void setDobleTapScale(float px,float py){
float currectScale=getScale();
if(currectScale<SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_BIGER), 10);
}
if(currectScale==SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(MAX_SCALE-1, px, py,REQUESTCODE_BIGER), 10);
}
if(currectScale>SOURCE_SCALE){
ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_SMALLER), 10);
}
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
private class AutoScaleRunnable implements Runnable{
float targetScale=0;
float px=0;
float py=0;
int requestCode=0;
public AutoScaleRunnable(float targetScale,float px,float py,int requestCode){
this.targetScale=targetScale;
this.px=px;
this.py=py;
this.requestCode=requestCode;
}
@Override
public void run() {
if(requestCode==REQUESTCODE_BIGER){
matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
float currentScale = getScale();
if (currentScale<targetScale) {
ScaleMoveImageViewer.this.postDelayed(this, 10);
}else {
while(getScale()!=targetScale){
matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
}
}
else if (requestCode==REQUESTCODE_SMALLER) {
matrix.postScale(SMALLER_TMP_SCALE, SMALLER_TMP_SCALE, px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
float currentScale = getScale();
if(currentScale>targetScale){
ScaleMoveImageViewer.this.postDelayed(this, 10);
}else {
while(getScale()!=targetScale){
matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py);
ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight());
setImageMatrix(matrix);
}
}
}
}
}
双击缩放,不能突然一下子就变大或变小,这样用户体验效果很差,所以我们做成了一个动画效果,这里我们主要来讲解AutoScaleRunnable,当用户双击图片后,
AutoScaleRunnable 会执行,注意我们matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py);BIGER_TMP_SCALE=是一个接近1  比1大一点的数,所以我们每一次都是只缩放一点点,通过反复的执行run方法就达到了缩放到最终目标大小targetScale,如何反复呢,我们通过这句代码来实现
if (currentScale<targetScale) {
ScaleMoveImageViewer.this.postDelayed(this, 10);
}

代码分析到这里已经结束了!








最后

以上就是英俊手套为你收集整理的Android手势检测 带你打造支持图片缩放、平移预览(下)的全部内容,希望文章能够帮你解决Android手势检测 带你打造支持图片缩放、平移预览(下)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部