一.实现的效果
ScaleImageView_without_over_scroll.gif二.思路
1.定义放大和缩小的系数
2.监听双击
3.监听手势滑动&fling
三.难点及解决
ScaleImageView_with_over_scroll.gif3.1.放大缩小级别的计算:
使用图片宽高比与控件宽高比做对比,
3.2.双击&手势滑动&fling:
交给GestureDetector&Scroller
Scroller与OverScroller存在速度上的区别,并且,OverScroller的可以实现过度滑动如:
image.png
四.talk is cheap
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.support.v4.view.GestureDetectorCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.OverScroller;
import com.example.rookie.hencoder_plus.R;
/**
* 支持双击放大/缩小&拖拽的ImageView
* 1.定义大图&小图模式的系数
* <p>
* 2.增加放大缩小的过程动画
* 3.使用GestureDetector处理双击&拖拽
*/
public class ScaleImageView extends View implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
private static final float OVER_SCALE_FACTOR = 1.5f;
private int width;
private int height;
private Bitmap bitmap;
private float originalOffsetX, originalOffsetY;//初始偏移,保证图片在正中间
private float offsetX, offsetY;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float bigModeScale, smallModeScale;
GestureDetectorCompat gestureDetectorCompat;
private float scaleFraction;
private OverScroller overScroller;
/**
* 属性动画使用
*
* @return
*/
private float getScaleFraction() {
return scaleFraction;
}
/**
* 属性动画使用
*
* @return
*/
private void setScaleFraction(float scaleFraction) {
this.scaleFraction = scaleFraction;
invalidate();
}
public ScaleImageView(Context context) {
this(context, null);
}
public ScaleImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ScaleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
gestureDetectorCompat = new GestureDetectorCompat(getContext(), this);
gestureDetectorCompat.setOnDoubleTapListener(this);
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_tmac);
overScroller = new OverScroller(getContext());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = getWidth();
height = getHeight();
originalOffsetX = (width - bitmap.getWidth()) / 2f;
originalOffsetY = (height - bitmap.getHeight()) / 2f;
//计算缩放系数
if (((float) bitmap.getWidth() / bitmap.getHeight()) > ((float) width / height)) {
Log.e("test", "图片的宽高比更大--->");
//图片的宽高比更大,那么较小的缩放模式就是以宽度的
smallModeScale = ((float) width) / bitmap.getWidth();
bigModeScale = ((float) height) / bitmap.getHeight() * OVER_SCALE_FACTOR;
} else {
//view的宽高比更大,图片应该放大以铺满整个屏幕
Log.e("test", "控件的宽高比更大--->");
smallModeScale = ((float) height) / bitmap.getHeight();
bigModeScale = ((float) width) / bitmap.getWidth() * OVER_SCALE_FACTOR;
}
}
private boolean bigMode;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将图片画到中间
// canvas.translate((width - bitmap.getWidth()) / 2, (height - bitmap.getHeight()) / 2);
//拖动所产生的偏移
if (!bigMode) {
canvas.save();
}
canvas.translate(offsetX, offsetY);
if (!bigMode) {
canvas.restore();
offsetX = offsetY = 0;
}
float scale = smallModeScale + (bigModeScale - smallModeScale) * scaleFraction;
canvas.scale(scale, scale, width / 2f, height / 2f);
canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetectorCompat.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent e) {
if (overScroller != null && !overScroller.isFinished()) {
overScroller.forceFinished(true);
}
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//向下,向右移动,distanceY,distanceX为正值(这里的distance是旧位置-新位置所产生的位移)
// Log.e("test", "distanceX:" + distanceX + "distanceY:" + distanceY);
//只有大图模式才可以拖动
if (bigMode) {
//注意边界值
//放大后的bitmap的width
final float overScaleBitmapWidth = bitmap.getWidth() * bigModeScale;
final float overScaleBitmapHeight = bitmap.getHeight() * bigModeScale;
offsetX = offsetX - distanceX;
offsetX = Math.min(offsetX, (overScaleBitmapWidth - width) / 2);
offsetX = Math.max(offsetX, -(overScaleBitmapWidth - width) / 2);
offsetY = offsetY - distanceY;
offsetY = Math.min(offsetY, (overScaleBitmapHeight - height) / 2);
offsetY = Math.max(offsetY, -(overScaleBitmapHeight - height) / 2);
}
invalidate();
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//以当前的偏移点offsetX,offsetY为参考点
//这里的overScroller 的8个参数的最后两个参数是额外的超出滑动的区域,类似与ios的弹性滑动
int overScrollDistance = 0;
overScroller.fling(((int) offsetX), ((int) offsetY), ((int) velocityX), ((int) velocityY),
-(((int) (bitmap.getWidth() * bigModeScale)) - width) / 2,
(((int) (bitmap.getWidth() * bigModeScale)) - width) / 2,
-(((int) (bitmap.getHeight() * bigModeScale)) - height) / 2,
(((int) (bitmap.getHeight() * bigModeScale)) - height) / 2, overScrollDistance, overScrollDistance);
invalidate();
return false;
}
@Override
public void computeScroll() {
super.computeScroll();
if (overScroller.computeScrollOffset() && bigMode) {
//当前的x,y即offsetX,offsetY
offsetX = overScroller.getCurrX();
offsetY = overScroller.getCurrY();
// Log.e("test", "currX:" + currX + "->currY:" + currY);
// Log.e("test", "offsetX:" + offsetX + "->offsetY:" + offsetY);
invalidate();
}
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.e("test", "onDoubleTap--->");
bigMode = !bigMode;
if (bigMode) {
getScaleAnimator().start();
} else {
getScaleAnimator().reverse();
}
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
ObjectAnimator scaleAnimator;
ObjectAnimator getScaleAnimator() {
if (scaleAnimator == null) {
scaleAnimator = ObjectAnimator.ofFloat(this, "scaleFraction", 0, 1);
}
return scaleAnimator;
}
}
网友评论