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