AndroidはScaleGestureDetectorで画像のズームを実現
14409 ワード
, OnTouch() , ,
ScaleGestureDetector , !
/** * ImageView * @description: * @author ldm * @date 2016-4-13 11:08:53 */
blic class ScaleImageView extends ImageView implements OnGlobalLayoutListener,
OnTouchListener, OnScaleGestureListener {
//
private boolean mIsFirst = false;
//
private float mBaseScale;
//
private float mMaxScale;
// Matrix
private Matrix mImageMatrix;
//
private ScaleGestureDetector mScaleGestureDetector;
/** * View * * @param context */
public ScaleImageView(Context context) {
this(context, null);
}
public ScaleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/** * * * @description: * @author ldm * @date 2016-4-12 4:57:04 */
private void init(Context context) {
mImageMatrix = new Matrix();
super.setScaleType(ScaleType.MATRIX);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
setOnTouchListener(this);
}
// View OnGlobalLayoutListener , view 。
@Override
public void onGlobalLayout() {
if (!mIsFirst) {
mIsFirst = true;
//
int width = getWidth();
int height = getHeight();
// ImageView
Drawable d = getDrawable();
if (null == d) {
return;
}
int dw = d.getIntrinsicWidth();//
int dh = d.getIntrinsicHeight();//
float scale = 1.0f;
if (dw > width && dh < height) {//
scale = width * 1.0f / dw;//
}
// &
if ((dw < width && dh < height) || (dw > width && dh < height)) {
scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);//
}
if (dw < width && dh > height) {// ,
scale = height * 1.0f / dh;//
}
mBaseScale = scale;
mMaxScale = mBaseScale * 4;
//
float dx = width / 2 - dw / 2;
float dy = height / 2 - dh / 2;
mImageMatrix.postTranslate(dx, dy);
mImageMatrix.postScale(mBaseScale, mBaseScale, width / 2,
height / 2);
setImageMatrix(mImageMatrix);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
return true;// return true
}
// view
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// OnGlobalLayoutListener
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
// view
@SuppressWarnings("deprecation")
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// OnGlobalLayoutListener
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
//
@Override
public boolean onScale(ScaleGestureDetector detector) {
//
float scaleFactor = detector.getScaleFactor();
float scale = getScale();
if (null == getDrawable()) {
return true;
}
//
if ((scale < mMaxScale && scaleFactor > 1.0f)
|| (scale > mBaseScale && scaleFactor < 1.0f)) {
if (scale * scaleFactor < mBaseScale) {
scaleFactor = mBaseScale / scale;
}
if (scale * scaleFactor > mMaxScale) {
scaleFactor = mMaxScale / scale;
}
//
// mScaleMatrix.postScale(scaleFactor, scaleFactor, getWidth() / 2,
// getHeight() / 2);
//
mImageMatrix.postScale(scaleFactor, scaleFactor,
detector.getFocusX(), detector.getFocusY());
borderAndCenterCheck();
setImageMatrix(mImageMatrix);
}
return false;
}
//
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// true onScale()
return true;
}
//
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// TODO Auto-generated method stub
}
private float getScale() {
float[] values = new float[9];
mImageMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
/** * */
private void borderAndCenterCheck() {
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 / 2f - rect.right + rect.width() / 2f;
}
if (rect.height() < height) {
deltaY = height / 2f - rect.bottom + rect.height() / 2f;
}
mImageMatrix.postTranslate(deltaX, deltaY);
}
/** * * * @return */
private RectF getMatrixRectF() {
Matrix matrix = mImageMatrix;
RectF rectF = new RectF();
Drawable d = getDrawable();
if (d != null) {
rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rectF);
}
return rectF;
}
}
レイアウトxmlで直接使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" >
<com.ldm.view.ScaleImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" android:src="@drawable/zoom_test" />
</LinearLayout>