目标需求

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

实现流程

  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. 前端开发模拟数据------webpack-api-mocker

    应用场景: 在实际的项目开发过程中,一般都会进行前后端分离的开发模式,前端通过mock或者其他的插件模拟后台返回数据的功能.在常用的webpack构建工程项目中,通过和webpack-dev-serv ...

  2. BZOJ 4265 货币系统

    今天比赛的时候做到的.题解写得很简单,但是感觉对于我这种蒟蒻还是很有思考的价值的. 题面(由于题面很短,就不概括了):小Q当上了新的宇宙大总统,他现在准备重新设计一套货币系统. 这个货币系统要求一共有 ...

  3. 【puppeteer】前端自动化初探(一)

    一.前提 windows环境的puppeteer环境配置要简单点,mac环境坑竟然有点多,这边稍微提下 二.开发环境 nodejs puppeteer mac 三.简单介绍下puppeteer Pup ...

  4. oracle11g 数据库修改 UTF8字符集

    步骤一:执行以下命令 sqlplus "/as sysdba" conn /as sysdba; shutdown immediate; startup mount; ALTER ...

  5. Application、QueryString、session、cookie、ViewState、Server.Transfer等

    Application: WebForm1.aspx: protected void Button1_Click(object sender, EventArgs e) { ; Response.Re ...

  6. 《我的嵌入式开发》---- IIC 通信

    IIC 通用文件,文件是在NRF51xx 芯片基础,keil 平台开发测试通过,后期修改为STM32F2xx系列的配置. 文件百度云盘链接 : https://pan.baidu.com/s/1AFx ...

  7. 使用Visual Studio给SQL生成测试数据

    参考:http://www.cnblogs.com/CareySon/archive/2012/02/20/2359444.html 使用VS2010的数据生成计划来生成测试数据 以下面两个表来做例子 ...

  8. Windows 7 X64平台编译LLVM+clang

    1 源码包 去LLVM官方网站下载最新的源码,Windows平台下载三个即可(2019.04.24版本为LLVM 8.0.0): LLVM source code (.sig) Clang sourc ...

  9. Struts2单文件上传原理及示例

    一.文件上传的原理 表单元素的enctype属性指定的是表单数据的编码方式,该属性有3个值: 1.application/x-www-form-urlencoded:这是默认编码方式,它只处理表单域里 ...

  10. DOM 核心

    继承在DOM中的重要性: 1. Node 对象 2. Element 对象 3. Document 对象