zoukankan      html  css  js  c++  java
  • Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView

    目标需求

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

    实现流程

      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      当然, 也可以直接访问到指定目录看到ZoomableDraweeViewhttps://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();
        }
    }

      

    
    
    
  • 相关阅读:
    TortoiseGit学习系列之TortoiseGit基本操作修改提交项目(图文详解)
    TortoiseGit学习系列之TortoiseGit基本操作克隆项目(图文详解)
    TortoiseGit学习系列之Windows上本地代码如何通过TortoiserGit提交到GitHub详解(图文)
    TortoiseGit学习系列之Windows上TortoiseGit的安装详解(图文)
    TortoiseGit学习系列之TortoiseGit是什么?
    Cloudera Manager集群官方默认的各个组件开启默认顺序(图文详解)
    IntelliJ IDEA 代码字体大小的快捷键设置放大缩小(很实用)(图文详解)
    Jenkins+Ant+SVN+Jmeter实现持续集成
    jmeter+Jenkins 持续集成中发送邮件报错:MessagingException message: Exception reading response
    jmeter+Jenkins持续集成(四、定时任务和邮件通知)
  • 原文地址:https://www.cnblogs.com/guanxinjing/p/10481917.html
Copyright © 2011-2022 走看看