@SuppressLint("AppCompatCustomView")
public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener {private boolean mIsOneLoad = true;//初始化的比例,也就是最小比例private float mInitScale;//图片最大比例private float mMaxScale;//双击能达到的最大比例private float mMidScale;private Matrix mScaleMatrix;//捕获用户多点触控private ScaleGestureDetector mScaleGestureDetector;//移动private GestureDetector gestureDetector;//双击private boolean isEnlarge = false;//是否放大private ValueAnimator mAnimator; //双击缩放动画//滚动private OverScroller scroller;private int mCurrentX, mCurrentY;private ValueAnimator translationAnimation; //惯性移动动画//单击private OnClickListener onClickListener;//单击监听public ZoomImageView(Context context) {this(context, null);}public ZoomImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放setScaleType(ScaleType.MATRIX);scroller = new OverScroller(context);mScaleMatrix = new Matrix();//手势缩放mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {@Overridepublic boolean onScale(ScaleGestureDetector detector) {scale(detector);return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {scaleEnd(detector);}});//滑动和双击监听gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, final float distanceX, final float distanceY) {//滑动监听onTranslationImage(-distanceX, -distanceY);return true;}@Overridepublic boolean onDoubleTap(MotionEvent e) {//双击监听onDoubleDrowScale(e.getX(), e.getY());return true;}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {//滑动惯性处理mCurrentX = (int) e2.getX();mCurrentY = (int) e2.getY();RectF rectF = getMatrixRectF();if (rectF == null) {return false;}//startX为当前图片左边界的x坐标int startX = mCurrentX;int startY = mCurrentY;int minX = 0, maxX = 0, minY = 0, maxY = 0;int vX = Math.round(velocityX);int vY = Math.round(velocityY);maxX = Math.round(rectF.width());maxY = Math.round(rectF.height());if (startX != maxX || startY != maxY) {//调用fling方法,然后我们可以通过调用getCurX和getCurY来获得当前的x和y坐标//这个坐标的计算是模拟一个惯性滑动来计算出来的,我们根据这个x和y的变化可以模拟//出图片的惯性滑动scroller.fling(startX, startY, vX, vY, 0, maxX, 0, maxY, maxX, maxY);}if (translationAnimation != null && translationAnimation.isStarted())translationAnimation.end();translationAnimation = ObjectAnimator.ofFloat(0, 1);translationAnimation.setDuration(500);translationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {if (scroller.computeScrollOffset()) {//获得当前的x坐标int newX = scroller.getCurrX();int dx = newX - mCurrentX;mCurrentX = newX;//获得当前的y坐标int newY = scroller.getCurrY();int dy = newY - mCurrentY;mCurrentY = newY;//进行平移操作if (dx != 0 && dy != 0)onTranslationImage(dx, dy);}}});translationAnimation.start();return super.onFling(e1, e2, velocityX, velocityY);}@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {//单击事件if(onClickListener != null)onClickListener.onClick(ZoomImageView.this);return true;}});}@Overridepublic void setOnClickListener(OnClickListener onClickListener) {this.onClickListener = onClickListener;}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();getViewTreeObserver().addOnGlobalLayoutListener(this);}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();getViewTreeObserver().removeOnGlobalLayoutListener(this);}/*** imageView加载完成后调用,获取imageView加载完成后的图片大小*/@Overridepublic void onGlobalLayout() {if (mIsOneLoad) {//得到控件的宽和高int width = getWidth();int height = getHeight();//获取图片,如果没有图片则直接退出Drawable d = getDrawable();if (d == null)return;//获取图片的宽和高int dw = d.getIntrinsicWidth();int dh = d.getIntrinsicHeight();float scale = 1.0f;if (dw > width && dh <= height) {scale = width * 1.0f / dw;}if (dw <= width && dh > height) {scale = height * 1.0f / dh;}if ((dw <= width && dh <= height) || (dw >= width && dh >= height)) {scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);}//图片原始比例,图片回复原始大小时使用mInitScale = scale;//图片双击后放大的比例mMidScale = mInitScale * 2;//手势放大时最大比例mMaxScale = mInitScale * 4;//设置移动数据,把改变比例后的图片移到中心点float translationX = width * 1.0f / 2 - dw / 2;float translationY = height * 1.0f / 2 - dh / 2;mScaleMatrix.postTranslate(translationX, translationY);mScaleMatrix.postScale(mInitScale, mInitScale, width * 1.0f / 2, height * 1.0f / 2);setImageMatrix(mScaleMatrix);mIsOneLoad = false;}}@Overridepublic boolean onTouchEvent(MotionEvent event) {return mScaleGestureDetector.onTouchEvent(event)|gestureDetector.onTouchEvent(event);}//手势操作(缩放)public void scale(ScaleGestureDetector detector) {Drawable drawable = getDrawable();if (drawable == null)return;float scale = getScale();//获取手势操作的值,scaleFactor>1说明放大,<1则说明缩小float scaleFactor = detector.getScaleFactor();//获取手势操作后的比例,当放操作后比例在[mInitScale,mMaxScale]区间时允许放大mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());setImageMatrix(mScaleMatrix);removeBorderAndTranslationCenter();}//手势操作结束public void scaleEnd(ScaleGestureDetector detector) {float scale = getScale();scale = detector.getScaleFactor() * scale;if (scale < mInitScale) {scaleAnimation(mInitScale, getWidth() / 2, getHeight() / 2);} else if (scale > mMaxScale) {scaleAnimation(mMaxScale, getWidth() / 2, getHeight() / 2);}}//手势操作(移动)private void onTranslationImage(float dx, float dy) {if (getDrawable() == null)return;RectF rect = getMatrixRectF();//图片宽度小于控件宽度时不允许左右移动if (rect.width() <= getWidth())dx = 0.0f;//图片高度小于控件宽度时,不允许上下移动if (rect.height() <= getHeight())dy = 0.0f;//移动距离等于0,那就不需要移动了if (dx == 0.0f && dy == 0.0f)return;mScaleMatrix.postTranslate(dx, dy);setImageMatrix(mScaleMatrix);//去除移动边界removeBorderAndTranslationCenter();}//消除控件边界和把图片移动到中间private void removeBorderAndTranslationCenter() {RectF rectF = getMatrixRectF();if (rectF == null)return;int width = getWidth();int height = getHeight();float widthF = rectF.width();float heightF = rectF.height();float left = rectF.left;float right = rectF.right;float top = rectF.top;float bottom = rectF.bottom;float translationX = 0.0f, translationY = 0.0f;if (left > 0) {//左边有边界if (widthF > width) {//图片宽度大于控件宽度,移动到左边贴边translationX = -left;} else {//图片宽度小于控件宽度,移动到中间translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);}} else if (right < width) {//右边有边界if (widthF > width) {//图片宽度大于控件宽度,移动到右边贴边translationX = width - right;} else {//图片宽度小于控件宽度,移动到中间translationX = width * 1.0f / 2f - (widthF * 1.0f / 2f + left);}}if (top > 0) {//顶部有边界if (heightF > height) {//图片高度大于控件高度,去除顶部边界translationY = -top;} else {//图片高度小于控件宽度,移动到中间translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);}} else if (bottom < height) {//底部有边界if (heightF > height) {//图片高度大于控件高度,去除顶部边界translationY = height - bottom;} else {//图片高度小于控件宽度,移动到中间translationY = height * 1.0f / 2f - (top + heightF * 1.0f / 2f);}}mScaleMatrix.postTranslate(translationX, translationY);setImageMatrix(mScaleMatrix);}/*** 双击改变大小** @param x 点击的中心点* @param y 点击的中心点*/private void onDoubleDrowScale(float x, float y) {//如果缩放动画已经在执行,那就不执行任何事件if (mAnimator != null && mAnimator.isRunning())return;float drowScale = getDoubleDrowScale();//执行动画缩放,不然太难看了scaleAnimation(drowScale, x, y);}/*** 缩放动画** @param drowScale 缩放的比例* @param x         中心点* @param y         中心点*/private void scaleAnimation(final float drowScale, final float x, final float y) {if (mAnimator != null && mAnimator.isRunning())return;mAnimator = ObjectAnimator.ofFloat(getScale(), drowScale);mAnimator.setDuration(500);mAnimator.setInterpolator(new AccelerateInterpolator());mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float value = ((float) animation.getAnimatedValue()) / getScale();mScaleMatrix.postScale(value, value, x, y);setImageMatrix(mScaleMatrix);removeBorderAndTranslationCenter();}});mAnimator.start();}//返回双击后改变的大小比例(我们希望缩放误差在deviation范围内)private float getDoubleDrowScale() {float deviation = 0.05f;float drowScale = 1.0f;float scale = getScale();if (Math.abs(mInitScale - scale) < deviation)scale = mInitScale;if (Math.abs(mMidScale - scale) < deviation)scale = mMidScale;if (Math.abs(mMaxScale - scale) < deviation)scale = mMaxScale;if (scale != mMidScale) {//当前大小不等于mMidScale,则调整到mMidScaledrowScale = mMidScale;isEnlarge = scale < mMidScale;} else {//如果等于mMidScale,则判断放大或者缩小//判断是放大或者缩小,如果上次是放大,则继续放大,缩小则继续缩小if (isEnlarge) {//放大drowScale = mMaxScale;} else {//缩小drowScale = mInitScale;}}return drowScale;}//获取图片宽高以及左右上下边界private RectF getMatrixRectF() {Drawable drawable = getDrawable();if (drawable == null) {return null;}RectF rectF = new RectF(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());Matrix matrix = getImageMatrix();matrix.mapRect(rectF);return rectF;}/*** 获取当前图片的缩放值** @return*/private float getScale() {float[] values = new float[9];mScaleMatrix.getValues(values);return values[Matrix.MSCALE_X];}/*** 解决和父控件滑动冲突 只要图片边界超过控件边界,返回true** @param direction* @return true 禁止父控件滑动*/@Overridepublic boolean canScrollHorizontally(int direction) {RectF rect = getMatrixRectF();if (rect == null || rect.isEmpty())return false;if (direction > 0) {return rect.right >= getWidth() + 1;} else {return rect.left <= 0 - 1;}}/*** ** @param direction* @return*/@Overridepublic boolean canScrollVertically(int direction) {RectF rect = getMatrixRectF();if (rect == null || rect.isEmpty())return false;if (direction > 0) {return rect.bottom >= getHeight() + 1;} else {return rect.top <= -1;}}}

Android 自定义图片点击放大、缩小相关推荐

  1. 我的Android进阶之旅------android Matrix图片随意的放大缩小,拖动(转)

    step1:新建一个项目DragAndZoom,并准备一张照片放在res/drawable-hdpi目录下,如下图所示: step2: 设置应用的UI界面,在main.xml中设置: [html] v ...

  2. jQuery实现图片点击放大缩小(小案例)

        我们不废话,直接上例子.首先利用dom的垂直分层实现图片的点击放大和缩小(手机上使用的效果较好),在图片放大的时候同时禁止页面的滑动,如果在web端的话可以不禁止屏幕的滚动(因为图片放大是将图 ...

  3. 前端jquery实现图片点击放大缩小

    利用dom的垂直分层实现图片的点击放大和缩小(手机上使用的效果较好),在图片放大的时候同时禁止页面的滑动,如果在web端的话可以不禁止屏幕的滚动(因为图片放大是将图片的宽度变成100%,在web上长度 ...

  4. Android实现图片点击放大

    第一步: // 查看大图 implementation 'com.github.SherlockGougou:BigImageViewPager:v4_6.1.1' 第二步: 在图片点击事件里调用: ...

  5. android 自定义view实现拖动放大缩小_自定义itemClickView

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.自定义View类实现 二.自定义View标签 三.自定义View 布局 四.自定义View 选择器 ...

  6. android 自定义view实现拖动放大缩小_自定义itemCheckView

    阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 自定义View类实现 自定义View标签 ...

  7. android+放大缩小图片+有jar嘛,Android相册支持点击放大图片,滑动切换图片,手势放大缩小...

    [实例简介] 项目使用了开源框架Universal-Image-Loader 显示本地图库所有照片 点击放大,单击退出 双击放大缩小 支持左右滑动查看图片 支持手势放大缩小图片 [实例截图] [核心代 ...

  8. android 自定义图片,Android自定义图片集合

    本文主要包括以下内容: 使用Xfermode设置圆角图片 使用BitmapShader设置圆角图片 滑动旋转缩放的bimp图片 图片颜色处理(滑动) 图片 + 文字 其中1,2是两种不同方式处理图片圆 ...

  9. layui 怎么设置点击图片放大_layui实现一个图片点击放大

    layui实现一个图片点击放大 2019-10-27 01:58:45  卢浮宫  版权声明:本文为站长原创文章,转载请写明出处 QQ分享 一.背景 业务需求,实现一个图片点击放大功能.之前有说个一个 ...

最新文章

  1. 关于mysql的ddl_log.log文件
  2. Hadoop 新 MapReduce 框架 Yarn 详解
  3. Linux - 查看、修改、更新系统时间(自动同步网络时间)
  4. Erlang消息传递-tut15.erl
  5. url存在宽字节跨站漏洞_【XSS漏洞】XSS漏洞相关总结v1.0
  6. agx 安装ros opencv_Linux下配置深度学习开发环境(及ros)
  7. php导航栏代码子菜单找不到,php – 下拉导航菜单,显示每个类别的最新帖子
  8. ansys怎么删除线段_如何彻底删除ansys
  9. 如何在word编辑文本框,教程来啦,怎样在word编辑文本框
  10. 教程丨GIS制图教程01
  11. python实战项目词云生成器(wordcloud+jieba+pyinstaller打包)——词云生成软件【Pyinstaller打包问题解决】
  12. ISO9000中服装加工行业应执行哪些检验标准?
  13. Vue.js实战——内置指令(一)
  14. 电子计算机快速算法,序列产生的快速算法
  15. 微信分享链接含敏感词被屏蔽的问题
  16. OpenCV Java入门三 Mat的基本操作
  17. css替换csgo弹道,csgo怎么能让弹道更明显一些?
  18. APK反编译工具推荐----Jadx
  19. 计算机网络 | 网络概述(什么是互联网 互联网结构)
  20. 函数式编程中的重要概念

热门文章

  1. 移动100m宽带慢的要死_wifi慢到快崩溃明明100m宽带却像2m的网速教你1招快速解决...
  2. 300M宽带网速只有16M?下载速度达到多少才算正常?
  3. Android LCD整理二:mtk平台LCD流程分析(LK部分)
  4. bzoj 1123: [POI2008]BLO(Trajan求割点)
  5. 由DBeaver与PL/SQL引发的数据库吐槽
  6. java畜牧场信息管理系统
  7. 10本 JavaScript PDF 书籍免费分享
  8. 智能井盖运用5G技术
  9. 解决win10 安装dnw驱动,每次重启都得禁用数字签名。解决命令行操作,设置元素数据时出错。电脑关闭Secure Boot
  10. 2017校招信息每日汇总(更新至8.4)