今天做了一个可移动的ImageView,要点如下:
1 ontouch
2 ongloballayout
3 image放置适当的位置
4 matrix变换(平移,缩放)
代码很简单
activity_main.xml
MainActivity.java
package com.none.moveimage;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import com.none.view.MoveImage;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MoveImage img = (MoveImage)findViewById(R.id.id_img);
img.setImageResource(R.drawable.dou);
}
}
MoveImage.java
package com.none.view;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
/**
* Created by pc on 2015/5/11.
*/
public class MoveImage extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, View.OnTouchListener {
private boolean mInit;
private boolean mIsCanMove;
private float mLastX;
private float mLastY;
private Matrix mScaleMatrix;
private int mMoveSlop;
public MoveImage(Context context) {
this(context, null);
}
public MoveImage(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MoveImage(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mScaleMatrix = new Matrix();
mMoveSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOnTouchListener(this);
mIsCanMove = false;
}
@Override
protected void onAttachedToWindow() {
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
if (!mInit) {
Drawable d = getDrawable();
if (d != null) {
float scale = 1.0f;
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
int width = getWidth();
int height = getHeight();
if (dw > width && dh < height) {
scale = width * 1.0f / dw;
} else if (dw < width && dh > height) {
scale = height * 1.0f / dh;
} else if (dw < width && dh < height) {
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
} else if (dw > width && dh > height) {
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);
} else {
scale = 1.0f;
}
int centerX = (width - dw) / 2;
int centerY = (height - dh) / 2;
mScaleMatrix.postTranslate(centerX, centerY);
scale = scale / 2.0f;
mScaleMatrix.postScale(scale, scale, width / 2, height / 2);
setImageMatrix(mScaleMatrix);
}
}
mInit = true;
}
private RectF getMatrixRectF() {
RectF rectf = new RectF();
final Matrix matrix = mScaleMatrix;
Drawable d = getDrawable();
if (d != null) {
rectf.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rectf);
}
return rectf;
}
private boolean isMoveAction(float dx, float dy) {
return Math.sqrt(dx * dx + dy * dy) > mMoveSlop;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
RectF rectF = getMatrixRectF();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mIsCanMove = rectF.contains(mLastX, mLastY);
break;
case MotionEvent.ACTION_MOVE:
if (mIsCanMove) {
float x = event.getX();
float y = event.getY();
float deltaX = x - mLastX;
float deltaY = y - mLastY;
if (isMoveAction(deltaX, deltaY)) {
checkBorderWhenMove(deltaX, deltaY, rectF);
setImageMatrix(mScaleMatrix);
}
mLastX = x;
mLastY = y;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsCanMove = false;
break;
}
return true;
}
private void checkBorderWhenMove(float deltaX, float deltaY, RectF rectF) {
int width = getWidth();
int height = getHeight();
if (rectF.left + deltaX < 0) {
deltaX = -rectF.left;
} else if (rectF.right + deltaX > width) {
deltaX = width - rectF.right;
}
if (rectF.top + deltaY < 0) {
deltaY = -rectF.top;
} else if (rectF.bottom + deltaY > height) {
deltaY = height - rectF.bottom;
}
mScaleMatrix.postTranslate(deltaX, deltaY);
}
}
之后在根据ongloballayout中的得到的图片size和屏幕大小进行比例计算,之后使用matrix.postscale对图片进行缩放。
图片的平移使用了matrix.posttranslate,平移的距离可随意指定。
另外还需要获得每次缩放后图片的rectf,也就是图片当前的位置。这个可以使用matrix.maprect获得。
最后在ontouch中控制图片的平移,在Down中对触摸点进行判断,非图片的点击不会对图片产生影响,当点击的是图片时,使用setimagematrix对图片移动进行刷新。
在移动的过程中判断图片是否会移动出屏幕,对上下左右进行判断,防止图片移动出屏幕。
参考http://www.imooc.com/learn/239中对图片伸缩和伸缩和的上下左右位置的处理。