最近在实现一个类似淘宝中的评论列表的功能,其中要在列表中显示评论图,点击图片后显示大图进行查看,各家app几乎都会有这样的功能。

可以看到,一个体验较好的查看大图的基本功能有,

第一,左右滑动时切换图片;

第二,双击或双指缩放实现图片的缩放;

第三,图片放大时,滑动到边缘继续滑动时,切换图片。

因为我们的app中使用了fresco库,但fresco提供的SimpleDraweeView不支持缩放,看网上有人扩展了SimpleDraweeView,使之支持缩放。但经过漫长的调研,发现fresco近期提供了一个新的sample:ZoomableDraweeView,专门用来支持缩放,欣喜若狂的下载下来把玩了一把,发现三个需求点都满足!可惜的是,这个控件在细节上有几点不满足:双击后放大到最大,再双击后却缩小为最小(期望恢复为正常大小),虽然最小可以设置,但这个值应该是在双指缩小时才用到。另一点是在双指缩小并松开后,图片保持在那个缩小的尺寸(期望自动恢复为正常大小)。

查看代码后发现需要修改几点就可以满足我的需求。下面的内容主要记录我思考问题、解决问题的思路,如果你也有类似的需求,可以直接拿代码:https://github.com/ibosong/CommentGallery

1. 双击恢复正常尺寸

修改DoubleTapGestureListener 中的onDoubleTapEvent方法,因为主要修改的逻辑在双指松开后,于是我们在MotionEvent.ACTION_UP的case中修改相关逻辑。首先判断mDoubleTapScroll,即是否是双击后不松开并滑动的操作,这种操作下如果在松开手指时,图片为缩小状态,应当恢复正常大小,所以将原代码:

if (mDoubleTapScroll) {
  float scale = calcScale(vp);
  zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
}

修改为:

if (mDoubleTapScroll) {
    float scale = calcScale(vp);
    if (scale < 1.0f) {
        zc.zoomToPoint(1.0f, mDoubleTapImagePoint, mDoubleTapViewPoint,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,
                null);
    } else {
        zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
    }
}

else里面的代码是正常双击后的代码,将其中的minScale 改为1.0f即可

else {
    final float maxScale = zc.getMaxScaleFactor();
    final float minScale = zc.getMinScaleFactor();
    if (zc.getScaleFactor() < (maxScale + minScale) / 2) {
        zc.zoomToPoint(
                maxScale,
                ip,
                vp,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,
                null);

    } else {
        zc.zoomToPoint(
                /*minScale*/1.0f,
                ip,
                vp,
                DefaultZoomableController.LIMIT_ALL,
                DURATION_MS,
                null);
    }
}

2. 双指缩放,处理双指缩小图片后松开手指的情况

阅读代码可知,ZoomableDraweeView中的onTouchEvent方法调用了DefaultZoomableController的onTouchEvent方法,这里面通过mGestureDetector的处理,最终回调到ZoomableDraweeView中的onGestureBegin,onGestureUpdate和onGestureEnd这三个方法中。mGestureDetector的处理是在MultiPointerGestureDetector的onTouchEvent方法中。这里面原来的按下和松开手指的逻辑是这样的:

case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP: {
  // restart gesture whenever the number of pointers changes
  mNewPointerCount = getPressedPointerCount(event);
  stopGesture();
  updatePointersOnTap(event);
  if (mPointerCount > 0 && shouldStartGesture()) {
    startGesture();
  }
  break;} 

每次在MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP情况下执行相同的动作:先stopGesture,然后startGesture,即先触发onGestureEnd,然后触发onGestureBegin。显然这样的处理是不合逻辑的,为什么在手指按下的时候要触发onGestureEnd?于是我们将代码修改为:

case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
    mNewPointerCount = getPressedPointerCount(event);
    updatePointersOnTap(event);
    if (mPointerCount > 0 && shouldStartGesture()) {
        startGesture();
    }
    break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP: {
    mNewPointerCount = getPressedPointerCount(event);    updatePointersOnTap(event);
    stopGesture();
    break;
}

在手指按下的时候触发onGestureBegin,手指抬起的时候触发onGestureEnd。这时候我们只要在DefaultZoomableController中的onGestureEnd方法中处理松开手指的情况:如果图片被缩小,则通过调用zoomToPoint方法将图片恢复正常大小。

@Override

public void onGestureEnd(TransformGestureDetector detector) {
    FLog.v(TAG, "onGestureEnd");
    // When the image was zoomed in, releasing the fingers will restore the size of image.
    if (getScaleFactor() < 1.0f) {
        zoomToPoint(1.0f, new PointF(0.f, 0.f), new PointF(0.f, 0.f));
    }
}

这里onGestureUpdate方法里的逻辑也要改一下,不要再调用mGestureDetector.restartGesture()。

@Overridepublic void onGestureUpdate(TransformGestureDetector detector) {
     FLog.v(TAG, "onGestureUpdate");
     boolean transformCorrected = calculateGestureTransform(mActiveTransform, LIMIT_ALL);
     onTransformChanged();
  // if (transformCorrected) {
  // mGestureDetector.restartGesture();
  // }
   // A transformation happened, but was it without correction?  mWasTransformCorrected = transformCorrected;
}

这样实现,操作起来比较生硬,恢复大小的时候没有动画。

于是我们将onGestureEnd中的处理移至AbstractAnimatedZoomableController中,并将zoomToPoint修改为另一个实现了动画的重载的方法:

@Override
public void onGestureEnd(TransformGestureDetector detector) {
    // When the image was zoomed in, releasing the fingers will restore the size of image.
    if (getScaleFactor() < 1.0f) {
        zoomToPoint(1.0f, new PointF(0.f, 0.f), new PointF(0.f, 0.f), LIMIT_ALL, 300, null);
    }
}

这样我们的改造就全部完成了,安装体验一下。

支持缩放的fresco图片控件 —— fresco sample: ZoomableDraweeView的更多相关文章

  1. 关于图片加载非常爽的一个三方控件 fresco,一个三fresco

    Hi  EveryBody 今天来玩一个非常爽的控件 fresco 到底有多爽呢 接着看就知道了 首先 来看看fresco 是个神马东西 https://github.com/facebook/fre ...

  2. wxPython缩放图片控件的一个小例子

    前几天写程序的时候,想有个自适应的图片控件,但是一直没有找到合适的解决方案.今天终于解决了这个问题,发在这里,以供参考. 程序截图: 文件下载地址: http://files.cnblogs.com/ ...

  3. Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...

  4. 安卓开发:UI组件-图片控件ImageView(使用Glide)和ScrollView

    2.7ImageView 2.7.1插入本地图片 一个图片控件,可以用来显示本地和网络图片. 在首页添加按钮ImageView,指向新页面(步骤与前同,不再详写). activity_image_vi ...

  5. FastReport.Net使用:[16]图片控件使用

    FastReport中,图片(Picture)控件的用法? 支持的图片格式 1.BMP, PNG, JPG, GIF, TIFF, ICO, EMF, WMF 支持的数据源 支持图片,数据列,文件名, ...

  6. WPF自定义控件之图片控件 AsyncImage

    AsyncImage 是一个封装完善,使用简便,功能齐全的WPF图片控件,比直接使用Image相对来说更加方便,但它的内部仍然使用Image承载图像,只不过在其基础上进行了一次完善成熟的封装 Asyn ...

  7. CYQ.Data 支持WPF相关的数据控件绑定(2013-08-09)

    事件的结果 经过多天的思考及忙碌的开发及测试,CYQ.Data 终于在UI上全面支持WPF,至此,CYQ.Data 已经可以方便支持wpf的开发,同时,框架仍保留最低.net framework2.0 ...

  8. MFC编程入门之二十七(常用控件:图片控件PictureControl)

    上一节讲的是滚动条控件,本节主要讲一种简单实用的控件,图片控件Picture Control.我们可以在界面某个位置放入图片控件,显示图片以美化界面. 图片控件简介 图片控件和前面讲到的静态文本框都是 ...

  9. VS2010/MFC常用控件:图片控件Picture Control

    图片控件Picture Control 本节主要讲一种简单实用的控件,图片控件Picture Control.我们可以在界面某个位置放入图片控件,显示图片以美化界面. 图片控件简介 图片控件和前面讲到 ...

随机推荐

  1. 【python之路11】集合数据类型(set)

    集合数据类型(set):集合是不重复的无需序列 1.集合数据类型的创建 a = {11,22,33} #或 a = set() #创建空集合,不能用a={},这样创建的是字典类型 2.集合转换(将可迭 ...

  2. Oracle用户权限分配

    一.权限分类 系统权限:系统规定用户使用数据库的权限.(系统权限是对用户而言). 实体权限:某种权限用户对其它用户的表或视图的存取权限.(是针对表或视图而言的). 二.系统权限管理 1.系统权限分类: ...

  3. IM 融云 之 列表中显示聊天用户名称

    现在发现,聊天列表中,用户名称没有显示出来.

  4. zepto.js swipe实现触屏tab菜单

    今天我们来说下zepto.js,有兴趣的朋友可以先进这个网站“http://zeptojs.com/” ,这个可以说是手机里的jquery,但是它取消了hover,加上了swipe及tap这两个触屏功 ...

  5. php刷新当前页面

    echo "<script language=JavaScript> location.replace(location.href);</script>"; ...

  6. BNU Online Judge-34776-What does the fox say?

    题目链接 http://www.bnuoj.com/bnuoj/problem_show.php?pid=34776 题意: fox 的叫声 例如测试用例 输入 toot woof wa ow ow ...

  7. JavaScript的4种this调用模式

    方法调用模式:函数调用模式:构造器调用模式:apply调用模式: 方法调用模式: 当一个函数被保存为对象的一个属性时,我们称它为一个方法.当一个方法被调用时,this被绑定到该对象. 函数调用模式: ...

  8. Error while registering Oracle JDBC Diagnosabilityh

    Error while registering Oracle JDBC Diagnosability 把ojdbc6.jar换成ojdbc14.jar就可以了: 后来发现又没有问题了:不过据说这个是数 ...

  9. Java策略模式(Strategy模式) 之体验

    <JAVA与模式>之策略模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述策略(Strategy)模式的: 策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法 ...

  10. oracle的位图索引和函数索引

    1.位图索引 位图索引适用于性别.婚姻状态.行政区等只有几列固定值的类型列,身份证号等就不适合位图索引,位图索引适用于静态数据,频繁更新的字段不适用建立位图索引,因为更新会导致索引块区的变更,还会引起 ...