標籤:android 自訂群組件 單指移動多指縮放
本例實現了最簡單的單指移動、雙指縮放的圖片組件,如下:
功能:
1.單指移動,雙指縮放。
2.可控制縮放範圍,防止過大或過小;初始化時自動縮放至組件大小,並置中顯示。
3.邊界控制,防止圖片“移出去了”。
4.可使用在xml中,並自動適應組件大小。
5.代碼簡潔!!!
核心代碼:DragScaleView.java
package com.sina.simplegestureimage;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.support.annotation.NonNull;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.View;/** * DragScaleView * Created by hanswim on 15-1-23. */public class DragScaleView extends View { //監聽圖片縮放 private ScaleGestureDetector mScaleDetector; //監聽圖片移動 private GestureDetector mGestureDetector; //當前的縮放比例 private float mScaleFactor = 1.0f; public DragScaleView(Context context) { super(context); } public DragScaleView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public DragScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private void init(Context context) { mScaleDetector = new ScaleGestureDetector(context, new SimpleScaleListenerImpl()); mGestureDetector = new GestureDetector(context, new SimpleGestureListenerImpl()); } private Paint bmpPaint = new Paint(); //圖片資源 private Bitmap bmp; //圖片的寬高 private int bmpWidth, bmpHeight; public void setImageResource(int id) { bmp = BitmapFactory.decodeResource(getResources(), id); bmpWidth = bmp.getWidth(); bmpHeight = bmp.getHeight(); initViewSize(); invalidate(); } //繪製圖片的起始位置 private float mPosX, mPosY; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bmp == null) { return; } if (!hasGetViewSize) { initViewSize(); } canvas.save(); checkBounds(); //以圖片的中心為基點進行縮放 canvas.scale(mScaleFactor, mScaleFactor, mPosX + bmpWidth / 2, mPosY + bmpHeight / 2); canvas.drawBitmap(bmp, mPosX, mPosY, bmpPaint); canvas.restore(); }// private float lastX, lastY;// private static final int INVALID_POINTER_ID = -1;// private int mActivePointerId = INVALID_POINTER_ID; @Override public boolean onTouchEvent(@NonNull MotionEvent event) { //雙指縮放 mScaleDetector.onTouchEvent(event); //單指移動 mGestureDetector.onTouchEvent(event); return true; //也可以自己實現“單指移動圖片” /* int action = MotionEventCompat.getActionMasked(event); switch (action) { case MotionEvent.ACTION_DOWN: { final int pointerIndex = MotionEventCompat.getActionIndex(event); mActivePointerId = MotionEventCompat.getPointerId(event, pointerIndex); lastX = event.getX(); lastY = event.getY(); break; } case MotionEvent.ACTION_MOVE: { // Find the index of the active pointer and fetch its position final int pointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId); float currentX = MotionEventCompat.getX(event, pointerIndex); float currentY = MotionEventCompat.getY(event, pointerIndex); mPosX += (currentX - lastX); mPosY += (currentY - lastY); invalidate(); lastX = currentX; lastY = currentY; break; } case MotionEvent.ACTION_POINTER_UP: { final int pointerIndex = MotionEventCompat.getActionIndex(event); final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex); if (pointerId == mActivePointerId) { // This was our active pointer going up. Choose a new // active pointer and adjust accordingly. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; lastX = MotionEventCompat.getX(event, newPointerIndex); lastY = MotionEventCompat.getY(event, newPointerIndex); mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex); } break; } case MotionEvent.ACTION_UP: { mActivePointerId = INVALID_POINTER_ID; break; } } */ } /** * 不能超出邊界. * 原則是:圖片較小時任意一條邊都不能出了邊界,圖片較大任意一條邊都不能進入邊界。寬度和高度分別獨立計算。 */ private void checkBounds() { if (mScaleFactor > widthScale) { //寬度方向已經填滿 mPosX = Math.min(mPosX, (mScaleFactor - 1) * (bmpWidth / 2)); mPosX = Math.max(mPosX, viewWidth - bmpWidth - (mScaleFactor - 1) * (bmpWidth / 2)); } else { mPosX = Math.max(mPosX, (mScaleFactor - 1) * (bmpWidth / 2)); mPosX = Math.min(mPosX, viewWidth - bmpWidth - (mScaleFactor - 1) * (bmpWidth / 2)); } if (mScaleFactor > heightScale) { //高度方向已經填滿 mPosY = Math.min(mPosY, (mScaleFactor - 1) * (bmpHeight / 2)); mPosY = Math.max(mPosY, viewHeight - bmpHeight - (mScaleFactor - 1) * (bmpHeight / 2)); } else { mPosY = Math.max(mPosY, (mScaleFactor - 1) * (bmpHeight / 2)); mPosY = Math.min(mPosY, viewHeight - bmpHeight - (mScaleFactor - 1) * (bmpHeight / 2)); } } private int viewWidth, viewHeight; //組件尺寸只需要擷取一次 private boolean hasGetViewSize; private void initViewSize() { viewWidth = getWidth(); viewHeight = getHeight(); if (viewWidth > 0 && viewHeight > 0) { hasGetViewSize = true; widthScale = 1.0f * viewWidth / bmpWidth; heightScale = 1.0f * viewHeight / bmpHeight; //初始縮放比例(使組件剛好鋪滿) mScaleFactor = Math.min(widthScale, heightScale); //初始時圖片置中繪製 mPosX = viewWidth / 2 - bmpWidth / 2; mPosY = viewHeight / 2 - bmpHeight / 2; } } /** * 寬度和高度放大多少倍時,剛好填滿此方向的螢幕 */ private float widthScale, heightScale; //縮放 private class SimpleScaleListenerImpl extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); //縮放倍數範圍:0.3~3 mScaleFactor = Math.max(0.3f, Math.min(mScaleFactor, 3.0f)); invalidate(); return true; } } //移動 private class SimpleGestureListenerImpl extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { mPosX -= distanceX; mPosY -= distanceY; invalidate(); return true; } }}
在Activity中使用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.drag_scale); RadioButton landscapeRBtn = (RadioButton) findViewById(R.id.radio_landscape); final DragScaleView dragView = (DragScaleView) findViewById(R.id.drag_scale_view); dragView.setImageResource(R.drawable.cat_boarder); landscapeRBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { dragView.setImageResource(R.drawable.cat_boarder); } else { dragView.setImageResource(R.drawable.cat_boarder_p); } } }); }
======
原始碼即將奉上,盡情期待。
Android:實現最簡單的單指移動、雙指縮放的圖片組件