本例实现了最简单的单指移动、双指缩放的图片组件,效果图如下:
功能:
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); } } }); }
======
源代码即将奉上,尽情期待。
时间: 2024-10-27 05:45:28