一直以来都觉的在Android上浏览图片没有IOS体验那么丝滑,包括像淘宝在内的大型App在看图组件的体验上都存在着明显的Bug,例如不跟手,多指触控冲突处理不够完善,动画不流畅卡顿等等问题。 目前Android主流图片加载库基本以Glide和Fresco为主,大部分场景下两者性能上也不至于有明显的差别,Glide因为易用性更为流行。但是在低端机型和特定场景的性能表现还有图片格式支持的种类上Fresco还是具有一定优势,因此也有不少中大型App选择Fresco作为项目的图片加载库。
FrescoPhotoView是完全基于Fresco特性实现的看图组件,支持流畅的转场动画,自定义缩放级别,手势监听,简单的来说就是扩展了DraweeView,部分实现参考了官方给到的Demo,在体验上更加丝滑,跟手。如果你的项目使用的是Fresco,请毫不犹豫的使用FrescoPhotoView吧。
Download
dependencies {
implementation 'com.github.ccyzml:FrescoPhotoView:1.0.0'
}
复制代码
Usage
基本使用
frescoPhotoView = findViewById(R.id.photo_view)
val controller: DraweeController = Fresco.newDraweeControllerBuilder()
.setUri("url")
.build()
frescoPhotoView.controller = controller
//是否允许缩放
frescoPhotoView.setZoomingEnabled(allowZooming)
//是否允许移动
frescoPhotoView.setTranslationEnabled(allowTransition)
复制代码
手势监听
frescoPhotoView.setTapListener(object : SimpleOnGestureListener() {
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
return super.onFling(e1, e2, velocityX, velocityY)
}
override fun onDoubleTap(e: MotionEvent): Boolean {
return super.onDoubleTap(e)
}
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
return super.onSingleTapConfirmed(e)
}
override fun onLongPress(e: MotionEvent) {
super.onLongPress(e)
}
})
复制代码
自定义缩放级别
//设置最大放缩大小
frescoPhotoView.setMaxScaleFactor(4f)
//自定义放缩大小 ps:自定义的值不能超过上述的值
frescoPhotoView.setScaleFactorRetriever(object : ScaleFactorRetriever {
override fun nextFactor(currFactor: Float): Float {
if (currFactor >= 1 && currFactor < 2) {
return 2f
} else if (currFactor >= 2 && currFactor < 3) {
return 3f
} else if (currFactor >= 3) {
return 1f
}
return 1f
}
})
复制代码
嵌套滑动
//如果使用在viewpager等滑动容器中支持嵌套滑动
frescoPhotoView.setHorizontalNestedScrollEnabled(true)
复制代码
Advanced Usage
过渡动画
FrescoPhotoView并没有提供一个高度封装的组件,因为实际项目中通常会涉及到图片和视频和混排,图片还可能有gif,而视频的播放器通常也有很多选择如ExoPlayer,ijkPlayer,在动画过程中视频的播放状态如何选择,是播放还是暂停?看图过程中还有一些别的逻辑如何添加?很多提供了高度封装的项目都添加了许多极不优雅的配置代码,而且这些配置也只能满足部分场景,这种过渡封装反而失去了可扩展性,如果项目有一些需求有出入,修改起来将会变的非常变扭,因此FrescoPhotoView只提供了过渡动画所必须组件,依靠这些组件不仅保证了高扩展性,也使整个接入变得很简单。
Demo代码:github.com/ccyzml/Fres…
1.实现一个RecyclerView.Adapter,需继承TransitionPagerAdapter
因为看图的控件本身是个ViewPager2,而ViewPager2的内部实现也是RecyclerView。因此第一步就使用普通的RecyclerView一样实现一个Adapter,Adapter需要继承TransitionPagerAdapter,分别实现图片和视频的ViewHolder,保证根节点ViewGroup必须为TransitionLayout
图片的ViewHolder比较特别,需要使用FrescoTransitionPhotoView,而不是FrescoPhotoView,FrescoPhotoView并没有过渡动画的能力。因为过渡动画联动手势处理的需要,需要将告知TransitionLayout FrescoTransitionPhotoView的存在,同时让FrescoTransitionPhotoView支持嵌套滚动
<com.zml.frescophotoview.transition.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--过渡动画联用请使用FrescoTransitionPhotoView而不是FrescoPhotoView-->
<com.zml.frescophotoview.transition.FrescoTransitionPhotoView
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.zml.frescophotoview.transition.TransitionLayout>
复制代码
//支持嵌套滚动
photoView.setHorizontalNestedScrollEnabled(true)
//这行很重要!!!!!!!!使FrescoPhotoView与TransitionLayout能合作处理过渡动画的手势
transitionLayout.setDelegateDragTransitionView(photoView)
复制代码
2.new一个负责动画的PhotoViewerDialog,本质就是一个全屏Dialog,并为其设置步骤1的adapter
val dialog = PhotoViewerDialog(context).apply { adapter = DemoAdapter() }
复制代码
3.启动动画
//使用TransitionUtils得到一个rect
val startRect = TransitionUtils.calculateStartRect(
draweeView,//需要执行动画的View,ImageView,DraweeView均可
picWidthHeight//图片的宽高数组如[1920,1080]
)
dialog.showAnimated(position,startRect)
复制代码