Created
April 23, 2013 02:49
-
-
Save feng88724/5440449 to your computer and use it in GitHub Desktop.
Simple TouchImageView for Android. drag freely.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Activity; | |
import android.content.Context; | |
import android.graphics.Color; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.view.MotionEvent; | |
import android.view.animation.TranslateAnimation; | |
import android.widget.ImageView; | |
/** | |
* 大图浏览 | |
* 实现了多点触碰、拖动、两指缩放、双击缩放 | |
* (需手动指定容器大小setScreenWidth/setScreenHeight,否则仅适合全屏使用) | |
* @author Robot | |
*/ | |
public class TouchView extends ImageView { | |
static final int NONE = 0; | |
static final int DRAG = 1; //拖动中 | |
static final int ZOOM = 2; //缩放中 | |
static final int BIGGER = 3; //放大ing | |
static final int SMALLER = 4; //缩小ing | |
private int mode = NONE; //当前的事件 | |
private float beforeLenght; //两触点距离 | |
private float afterLenght; //两触点距离 | |
private float scale = 0.04f; //缩放的比例 X Y方向都是这个值 越大缩放的越快,但越小越精细 | |
//最大放大倍数(默认原图2倍) | |
private float MAX_SCALE = 2f; | |
//最小缩小倍数(默认原图1/2倍) | |
private float MIN_SCALE = 2f; | |
//显示区域大小 | |
private int screenW; | |
private int screenH; | |
//原始图片大小 | |
private int WIDTH_IMAGE_ORIGINAL; | |
private int HEIGHT_IMAGE_ORIGINAL; | |
private int minWidth; | |
private int minHeight; | |
/*处理拖动 变量 */ | |
private int start_x; | |
private int start_y; | |
private int stop_x ; | |
private int stop_y ; | |
private TranslateAnimation trans; //处理超出边界的动画 | |
private long mTimeOfFirstPointerDown;//前一次按下时间 | |
private long mTimeOfLastClick;//后一次离开时间 | |
public TouchView(Context context) { | |
super(context); | |
init(context); | |
} | |
/** | |
* @param context | |
* @param attrs | |
*/ | |
public TouchView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(context); | |
} | |
private void init(Context context) { | |
this.setPadding(0, 0, 0, 0); | |
this.setScaleType(ScaleType.CENTER_INSIDE); | |
this.setAdjustViewBounds(true); | |
this.setBackgroundColor(Color.alpha(122)); | |
screenW = ((Activity)context).getWindowManager().getDefaultDisplay().getWidth(); | |
screenH = ((Activity)context).getWindowManager().getDefaultDisplay().getHeight(); | |
} | |
/** | |
* 两点间的距离 | |
*/ | |
private float spacing(MotionEvent event) { | |
float x = event.getX(0) - event.getX(1); | |
float y = event.getY(0) - event.getY(1); | |
return (float)Math.sqrt(x * x + y * y); | |
} | |
/** | |
* 处理触碰 | |
*/ | |
@Override | |
public boolean onTouchEvent(MotionEvent event) | |
{ | |
Log.d("TouchView", "Mode Type: " + mode); | |
switch (event.getAction() & MotionEvent.ACTION_MASK) { | |
case MotionEvent.ACTION_DOWN: | |
mTimeOfFirstPointerDown = System.currentTimeMillis(); | |
mode = DRAG; | |
stop_x = (int) event.getRawX(); | |
stop_y = (int) event.getRawY(); | |
start_x = (int) event.getX(); | |
start_y = stop_y - this.getTop(); | |
if(event.getPointerCount()==2) | |
beforeLenght = spacing(event); | |
break; | |
case MotionEvent.ACTION_POINTER_DOWN: | |
mTimeOfFirstPointerDown = mTimeOfLastClick = 0; | |
if (spacing(event) > 10f) { | |
mode = ZOOM; | |
beforeLenght = spacing(event); | |
} | |
break; | |
case MotionEvent.ACTION_UP: | |
if (System.currentTimeMillis() - mTimeOfFirstPointerDown <= 300){ | |
if (mTimeOfLastClick > 0 && System.currentTimeMillis() - mTimeOfLastClick <= 300){//双击 | |
//双击时, 让图片大小超过屏幕 | |
int maxWidth = WIDTH_IMAGE_ORIGINAL; | |
int maxHeight = HEIGHT_IMAGE_ORIGINAL; | |
if(getWidth() <= maxWidth && getHeight() <= maxHeight) { | |
//图片小于屏幕, 自动放大 | |
while(getWidth() < maxWidth || getHeight() < maxHeight) { | |
setScale(scale, BIGGER); | |
} | |
} else { | |
//图片大于屏幕, 自动缩小 | |
while(getWidth() > screenW || getHeight() > screenH) { | |
setScale(scale, SMALLER); | |
} | |
} | |
mTimeOfLastClick = 0; | |
} else {//单击 | |
mTimeOfLastClick = System.currentTimeMillis(); | |
this.performClick(); | |
} | |
} | |
/*判断是否超出范围 并处理*/ | |
int disX = 0; | |
int disY = 0; | |
//图片宽高 | |
if(getHeight() <= screenH) { | |
if(this.getTop() < 0) { | |
int dis = getTop(); | |
this.layout(this.getLeft(), 0, this.getRight(), 0 + this.getHeight()); | |
disY = dis - getTop(); | |
} else if(this.getBottom() > screenH) { | |
disY = getBottom() - screenH; | |
this.layout(this.getLeft(), screenH-getHeight(), this.getRight(), screenH); | |
} | |
} else {//图片高度超出显示范围 | |
if(this.getTop() < 0 && this.getBottom() < screenH) { | |
disY = getHeight()- screenH+getTop(); | |
this.layout(this.getLeft(), screenH-getHeight(), this.getRight(), screenH); | |
} else if(this.getTop() > 0 && this.getBottom() > screenH) { | |
int dis = getTop(); | |
this.layout(this.getLeft(), 0, this.getRight(), 0 + this.getHeight()); | |
disY = dis - getTop(); | |
} | |
} | |
if(getWidth() <= screenW) { | |
if(this.getLeft() < 0) { | |
disX = getLeft(); | |
this.layout(0, this.getTop(), 0+getWidth(), this.getBottom()); | |
} else if(this.getRight() > screenW) { | |
disX = getRight() - screenW; | |
this.layout(screenW-getWidth(), this.getTop(), screenW, this.getBottom()); | |
} | |
} else {//图片宽度超出显示范围 | |
Log.d("TouchView", "Left: " + getLeft() + " Right: " + getRight()); | |
if(this.getLeft() > 0 && this.getRight() > screenW) { | |
disX = getLeft(); | |
this.layout(0, this.getTop(), 0+getWidth(), this.getBottom()); | |
} else if(this.getLeft() < 0 && this.getRight() < screenW) { | |
disX = getRight() - screenW; | |
this.layout(screenW-getWidth(), this.getTop(), screenW, this.getBottom()); | |
} | |
} | |
if(disX!=0 || disY!=0) { | |
trans = new TranslateAnimation(disX, 0, disY, 0); | |
trans.setDuration(300); | |
this.startAnimation(trans); | |
} | |
mode = NONE; | |
break; | |
case MotionEvent.ACTION_POINTER_UP: | |
//图片缩的比屏幕小,自动放大 | |
if(getWidth() < minWidth && getHeight() < minHeight) { //原图大, 不允许小于屏幕; 原图小; 不允许小于原图 | |
while(getWidth() < minWidth && getHeight() < minHeight) { | |
setScale(scale, BIGGER); | |
} | |
} else if(getWidth() > WIDTH_IMAGE_ORIGINAL && getHeight() > HEIGHT_IMAGE_ORIGINAL) {//超出原图大小 | |
while(getWidth() > WIDTH_IMAGE_ORIGINAL && getHeight() > HEIGHT_IMAGE_ORIGINAL) { | |
setScale(scale, SMALLER); | |
} | |
} | |
mode = NONE; | |
break; | |
case MotionEvent.ACTION_MOVE: | |
/*处理拖动*/ | |
if (mode == DRAG) { | |
if(Math.abs(stop_x-start_x-getLeft())<88 && Math.abs(stop_y - start_y-getTop())<85) | |
{ | |
this.setPosition(stop_x - start_x, stop_y - start_y, stop_x + this.getWidth() - start_x, stop_y - start_y + this.getHeight()); | |
stop_x = (int) event.getRawX(); | |
stop_y = (int) event.getRawY(); | |
} | |
} | |
/*处理缩放*/ | |
else if (mode == ZOOM) { | |
if(spacing(event) > 10f) { | |
afterLenght = spacing(event); | |
float gapLenght = afterLenght - beforeLenght; | |
if(gapLenght == 0) { | |
break; | |
} else if(Math.abs(gapLenght) > 5f) {//双指放大/缩小 | |
if(gapLenght > 0) {//放大 | |
if(getWidth() < WIDTH_IMAGE_ORIGINAL*MAX_SCALE && getHeight() < HEIGHT_IMAGE_ORIGINAL*MAX_SCALE) {//不允许超出原图大小, 防止无限放大 | |
this.setScale(scale,BIGGER); | |
} | |
} else {//缩小 | |
if(getWidth() > minWidth/MIN_SCALE || getHeight() > minHeight/MIN_SCALE) {//不允许小于显示区域的一半,防止无限缩小 | |
this.setScale(scale,SMALLER); | |
} | |
} | |
beforeLenght = afterLenght; | |
} | |
} | |
} | |
break; | |
} | |
return true; | |
} | |
/** | |
* 实现处理缩放 | |
*/ | |
private void setScale(float temp, int flag) { | |
if (flag == BIGGER) { | |
this.setFrame(this.getLeft() - (int) (temp * this.getWidth()), | |
this.getTop() - (int) (temp * this.getHeight()), | |
this.getRight() + (int) (temp * this.getWidth()), | |
this.getBottom() + (int) (temp * this.getHeight())); | |
} else if (flag == SMALLER) { | |
this.setFrame(this.getLeft() + (int) (temp * this.getWidth()), | |
this.getTop() + (int) (temp * this.getHeight()), | |
this.getRight() - (int) (temp * this.getWidth()), | |
this.getBottom() - (int) (temp * this.getHeight())); | |
} | |
} | |
/** | |
* 实现处理拖动 | |
*/ | |
private void setPosition(int left,int top,int right,int bottom) { | |
this.layout(left,top,right,bottom); | |
} | |
@Override | |
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
super.onLayout(changed, left, top, right, bottom); | |
if(this.getDrawable() != null) { | |
WIDTH_IMAGE_ORIGINAL = this.getDrawable().getIntrinsicWidth(); | |
HEIGHT_IMAGE_ORIGINAL = this.getDrawable().getIntrinsicHeight(); | |
} | |
minWidth = Math.min(screenW, WIDTH_IMAGE_ORIGINAL); | |
minHeight = Math.min(screenH, HEIGHT_IMAGE_ORIGINAL); | |
} | |
/** | |
* @return the screenW | |
*/ | |
public int getScreenWidth() { | |
return screenW; | |
} | |
/** | |
* @param screenW the screenW to set | |
*/ | |
public void setScreenWidth(int screenW) { | |
this.screenW = screenW; | |
} | |
/** | |
* @return the screenH | |
*/ | |
public int getScreenHeight() { | |
return screenH; | |
} | |
/** | |
* @param screenH the screenH to set | |
*/ | |
public void setScreenHeight(int screenH) { | |
this.screenH = screenH; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment