博客转载自:http://blog.csdn.net/kongbaidepao/article/details/22267679
1.阻尼效果listview
- public class MyListView extends ListView implements Runnable {
- private float mLastDownY = 0f;
- private int mDistance = 0;
- private int mStep = 10;
- private boolean mPositive = false;
- public MyListView (Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public MyListView (Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- public MyListView (Context context) {
- super(context);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (mLastDownY == 0f && mDistance == 0) {
- mLastDownY = event.getY();
- return true;
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- break;
- case MotionEvent.ACTION_UP:
- if (mDistance != 0) {
- mStep = 1;
- mPositive = (mDistance >= 0);
- this.post(this);
- return true;
- }
- mLastDownY = 0f;
- mDistance = 0;
- break;
- case MotionEvent.ACTION_MOVE:
- if (mLastDownY != 0f) {
- mDistance = (int) (mLastDownY - event.getY());
- if ((mDistance < 0 && getFirstVisiblePosition() == 0 && getChildAt(0).getTop() == 0) || (mDistance > 0 && getLastVisiblePosition() == getCount() - 1)) {
- mDistance /= 2;
- scrollTo(0, mDistance);
- return true;
- }
- }
- mDistance = 0;
- break;
- }
- return super.onTouchEvent(event);
- }
- public void run() {
- mDistance += mDistance > 0 ? -mStep : mStep;
- scrollTo(0, mDistance);
- if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) {
- scrollTo(0, 0);
- mDistance = 0;
- mLastDownY = 0f;
- return;
- }
- mStep += 1;
- this.postDelayed(this, 10);
- }
- }
2.阻尼效果 scrollview
- public class CustomScrollView extends ScrollView {
- private View inner;// 孩子View
- private float y;// 点击时y坐标
- private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)
- private boolean isCount = false;// 是否开始计算
- private boolean isMoveing = false;// 是否开始移动.
- private ImageView imageView;
- private int initTop, initbottom;// 初始高度
- private int top, bottom;// 拖动时时高度。
- public void setImageView(ImageView imageView) {
- this.imageView = imageView;
- }
- public CustomScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- /***
- * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
- * 方法,也应该调用父类的方法,使该方法得以执行.
- */
- @Override
- protected void onFinishInflate() {
- if (getChildCount() > 0) {
- inner = getChildAt(0);
- }
- }
- /** touch 事件处理 **/
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (inner != null) {
- commOnTouchEvent(ev);
- }
- return super.onTouchEvent(ev);
- }
- /***
- * 触摸事件
- *
- * @param ev
- */
- public void commOnTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- top = initTop = imageView.getTop();
- bottom = initbottom = imageView.getBottom();
- break;
- case MotionEvent.ACTION_UP:
- isMoveing = false;
- // 手指松开.
- if (isNeedAnimation()) {
- animation();
- }
- break;
- /***
- * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
- * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.
- * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
- */
- case MotionEvent.ACTION_MOVE:
- final float preY = y;// 按下时的y坐标
- float nowY = ev.getY();// 时时y坐标
- int deltaY = (int) (nowY - preY);// 滑动距离
- if (!isCount) {
- deltaY = 0; // 在这里要归0.
- }
- if (deltaY < 0 && top <= initTop)
- return;
- // 当滚动到最上或者最下时就不会再滚动,这时移动布局
- isNeedMove();
- if (isMoveing) {
- // 初始化头部矩形
- if (normal.isEmpty()) {
- // 保存正常的布局位置
- normal.set(inner.getLeft(), inner.getTop(),
- inner.getRight(), inner.getBottom());
- }
- // 移动布局
- inner.layout(inner.getLeft(), inner.getTop() + deltaY / 3,
- inner.getRight(), inner.getBottom() + deltaY / 3);
- top += (deltaY / 6);
- bottom += (deltaY / 6);
- imageView.layout(imageView.getLeft(), top,
- imageView.getRight(), bottom);
- }
- isCount = true;
- y = nowY;
- break;
- default:
- break;
- }
- }
- /***
- * 回缩动画
- */
- public void animation() {
- TranslateAnimation taa = new TranslateAnimation(0, 0, top + 200,
- initTop + 200);
- taa.setDuration(200);
- imageView.startAnimation(taa);
- imageView.layout(imageView.getLeft(), initTop, imageView.getRight(),
- initbottom);
- // 开启移动动画
- TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
- normal.top);
- ta.setDuration(200);
- inner.startAnimation(ta);
- // 设置回到正常的布局位置
- inner.layout(normal.left, normal.top, normal.right, normal.bottom);
- normal.setEmpty();
- isCount = false;
- y = 0;// 手指松开要归0.
- }
- // 是否需要开启动画
- public boolean isNeedAnimation() {
- return !normal.isEmpty();
- }
- /***
- * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
- *
- * getHeight():获取的是屏幕的高度
- *
- * @return
- */
- public void isNeedMove() {
- int offset = inner.getMeasuredHeight() - getHeight();
- int scrollY = getScrollY();
- // Log.e("jj", "scrolly=" + scrollY);
- // 0是顶部,后面那个是底部
- if (scrollY == 0 || scrollY == offset) {
- isMoveing = true;
- }
- }
- }
- public class RoundedImageView extends ImageView {
- public RoundedImageView(Context context) {
- super(context);
- // TODO Auto-generated constructor stub
- }
- public RoundedImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- Drawable drawable = getDrawable();
- if (drawable == null) {
- return;
- }
- if (getWidth() == 0 || getHeight() == 0) {
- return;
- }
- Bitmap b = ((BitmapDrawable) drawable).getBitmap();
- Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
- int w = getWidth(), h = getHeight();
- Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
- canvas.drawBitmap(roundBitmap, 0, 0, null);
- }
- public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
- Bitmap sbmp;
- if (bmp.getWidth() != radius || bmp.getHeight() != radius)
- sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
- else
- sbmp = bmp;
- Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
- Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- final int color = 0xffa19774;
- final Paint paint = new Paint();
- final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
- canvas.drawARGB(0, 0, 0, 0);
- paint.setColor(Color.parseColor("#BAB399"));
- canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
- sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
- paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
- canvas.drawBitmap(sbmp, rect, rect, paint);
- return output;
- }
- }
- <com.example.view.RoundedImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:adjustViewBounds="true"
- android:maxHeight="80dip"
- android:maxWidth="80dip"
- android:src="@drawable/aa" />
3.开关按钮(为了兼容版本)
- public class SlidButton extends View implements OnTouchListener {
- private boolean nowChoose = false;// 记录当前按钮是否打开,true为打开,false为关闭
- private boolean onSlip = false;// 记录用户是否在滑动
- private float downX, nowX; // 按下时的x,当前的x
- private Rect btn_on, btn_off;// 打开和关闭状态下,游标的Rect
- private boolean isChgLsnOn = false;//是否设置监听
- private OnChangedListener changedLis;
- int begin,end;//控件当前的位置
- private Bitmap bg_on, bg_off, slip_btn;
- public SlidButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public SlidButton(Context context) {
- super(context);
- init();
- }
- private void init() {
- // 载入图片资源
- bg_on = BitmapFactory.decodeResource(getResources(),
- R.drawable.sild_bg_on1);
- bg_off = BitmapFactory.decodeResource(getResources(),
- R.drawable.sild_bg_off1);
- slip_btn = BitmapFactory.decodeResource(getResources(),
- R.drawable.sild_bg_btn1);
- // 获得需要的Rect数据
- btn_on = new Rect(0, 0, slip_btn.getWidth() , slip_btn.getHeight());
- btn_off = new Rect(bg_off.getWidth() - slip_btn.getWidth(), 0,
- bg_off.getWidth(), slip_btn.getHeight());
- setOnTouchListener(this);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- Matrix matrix = new Matrix();
- begin =this.getWidth() - bg_off.getWidth();
- end =9;
- matrix.postTranslate(begin, end);
- Paint paint = new Paint();
- float x;
- {
- // if (nowX<(bg_on.getWidth()/2)) //滑动到前半段与后半段的背景不同,在此做判断
- if(!nowChoose){
- canvas.drawBitmap(bg_off, matrix, paint);//画出关闭时的背景
- }else{
- canvas.drawBitmap(bg_on, matrix, paint);//画出打开时的背景
- }
- if (onSlip) {//是否是在滑动状态,
- if(nowX >= bg_on.getWidth()){
- //是否划出指定范围,不能让游标跑到外头,必须做这个判断
- x = bg_on.getWidth() - slip_btn.getWidth()/2;//减去游标1/2的长度
- }else{
- x = nowX - slip_btn.getWidth() / 2;
- }
- }else {
- if(nowChoose)//根据现在的开关状态设置画游标的位置
- x = btn_off.left;
- else
- x = btn_on.left;
- }
- if (x < 0 ) //对游标位置进行异常判断..
- x = 0;
- else if(x > bg_on.getWidth() - slip_btn.getWidth())
- x = bg_on.getWidth() - slip_btn.getWidth();
- canvas.drawBitmap(slip_btn, x + begin, end, paint);//画出游标.
- }
- }
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {//根据动作来执行代码
- case MotionEvent.ACTION_MOVE:
- nowX = event.getX();
- break;
- case MotionEvent.ACTION_DOWN:
- if (event.getX() < begin)
- return false;
- onSlip = true;
- downX = event.getX();
- nowX = downX;
- break;
- case MotionEvent.ACTION_UP://松开
- onSlip = false;
- boolean lastChoose = nowChoose;
- /*if (event.getX() >= begin+(bg_on.getWidth()/2))
- nowChoose = true;
- else
- nowChoose = false; */
- nowChoose =!nowChoose;
- if(isChgLsnOn && (lastChoose != nowChoose))//如果设置了监听器,就调用其方法.
- changedLis.OnChanged(nowChoose);
- break;
- default:
- break;
- }
- invalidate();
- return true;
- }
- public void SetOnChangedListener(OnChangedListener l){//设置监听器,当状态修改的时候
- isChgLsnOn = true;
- changedLis = l;
- }
- public interface OnChangedListener {
- abstract void OnChanged(boolean checkState);
- }
- }
- <com.view.SlidButton
- android:layout_width="50dip"
- android:layout_height="30dp"
- />
4. 缩小放大图片
- public class TouchImageView extends ImageView {
- Matrix matrix;
- // We can be in one of these 3 states
- static final int NONE = 0;
- static final int DRAG = 1;
- static final int ZOOM = 2;
- int mode = NONE;
- // Remember some things for zooming
- PointF last = new PointF();
- PointF start = new PointF();
- float minScale = 1f;
- float maxScale = 3f;
- float[] m;
- int viewWidth, viewHeight;
- static final int CLICK = 3;
- float saveScale = 1f;
- protected float origWidth, origHeight;
- int oldMeasuredWidth, oldMeasuredHeight;
- ScaleGestureDetector mScaleDetector;
- Context context;
- public TouchImageView(Context context) {
- super(context);
- sharedConstructing(context);
- }
- public TouchImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- sharedConstructing(context);
- }
- private void sharedConstructing(Context context) {
- super.setClickable(true);
- this.context = context;
- mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
- matrix = new Matrix();
- m = new float[9];
- setImageMatrix(matrix);
- setScaleType(ScaleType.MATRIX);
- setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- mScaleDetector.onTouchEvent(event);
- PointF curr = new PointF(event.getX(), event.getY());
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- last.set(curr);
- start.set(last);
- mode = DRAG;
- break;
- case MotionEvent.ACTION_MOVE:
- if (mode == DRAG) {
- float deltaX = curr.x - last.x;
- float deltaY = curr.y - last.y;
- float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale);
- float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale);
- matrix.postTranslate(fixTransX, fixTransY);
- fixTrans();
- last.set(curr.x, curr.y);
- }
- break;
- case MotionEvent.ACTION_UP:
- mode = NONE;
- int xDiff = (int) Math.abs(curr.x - start.x);
- int yDiff = (int) Math.abs(curr.y - start.y);
- if (xDiff < CLICK && yDiff < CLICK)
- performClick();
- break;
- case MotionEvent.ACTION_POINTER_UP:
- mode = NONE;
- break;
- }
- setImageMatrix(matrix);
- invalidate();
- return true; // indicate event was handled
- }
- });
- }
- public void setMaxZoom(float x) {
- maxScale = x;
- }
- private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- mode = ZOOM;
- return true;
- }
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- float mScaleFactor = detector.getScaleFactor();
- float origScale = saveScale;
- saveScale *= mScaleFactor;
- if (saveScale > maxScale) {
- saveScale = maxScale;
- mScaleFactor = maxScale / origScale;
- } else if (saveScale < minScale) {
- saveScale = minScale;
- mScaleFactor = minScale / origScale;
- }
- if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight)
- matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2);
- else
- matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
- fixTrans();
- return true;
- }
- }
- void fixTrans() {
- matrix.getValues(m);
- float transX = m[Matrix.MTRANS_X];
- float transY = m[Matrix.MTRANS_Y];
- float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale);
- float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale);
- if (fixTransX != 0 || fixTransY != 0)
- matrix.postTranslate(fixTransX, fixTransY);
- }
- float getFixTrans(float trans, float viewSize, float contentSize) {
- float minTrans, maxTrans;
- if (contentSize <= viewSize) {
- minTrans = 0;
- maxTrans = viewSize - contentSize;
- } else {
- minTrans = viewSize - contentSize;
- maxTrans = 0;
- }
- if (trans < minTrans)
- return -trans + minTrans;
- if (trans > maxTrans)
- return -trans + maxTrans;
- return 0;
- }
- float getFixDragTrans(float delta, float viewSize, float contentSize) {
- if (contentSize <= viewSize) {
- return 0;
- }
- return delta;
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- viewWidth = MeasureSpec.getSize(widthMeasureSpec);
- viewHeight = MeasureSpec.getSize(heightMeasureSpec);
- //
- // Rescales image on rotation
- //
- if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight
- || viewWidth == 0 || viewHeight == 0)
- return;
- oldMeasuredHeight = viewHeight;
- oldMeasuredWidth = viewWidth;
- if (saveScale == 1) {
- //Fit to screen.
- float scale;
- Drawable drawable = getDrawable();
- if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0)
- return;
- int bmWidth = drawable.getIntrinsicWidth();
- int bmHeight = drawable.getIntrinsicHeight();
- Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight);
- float scaleX = (float) viewWidth / (float) bmWidth;
- float scaleY = (float) viewHeight / (float) bmHeight;
- scale = Math.min(scaleX, scaleY);
- matrix.setScale(scale, scale);
- // Center the image
- float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight);
- float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth);
- redundantYSpace /= (float) 2;
- redundantXSpace /= (float) 2;
- matrix.postTranslate(redundantXSpace, redundantYSpace);
- origWidth = viewWidth - 2 * redundantXSpace;
- origHeight = viewHeight - 2 * redundantYSpace;
- setImageMatrix(matrix);
- }
- fixTrans();
- }
- }
- public class TouchImageViewActivity extends Activity {
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- TouchImageView img = (TouchImageView) findViewById(R.id.snoop);
- img.setImageResource(R.drawable.snoopy);
- img.setMaxZoom(4f);
- }
- }
- /**
- * 自定义的ImageView控制,可对图片进行多点触控缩放和拖动
- *
- * @author guolin
- */
- public class ZoomImageView extends View {
- /**
- * 初始化状态常量
- */
- public static final int STATUS_INIT = 1;
- /**
- * 图片放大状态常量
- */
- public static final int STATUS_ZOOM_OUT = 2;
- /**
- * 图片缩小状态常量
- */
- public static final int STATUS_ZOOM_IN = 3;
- /**
- * 图片拖动状态常量
- */
- public static final int STATUS_MOVE = 4;
- /**
- * 用于对图片进行移动和缩放变换的矩阵
- */
- private Matrix matrix = new Matrix();
- /**
- * 待展示的Bitmap对象
- */
- private Bitmap sourceBitmap;
- /**
- * 记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
- */
- private int currentStatus;
- /**
- * ZoomImageView控件的宽度
- */
- private int width;
- /**
- * ZoomImageView控件的高度
- */
- private int height;
- /**
- * 记录两指同时放在屏幕上时,中心点的横坐标值
- */
- private float centerPointX;
- /**
- * 记录两指同时放在屏幕上时,中心点的纵坐标值
- */
- private float centerPointY;
- /**
- * 记录当前图片的宽度,图片被缩放时,这个值会一起变动
- */
- private float currentBitmapWidth;
- /**
- * 记录当前图片的高度,图片被缩放时,这个值会一起变动
- */
- private float currentBitmapHeight;
- /**
- * 记录上次手指移动时的横坐标
- */
- private float lastXMove = -1;
- /**
- * 记录上次手指移动时的纵坐标
- */
- private float lastYMove = -1;
- /**
- * 记录手指在横坐标方向上的移动距离
- */
- private float movedDistanceX;
- /**
- * 记录手指在纵坐标方向上的移动距离
- */
- private float movedDistanceY;
- /**
- * 记录图片在矩阵上的横向偏移值
- */
- private float totalTranslateX;
- /**
- * 记录图片在矩阵上的纵向偏移值
- */
- private float totalTranslateY;
- /**
- * 记录图片在矩阵上的总缩放比例
- */
- private float totalRatio;
- /**
- * 记录手指移动的距离所造成的缩放比例
- */
- private float scaledRatio;
- /**
- * 记录图片初始化时的缩放比例
- */
- private float initRatio;
- /**
- * 记录上次两指之间的距离
- */
- private double lastFingerDis;
- /**
- * ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
- *
- * @param context
- * @param attrs
- */
- public ZoomImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- currentStatus = STATUS_INIT;
- }
- /**
- * 将待展示的图片设置进来。
- *
- * @param bitmap
- * 待展示的Bitmap对象
- */
- public void setImageBitmap(Bitmap bitmap) {
- sourceBitmap = bitmap;
- invalidate();
- }
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- // 分别获取到ZoomImageView的宽度和高度
- width = getWidth();
- height = getHeight();
- }
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_POINTER_DOWN:
- if (event.getPointerCount() == 2) {
- // 当有两个手指按在屏幕上时,计算两指之间的距离
- lastFingerDis = distanceBetweenFingers(event);
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (event.getPointerCount() == 1) {
- // 只有单指按在屏幕上移动时,为拖动状态
- float xMove = event.getX();
- float yMove = event.getY();
- if (lastXMove == -1 && lastYMove == -1) {
- lastXMove = xMove;
- lastYMove = yMove;
- }
- currentStatus = STATUS_MOVE;
- movedDistanceX = xMove - lastXMove;
- movedDistanceY = yMove - lastYMove;
- // 进行边界检查,不允许将图片拖出边界
- if (totalTranslateX + movedDistanceX > 0) {
- movedDistanceX = 0;
- } else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {
- movedDistanceX = 0;
- }
- if (totalTranslateY + movedDistanceY > 0) {
- movedDistanceY = 0;
- } else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {
- movedDistanceY = 0;
- }
- // 调用onDraw()方法绘制图片
- invalidate();
- lastXMove = xMove;
- lastYMove = yMove;
- } else if (event.getPointerCount() == 2) {
- // 有两个手指按在屏幕上移动时,为缩放状态
- centerPointBetweenFingers(event);
- double fingerDis = distanceBetweenFingers(event);
- if (fingerDis > lastFingerDis) {
- currentStatus = STATUS_ZOOM_OUT;
- } else {
- currentStatus = STATUS_ZOOM_IN;
- }
- // 进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
- if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)
- || (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {
- scaledRatio = (float) (fingerDis / lastFingerDis);
- totalRatio = totalRatio * scaledRatio;
- if (totalRatio > 4 * initRatio) {
- totalRatio = 4 * initRatio;
- } else if (totalRatio < initRatio) {
- totalRatio = initRatio;
- }
- // 调用onDraw()方法绘制图片
- invalidate();
- lastFingerDis = fingerDis;
- }
- }
- break;
- case MotionEvent.ACTION_POINTER_UP:
- if (event.getPointerCount() == 2) {
- // 手指离开屏幕时将临时值还原
- lastXMove = -1;
- lastYMove = -1;
- }
- break;
- case MotionEvent.ACTION_UP:
- // 手指离开屏幕时将临时值还原
- lastXMove = -1;
- lastYMove = -1;
- break;
- default:
- break;
- }
- return true;
- }
- /**
- * 根据currentStatus的值来决定对图片进行什么样的绘制操作。
- */
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- switch (currentStatus) {
- case STATUS_ZOOM_OUT:
- case STATUS_ZOOM_IN:
- zoom(canvas);
- break;
- case STATUS_MOVE:
- move(canvas);
- break;
- case STATUS_INIT:
- initBitmap(canvas);
- default:
- canvas.drawBitmap(sourceBitmap, matrix, null);
- break;
- }
- }
- /**
- * 对图片进行缩放处理。
- *
- * @param canvas
- */
- private void zoom(Canvas canvas) {
- matrix.reset();
- // 将图片按总缩放比例进行缩放
- matrix.postScale(totalRatio, totalRatio);
- float scaledWidth = sourceBitmap.getWidth() * totalRatio;
- float scaledHeight = sourceBitmap.getHeight() * totalRatio;
- float translateX = 0f;
- float translateY = 0f;
- // 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放
- if (currentBitmapWidth < width) {
- translateX = (width - scaledWidth) / 2f;
- } else {
- translateX = totalTranslateX * scaledRatio + centerPointX * (1 - scaledRatio);
- // 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕
- if (translateX > 0) {
- translateX = 0;
- } else if (width - translateX > scaledWidth) {
- translateX = width - scaledWidth;
- }
- }
- // 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
- if (currentBitmapHeight < height) {
- translateY = (height - scaledHeight) / 2f;
- } else {
- translateY = totalTranslateY * scaledRatio + centerPointY * (1 - scaledRatio);
- // 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕
- if (translateY > 0) {
- translateY = 0;
- } else if (height - translateY > scaledHeight) {
- translateY = height - scaledHeight;
- }
- }
- // 缩放后对图片进行偏移,以保证缩放后中心点位置不变
- matrix.postTranslate(translateX, translateY);
- totalTranslateX = translateX;
- totalTranslateY = translateY;
- currentBitmapWidth = scaledWidth;
- currentBitmapHeight = scaledHeight;
- canvas.drawBitmap(sourceBitmap, matrix, null);
- }
- /**
- * 对图片进行平移处理
- *
- * @param canvas
- */
- private void move(Canvas canvas) {
- matrix.reset();
- // 根据手指移动的距离计算出总偏移值
- float translateX = totalTranslateX + movedDistanceX;
- float translateY = totalTranslateY + movedDistanceY;
- // 先按照已有的缩放比例对图片进行缩放
- matrix.postScale(totalRatio, totalRatio);
- // 再根据移动距离进行偏移
- matrix.postTranslate(translateX, translateY);
- totalTranslateX = translateX;
- totalTranslateY = translateY;
- canvas.drawBitmap(sourceBitmap, matrix, null);
- }
- /**
- * 对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。
- *
- * @param canvas
- */
- private void initBitmap(Canvas canvas) {
- if (sourceBitmap != null) {
- matrix.reset();
- int bitmapWidth = sourceBitmap.getWidth();
- int bitmapHeight = sourceBitmap.getHeight();
- if (bitmapWidth > width || bitmapHeight > height) {
- if (bitmapWidth - width > bitmapHeight - height) {
- // 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来
- float ratio = width / (bitmapWidth * 1.0f);
- matrix.postScale(ratio, ratio);
- float translateY = (height - (bitmapHeight * ratio)) / 2f;
- // 在纵坐标方向上进行偏移,以保证图片居中显示
- matrix.postTranslate(0, translateY);
- totalTranslateY = translateY;
- totalRatio = initRatio = ratio;
- } else {
- // 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来
- float ratio = height / (bitmapHeight * 1.0f);
- matrix.postScale(ratio, ratio);
- float translateX = (width - (bitmapWidth * ratio)) / 2f;
- // 在横坐标方向上进行偏移,以保证图片居中显示
- matrix.postTranslate(translateX, 0);
- totalTranslateX = translateX;
- totalRatio = initRatio = ratio;
- }
- currentBitmapWidth = bitmapWidth * initRatio;
- currentBitmapHeight = bitmapHeight * initRatio;
- } else {
- // 当图片的宽高都小于屏幕宽高时,直接让图片居中显示
- float translateX = (width - sourceBitmap.getWidth()) / 2f;
- float translateY = (height - sourceBitmap.getHeight()) / 2f;
- matrix.postTranslate(translateX, translateY);
- totalTranslateX = translateX;
- totalTranslateY = translateY;
- totalRatio = initRatio = 1f;
- currentBitmapWidth = bitmapWidth;
- currentBitmapHeight = bitmapHeight;
- }
- canvas.drawBitmap(sourceBitmap, matrix, null);
- }
- }
- /**
- * 计算两个手指之间的距离。
- *
- * @param event
- * @return 两个手指之间的距离
- */
- private double distanceBetweenFingers(MotionEvent event) {
- float disX = Math.abs(event.getX(0) - event.getX(1));
- float disY = Math.abs(event.getY(0) - event.getY(1));
- return Math.sqrt(disX * disX + disY * disY);
- }
- /**
- * 计算两个手指之间中心点的坐标。
- *
- * @param event
- */
- private void centerPointBetweenFingers(MotionEvent event) {
- float xPoint0 = event.getX(0);
- float yPoint0 = event.getY(0);
- float xPoint1 = event.getX(1);
- float yPoint1 = event.getY(1);
- centerPointX = (xPoint0 + xPoint1) / 2;
- centerPointY = (yPoint0 + yPoint1) / 2;
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <com.example.ZoomImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/zoom_image_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#000000" >
- </com.example.ZoomImageView>