今天做了一个可移动的ImageView,要点如下:
1 ontouch
2 ongloballayout
3 image放置适当的位置
4 matrix变换(平移,缩放)
代码很简单
activity_main.xml
<RelativeLayout 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=".MainActivity"> <com.none.view.MoveImage android:id="@+id/id_img" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="matrix" /> </RelativeLayout>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中对图片伸缩和伸缩和的上下左右位置的处理。