目标需求

  实现一张小图片,被点击后变成一个在整个屏幕上显示的大图片.类似于微信朋友圈的图片.

实现流程

  1.Fresco基本初始化

  2.下载并且导入ZoomableDraweeView 它是实现大图的关键view

  3.创建activity,在布局文件里加入ZoomableDraweeView设置为全屏幕占满.(如果你需要多图翻页浏览功能,请另外添加ViewPager在放入ZoomableDraweeView)

  4.在activity配置需要加载的图片

需要访问的网址:

  Fresco的github: https://github.com/facebook/fresco

  Zoomable包路径: https://github.com/facebook/fresco/tree/master/samples/zoomable

Fresco基本初始化

  这个流程我就不废话了,如果这个还没了解过它,请移步 https://www.cnblogs.com/guanxinjing/p/10364380.html

  

下载并且导入ZoomableDraweeView

  接下来是关键点Zoomable是Fresco Demo工程里自带的图片缩放库,但是它并不在依赖包里.所以你依赖了Fresco也无法找到这个View.所以我们需要手动找到这个包并且导入它.

  1.第一步找到它:

  在官方文档里只有一个小地方标注了它的存在,在这个官方文档网址:https://www.fresco-cn.org/docs/sample-code.html     当然, 也可以直接访问到指定目录看到ZoomableDraweeView:  https://github.com/facebook/fresco/tree/master/samples/zoomable

  

  就是这个缩放库,没有任何详细解释

  2.第二步 下载整个Fresco demo工程

  在github里将这个工程下载下来,这个不需要多说啥了

  3.第三步 导入gestures包

  ZoomableDraweeView的缩放实现还需要这个demo工程里的一个手势处理包就是这个gestures包,它的路径如下图所示:

  

  找到它,将这个java文件放到你的工程里

  4.第四步 导入Zoomable

  路径如下:

  

  将这个包里的所有文件放到你的工程里,并且将一些报错依赖路径重新指向正确依赖路径

创建activity,在布局文件里加入ZoomableDraweeView设置为全屏幕占满

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".work.share.ZoomableActivity"> <com.yt.kangaroo.widgets.zoomable.ZoomableDraweeView
android:id="@+id/zoomable"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>

在activity配置需要加载的图片

 @Override
public void initView() {
mZoomableDraweeView = (ZoomableDraweeView)findViewById(R.id.zoomable);
mZoomableDraweeView.setIsLongpressEnabled(false);//长按
// mZoomableDraweeView.setAllowTouchInterceptionWhileZoomed(true);//是否允许缩放时左右切换(如果设置为true,则父视图可以在视图缩放时截获触摸事件)
mZoomableDraweeView.setTapListener(new DoubleTapGestureListener(mZoomableDraweeView));//双击击放大或缩小
DraweeController controller = Fresco.newDraweeControllerBuilder()//创建Fresco的图片下载配置
.setUri("https://s1.52poke.wiki/wiki/thumb/7/73/002Ivysaur.png/300px-002Ivysaur.png")
.build();
mZoomableDraweeView.setController(controller);//将下载配置导入 }

其他api


mZoomableDraweeView.setZoomingEnabled(false);//设置是否缩放

如果你需要实现单击功能

  这个 ZoomableDraweeView已经将触摸交给双击监听处理类DoubleTapGestureListener了,所以你无法使用setOnClickListener();方法实现ZoomableDraweeView的单击监听

mZoomableDraweeView.setTapListener(new DoubleTapGestureListener(mZoomableDraweeView));//双击击放大或缩小

  这行代码就已经表示了,作者自己实现了一个DoubleTapGestureListener(双击监听类,作者主要用来双击放大缩小图片),然后设置给TapListener,所以这个时候单击已经被拦截了.所以目前只有2个方法

  1.在ZoomableDraweeView里实现onTouchEvent判断单击事件,这样处理太费时费力,且一不小心就会破坏原有的其他触摸手势功能

  2.我们也重写DoubleTapGestureListener这个类,在作者原有的DoubleTapGestureListener里面添加我们的单击事件然后接口出去.

所以我们使用第二种方法来实现单击事件,做法如下:

  在DoubleTapGestureListener里重写一下,增加重写onSingleTapConfirmed方法(要注意只有onSingleTapConfirmed方法是单击确定后的回调):

/**
* Tap gesture listener for double tap to zoom / unzoom and double-tap-and-drag to zoom.
*
* @see ZoomableDraweeView#setTapListener(GestureDetector.SimpleOnGestureListener)
*/
public class DoubleTapGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int DURATION_MS = 300;
private static final int DOUBLE_TAP_SCROLL_THRESHOLD = 20; private final ZoomableDraweeView mDraweeView;
private final PointF mDoubleTapViewPoint = new PointF();
private final PointF mDoubleTapImagePoint = new PointF();
private float mDoubleTapScale = 1;
private boolean mDoubleTapScroll = false;
private OnSingleClickListener mListener; public DoubleTapGestureListener(ZoomableDraweeView zoomableDraweeView) {
mDraweeView = zoomableDraweeView;
} /**
* 重写这个方法实现单击监听
* @param e
* @return
*/
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
if (mListener != null){
mListener.onSingleClick();
}
return true;
} @Override
public boolean onDoubleTapEvent(MotionEvent e) {
AbstractAnimatedZoomableController zc =
(AbstractAnimatedZoomableController) mDraweeView.getZoomableController();
PointF vp = new PointF(e.getX(), e.getY());
PointF ip = zc.mapViewToImage(vp);
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mDoubleTapViewPoint.set(vp);
mDoubleTapImagePoint.set(ip);
mDoubleTapScale = zc.getScaleFactor();
break;
case MotionEvent.ACTION_MOVE:
mDoubleTapScroll = mDoubleTapScroll || shouldStartDoubleTapScroll(vp);
if (mDoubleTapScroll) {
float scale = calcScale(vp);
zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
}
break;
case MotionEvent.ACTION_UP:
if (mDoubleTapScroll) {
float scale = calcScale(vp);
zc.zoomToPoint(scale, mDoubleTapImagePoint, mDoubleTapViewPoint);
} 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,
ip,
vp,
DefaultZoomableController.LIMIT_ALL,
DURATION_MS,
null);
}
}
mDoubleTapScroll = false;
break;
}
return true;
} private boolean shouldStartDoubleTapScroll(PointF viewPoint) {
double dist = Math.hypot(
viewPoint.x - mDoubleTapViewPoint.x,
viewPoint.y - mDoubleTapViewPoint.y);
return dist > DOUBLE_TAP_SCROLL_THRESHOLD;
} private float calcScale(PointF currentViewPoint) {
float dy = (currentViewPoint.y - mDoubleTapViewPoint.y);
float t = 1 + Math.abs(dy) * 0.001f;
return (dy < 0) ? mDoubleTapScale / t : mDoubleTapScale * t;
} public void setOnSingleClick(OnSingleClickListener listener){
this.mListener = listener;
} /**
* 实现单击接口
*/
public interface OnSingleClickListener{
void onSingleClick(); } }

activity里实现单击回调:

DoubleTapGestureListener doubleTapGestureListener = new DoubleTapGestureListener(mZoomableDraweeView);
doubleTapGestureListener.setOnSingleClick(new DoubleTapGestureListener.OnSingleClickListener() { //实现双击监听里的单击功能监听(双击作者这个View已经实现处理了)
@Override
public void onSingleClick() {
finish();
}
});

嵌套ViewPager

下面的demo不是完整的,图片计数没做,但是功能已经实现了

activity_zoomable_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".work.share.ZoomableActivity"> <androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"> </androidx.viewpager.widget.ViewPager> <TextView
android:id="@+id/image_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="数量"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
package com.yt.kangaroo.work.share.zoomable_pager;

import android.content.Intent;
import android.graphics.drawable.Animatable;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast; import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.imagepipeline.request.ImageRequest;
import com.yt.kangaroo.R;
import com.yt.kangaroo.app.AppEventBusMsg;
import com.yt.kangaroo.app.BaseActivity;
import com.yt.kangaroo.net.teacherNet.TClircleListBase;
import com.yt.kangaroo.utils.L;
import com.yt.kangaroo.utils.ThumbnailUtil;
import com.yt.kangaroo.widgets.zoomable.DoubleTapGestureListener;
import com.yt.kangaroo.widgets.zoomable.ZoomableDraweeView; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList;
import java.util.List; /**
*@content:左右滑页大图片显示Activity
*@time:2019-6-21
*@build:
*/ public class ZoomablePagerActivity extends BaseActivity {
public static final String T_CLIRCLE_IMAGE_KEY = "TClircleImage";
private List<TClircleListBase.FriendsPublish.Pic> mTPicList;
private ViewPager mViewPager;
private TextView mImageCount;
private ZoomablePagerAdapter mAdapter;
private long mBackDelay = 0; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListener();
EventBus.getDefault().register(this);
mBackDelay = System.currentTimeMillis();
} @Override
public int getLayout() {
return R.layout.activity_zoomable_pager;
} @Override
public void initView() {
mViewPager = findViewById(R.id.view_pager);
mImageCount = findViewById(R.id.image_count);
mAdapter = new ZoomablePagerAdapter();
mViewPager.setAdapter(mAdapter); } private void initListener(){
mAdapter.setOnSingleClick(new ZoomablePagerAdapter.OnSingleClickListener() {
@Override
public void onSingleClick() {
if (System.currentTimeMillis() - mBackDelay > 1*1000){ //退出延迟,太快的返回进出Activity会导致EventBus发送数据出现问题
EventBus.getDefault().unregister(this);
finish();
}
}
});
} @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onUiThread(AppEventBusMsg msg){
L.e("接到数据onUiThread");
if (msg.getKey().equals(T_CLIRCLE_IMAGE_KEY)){
L.e("接到数据T_CLIRCLE_IMAGE_KEY");
mTPicList = msg.getObjectList();
List<String> urlList = new ArrayList<>();
for (TClircleListBase.FriendsPublish.Pic pic : mTPicList){
urlList.add(pic.getPicUrl()); }
L.e("urlList 长度="+urlList.size());
mAdapter.refreshData(urlList); }
EventBus.getDefault().removeStickyEvent(msg); } @Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
zoomable_pager_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"> <com.yt.kangaroo.widgets.zoomable.ZoomableDraweeView
android:id="@+id/zoomable"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/colorBlack1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> <ProgressBar
android:id="@+id/progress"
android:layout_width="40dp"
android:layout_height="40dp"
android:visibility="visible"
android:indeterminateDrawable="@anim/ic_wait"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
package com.yt.kangaroo.work.share.zoomable_pager;

import android.graphics.drawable.Animatable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.Toast; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.PagerAdapter; import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.imagepipeline.request.ImageRequest;
import com.yt.kangaroo.R; import com.yt.kangaroo.utils.L;
import com.yt.kangaroo.utils.ThumbnailUtil;
import com.yt.kangaroo.widgets.zoomable.DoubleTapGestureListener;
import com.yt.kangaroo.widgets.zoomable.ZoomableDraweeView; import java.util.ArrayList;
import java.util.List;
/**
*@content:左右滑页大图片显示适配器
*@time:2019-6-21
*@build:zhouqiang
*/
public class ZoomablePagerAdapter extends PagerAdapter {
private List<String> mImageUrlList = new ArrayList<>();
private OnSingleClickListener mOnSingleClickListener; public void refreshData(List<String> imageUrl){
L.e("触发refresh");
mImageUrlList.clear();
mImageUrlList.addAll(imageUrl);
notifyDataSetChanged(); } @Override
public int getCount() {
L.e("触发getCount="+mImageUrlList.size());
return mImageUrlList.size();
} @Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
} @NonNull
@Override
public Object instantiateItem(@NonNull final ViewGroup container, int position) {
L.e("触发instantiateItem");
View view = LayoutInflater.from(container.getContext()).inflate(R.layout.zoomable_pager_item, container, false);
ZoomableDraweeView zoomableDraweeView = view.findViewById(R.id.zoomable);
final ProgressBar progressBar = view.findViewById(R.id.progress);
zoomableDraweeView.setIsLongpressEnabled(false);//长按
DoubleTapGestureListener doubleTapGestureListener = new DoubleTapGestureListener(zoomableDraweeView);
doubleTapGestureListener.setOnSingleClick(new DoubleTapGestureListener.OnSingleClickListener() { //实现双击监听里的单击功能监听(双击作者这个View已经实现处理了)
@Override
public void onSingleClick() {
if (mOnSingleClickListener != null){
mOnSingleClickListener.onSingleClick();
} }
});
zoomableDraweeView.setTapListener(doubleTapGestureListener);//双击击放大或缩小
ControllerListener controllerListener = new ControllerListener() {
@Override
public void onSubmit(String id, Object callerContext) {
//开始提交
progressBar.setVisibility(View.VISIBLE); } @Override
public void onFinalImageSet(String id, @Nullable Object imageInfo, @Nullable Animatable animatable) {
//完成
progressBar.setVisibility(View.GONE); } @Override
public void onIntermediateImageSet(String id, @Nullable Object imageInfo) {
//中间图像集 } @Override
public void onIntermediateImageFailed(String id, Throwable throwable) {
//中间图像上失败 } @Override
public void onFailure(String id, Throwable throwable) {
//失败
Toast.makeText(container.getContext(),"网络异常,图片加载失败",Toast.LENGTH_LONG).show(); } @Override
public void onRelease(String id) { //释放 }
};
DraweeController controller = Fresco.newDraweeControllerBuilder()//创建Fresco的图片下载配置
.setControllerListener(controllerListener)
.setLowResImageRequest(ImageRequest.fromUri(ThumbnailUtil.handlerImageUrl(mImageUrlList.get(position))))
.setImageRequest(ImageRequest.fromUri(mImageUrlList.get(position)))
.setOldController(zoomableDraweeView.getController())
.build();
zoomableDraweeView.setController(controller);//将下载配置导入
container.addView(view);//注意别忘记添加
return view;
} @Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View)object);
} public void setOnSingleClick(OnSingleClickListener listener){
mOnSingleClickListener = listener; } public interface OnSingleClickListener{
void onSingleClick();
}
}

  

												

Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView的更多相关文章

  1. Android浏览图片,点击放大至全屏效果

    做到照片浏览的功能,对于QQ空间中点击图片放大至全屏,感觉效果很赞,于是也做了个类似的效果.如下. 我不知道QQ那个是怎么做的,我的思路如下: 首先,从图片缩略界面跳转到图片详情页面,应该是从一个Ac ...

  2. Android 实现九宫格、点击图片放大全屏浏览等

    项目GitHub地址https://github.com/tikeyc/TNinePlaceGridView_Android https://github.com/tikeyc/TikeycAndro ...

  3. Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(2)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  4. Android开发之漫漫长途 Ⅱ——Activity的显示之Window和View(1)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  5. Android开发之漫漫长途 Ⅲ——Activity的显示之Window和View(2)

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  6. Android开发中如何强制横屏和强制竖屏设置

    Android开发中如何强制横屏和强制竖屏设置 强制横屏设置: 按照下面代码示例修改Activity的onResume方法 @Override protected void onResume() { ...

  7. VMware上安装的Ubuntu不显示全屏解决方法

    花费了好一会才把电脑上的Vmware装上,把Ubuntu装到虚拟机上,谁知道Ubuntu不显示全屏,我调了分辨率,奈何Ubuntu里面固定的分辨率没有跟我电脑匹配的,然后开始寻找解决方法,在网上找了很 ...

  8. Android开发之漫漫长途 Ⅳ——Activity的显示之ViewRootImpl初探

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  9. Android开发之漫漫长途 Ⅴ——Activity的显示之ViewRootImpl的PreMeasure、WindowLayout、EndMeasure、Layout、Draw

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

随机推荐

  1. java中的hashmap理解

    转自大神,以便以后翻阅http://www.cnblogs.com/whgk/p/6091316.html

  2. .net core+Spring Cloud学习之路 一

    文章开头唠叨两句. 2019年了,而自己参加工作也两年有余了,用一个词来概括这两年多的生活,就是:“碌碌无为”. 也不能说一点收获都没有,但是很少.2019来了,我立志要打破现状,改变自己,突破自我. ...

  3. ubuntu18安装navicat

    1.登陆 http://www.navicat.com.cn/download/navicat-for-mysql 页面下载navicat安装包,务必选位置1-64bit ps: 中文版乱码问题严重, ...

  4. 学习笔记DL005:线性相关、生成子空间,范数,特殊类型矩阵、向量

    线性相关.生成子空间. 逆矩阵A⁽-1⁾存在,Ax=b 每个向量b恰好存在一个解.方程组,向量b某些值,可能不存在解,或者存在无限多个解.x.y是方程组的解,z=αx+(1-α),α取任意实数. A列 ...

  5. asp.net 按钮执行前后台方法——前台弹出提示信息,确认后继续执行后台方法,取消则不执行后台方法

    我们做一个测试的web页面,只需要一个button+一个label就ok啦,通过button按钮的后台事件修改label的text属性值来测试是否执行了后台事件里的代码 前台 写一个js方法: < ...

  6. 1.2.7 Excel表格打印技巧

    1.打印居中显示 把打印的内容放在纸张中间,居中对齐. 方法: ①点击[页面布局]选项卡: ②找到[页面设置]群组点击右下角显示更多: ③在页边距对话框中选择[页边距]: ④勾选[居中方式]中的[水平 ...

  7. spring事务详解(四)测试验证

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  8. mysql error 1067 invalid default timestamp

    问题 MySQL 5.7版本,在创建数据表时,使用以下语句定义一个字段: `update_time` timestamp DEFAULT '0000-00-00 00:00:00' ON UPDATE ...

  9. 在DataFrame数据表里面提取需要的行

    在DataFrame数据表里面提取需要的行 代码功能: 在DataFrame表格中使用loc(),得到我们想要的行,然后根据某一列元素的值进行排序 此代码中还展示了为DataFrame添加列,即直接n ...

  10. css 实现等分布局

    目前移动版等分布局最常用的是 flex 等分,pc 端上用得更多则是 float. 假设父元素下有 3 个子元素,每个子元素相隔 24px,子元素等分父元素宽度 实现:float + margin ( ...