建议使用Glide效果更好,另外建议开启原图缓存(有些版本是自动缓存原图的) diskCacheStrategy(DiskCacheStrategy.ALL或DiskCacheStrategy.DATA) 本库设置为ImageDiskMode.CONTAIN_ORIGINAL
RecyclerView场景 | 聊天页面 |
---|---|
打开视频 | 朋友圈 |
---|---|
1,支持自定义图片加载引擎
2,支持多种图片缓存模式
3,支持聊天界面的查看大图功能
4,支持微信聊天页面大图不在聊天页面时回到点击位置的效果
5,支持全部 ImageView.ScaleType 显示模式的图片打开大图效果,并且新增startCrop、endCrop、autoStartCenterCrop、autoEndCenterCrop四种显示模式
6,支持图片和视频混合数据
7,支持传入包含图片的 RecyclerView、ViewPager、ViewPager2、ListView、GridView 和 多个ImageView 的调用方式,傻瓜式调用,无需关心图片切换后该返回到哪个位置
8,支持大图和大图阅读模式
9,支持自定义大图切换效果(PageTransformer)
allprojects {
repositories {
...
maven { url "https://www.jitpack.io" }
}
}
你可以选择下面三种的其中一种,在module下的build.gradle添加。
implementation 'com.github.hirezy.OpenImageLib:OpenImageFullLib:v1.0.0'
#### B、引入只带有图片引擎的版本(只支持查看图片)
implementation 'com.github.hirezy.OpenImageLib:OpenImageGlideLib:v1.0.0'
//OpenImageLib 是基础库,没有引入图片引擎和视频播放器
implementation 'com.github.hirezy.OpenImageLib:OpenImageLib:v1.0.0'
你可以选择下面两种图片数据的其中一种
List<String> dataList = new ArrayList<>();
for (ImageEntity data : datas) {
dataList.add(data.getImageUrl());
}
//在点击时调用(以下以RecyclerView为例介绍)
OpenImage.with(activity)
//点击ImageView所在的RecyclerView(也支持设置setClickViewPager2,setClickViewPager,setClickGridView,setClickListView,setClickImageView)
.setClickRecyclerView(recyclerView,new SourceImageViewIdGet() {
@Override
public int getImageViewId(OpenImageUrl data, int position) {
return R.id.iv_image;//点击的ImageView的Id
}
})
//点击的ImageView的ScaleType类型(如果设置不对,打开的动画效果将是错误的)
.setSrcImageViewScaleType(ImageView.ScaleType.CENTER_CROP,true)
//RecyclerView的数据
.setImageUrlList(dataList, MediaType.IMAGE)
//点击的ImageView所在数据的位置
.setClickPosition(position)
//开始展示大图
.show();
PS:列表中展示的图片链接和展示大图时所用链接是不同时,这种方式可以有更好的过渡效果
public class ImageEntity implements OpenImageUrl {
public String photoUrl;//图片大图
public String smallPhotoUrl;//图片小图
public String coverUrl;//视频封面大图
public String smallCoverUrl;//视频封面小图
public String videoUrl;//视频链接
public int resouceType; //0图片1视频
public ImageEntity(String url) {
this.url = url;
}
public ImageEntity() {
}
@Override
public String getImageUrl() {
return resouceType ==1:coverUrl:photoUrl;//大图链接(或视频的封面大图链接)
}
@Override
public String getVideoUrl() {
return videoUrl;//视频链接
}
@Override
public String getCoverImageUrl() {//这个代表前边列表展示的图片
return resouceType ==1:smallCoverUrl:smallPhotoUrl;//封面小图链接(或视频的封面小图链接)
}
@Override
public MediaType getType() {
return resouceType ==1:MediaType.VIDEO:MediaType.IMAGE;//数据是图片还是视频
}
}
然后调用显示
//在点击时调用(以下以RecyclerView为例介绍)
OpenImage.with(activity)
//点击ImageView所在的RecyclerView(也支持设置setClickViewPager2,setClickViewPager,setClickGridView,setClickListView,setClickImageView)
.setClickRecyclerView(recyclerView,new SourceImageViewIdGet() {
@Override
public int getImageViewId(OpenImageUrl data, int position) {
return R.id.iv_image;//点击的ImageView的Id
}
})
//点击的ImageView的ScaleType类型(如果设置不对,打开的动画效果将是错误的)
.setSrcImageViewScaleType(ImageView.ScaleType.CENTER_CROP,true)
//RecyclerView的数据
.setImageUrlList(datas)
//点击的ImageView所在数据的位置
.setClickPosition(position)
//开始展示大图
.show();
PS.完整调用示例
//在点击时调用(以下以RecyclerView为例介绍)
OpenImage.with(activity)
//点击ImageView所在的RecyclerView(也支持设置setClickViewPager2,setClickViewPager,setClickGridView,setClickListView,setClickImageView)
.setClickRecyclerView(recyclerView,new SourceImageViewIdGet() {
@Override
public int getImageViewId(OpenImageUrl data, int position) {
return R.id.iv_image;//点击的ImageView的Id
}
})
//点击的ImageView的ScaleType类型(如果设置不对,打开的动画效果将是错误的)
.setSrcImageViewScaleType(ImageView.ScaleType.CENTER_CROP,true)
//RecyclerView的数据
.setImageUrlList(datas)
//点击的ImageView所在数据的位置
.setClickPosition(position)
//可不设置,默认ImageDiskMode.CONTAIN_ORIGINAL,如果Glide不缓存原图,请设置其他参数
.setImageDiskMode(ImageDiskMode.CONTAIN_ORIGINAL)
//可不设置(setImageDiskMode设置为RESULT或NONE时必须设置)
.setItemLoadHelper(new ItemLoadHelper() {
@Override
public void loadImage(Context context, OpenImageUrl openImageUrl, String imageUrl, ImageView imageView, int overrideWidth, int overrideHeight, OnLoadCoverImageListener onLoadCoverImageListener) {
//如果使用的Glide缓存模式是ImageDiskMode.RESULT(只保存目标图片大小),必须在加载图片时传入大小,详看Demo
Glide.with(imageView).load(imageUrl)
.override(overrideWidth, overrideHeight)
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
onLoadCoverImageListener.onLoadImageFailed();
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
onLoadCoverImageListener.onLoadImageSuccess();
return false;
}
}).into(imageView);
}
})
//可不设置(定制页面样式,详细可看Wiki文档)
.setOpenImageStyle(R.style.DefaultPhotosTheme)
//开始展示大图
.show();
(如果您使用的是OpenImageFullLib或OpenImageGlideLib则不需要这一步)
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//初始化大图加载器
OpenImageConfig.getInstance().setBigImageHelper(new BigImageHelperImpl());
}
}
public class BigImageHelperImpl implements BigImageHelper {
@Override
public void loadImage(Context context, String imageUrl, OnLoadBigImageListener onLoadBigImageListener) {
RequestOptions requestOptions = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.format(DecodeFormat.PREFER_RGB_565);
Glide.with(context)
.load(imageUrl).apply(requestOptions).addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
onLoadBigImageListener.onLoadImageFailed();
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
onLoadBigImageListener.onLoadImageSuccess(resource);
return false;
}
}).into(new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
}
@Override
public void loadImage(Context context, String imageUrl, ImageView imageView) {
RequestOptions requestOptions = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.format(DecodeFormat.PREFER_RGB_565);
Glide.with(context)
.load(imageUrl).apply(requestOptions).into(imageView);
}
}
(如果您使用的是OpenImageFullLib则不需要这一步)
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//初始化视频创建类
OpenImageConfig.getInstance().setVideoFragmentCreate(new VideoFragmentCreateImpl());
}
}
public class VideoFragmentCreateImpl implements VideoFragmentCreate {
@Override
public BaseFragment createVideoFragment() {
return new VideoPlayerFragment();
}
}
public class VideoPlayerFragment extends BaseImageFragment<ENDownloadView> {
private FragmentVideoBinding binding;
private String playerKey;
private boolean isLoadImageFinish;
protected boolean isPlayed;
@Override
protected ImageView getSmallCoverImageView() {//返回小封面图
return binding.videoPlayer.getSmallCoverImageView();
}
@Override
protected ImageView getPhotoView() {//返回大封面图,必须在小封面图下边
return binding.videoPlayer.getCoverImageView();
}
@Override
protected ENDownloadView getLoadingView() {//返回loadingView
return (ENDownloadView) binding.videoPlayer.getLoadingView();
}
@Override
protected void hideLoading(ENDownloadView pbLoading) {//隐藏loading需要特殊处理的重写这个
super.hideLoading(pbLoading);
pbLoading.release();
binding.videoPlayer.getStartButton().setVisibility(View.VISIBLE);
}
@Override
protected void showLoading(ENDownloadView pbLoading) {//显示loading需要特殊处理的重写这个
super.showLoading(pbLoading);
pbLoading.start();
binding.videoPlayer.getStartButton().setVisibility(View.GONE);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.videoPlayer.findViewById(R.id.back).setOnClickListener(v -> close());
playerKey = binding.videoPlayer.getVideoKey();
binding.videoPlayer.goneAllWidget();
isPlayed = false;
}
@Override
protected void onTouchClose(float scale) {//下拉关闭回调
super.onTouchClose(scale);
binding.videoPlayer.findViewById(R.id.surface_container).setVisibility(View.GONE);
binding.videoPlayer.goneAllWidget();
}
@Override
protected void onTouchScale(float scale) {//下拉时回调
super.onTouchScale(scale);
binding.videoPlayer.goneAllWidget();
if (scale == 0){
binding.videoPlayer.showAllWidget();
}
}
@Override
protected void loadImageFinish(boolean isLoadImageSuccess) {
isLoadImageFinish = true;
play();
}
private void play(){
if (isTransitionEnd && isLoadImageFinish && !isPlayed){//这里可以不等封面图加载完就播放,这个是为了更好的效果
if (getLifecycle().getCurrentState() == Lifecycle.State.RESUMED){
toPlay4Resume();
}else {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_RESUME){
toPlay4Resume();
source.getLifecycle().removeObserver(this);
}
}
});
}
isPlayed = true;
}
}
protected void toPlay4Resume(){
binding.videoPlayer.playUrl(openImageBean.getVideoUrl());
binding.videoPlayer.startPlayLogic();
}
@Override
protected void onTransitionEnd() {
super.onTransitionEnd();
play();
}
@Override
public void onResume() {
super.onResume();
if (playerKey != null) {
GSYVideoController.resumeByKey(playerKey);
}
}
@Override
public void onPause() {
super.onPause();
if (playerKey != null) {
GSYVideoController.pauseByKey(playerKey);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (playerKey != null) {
GSYVideoController.cancelByKeyAndDeleteKey(playerKey);
}
}
@Override
public View getExitImageView() {//退出页面时需要保证封面图可见
binding.videoPlayer.getThumbImageViewLayout().setVisibility(View.VISIBLE);
return super.getExitImageView();
}
}
GSYVideoPlayer 的混淆规则:
-keep class com.shuyu.gsyvideoplayer.video.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.**
-keep class com.shuyu.gsyvideoplayer.video.base.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.video.base.**
-keep class com.shuyu.gsyvideoplayer.utils.** { *; }
-dontwarn com.shuyu.gsyvideoplayer.utils.**
-keep class tv.danmaku.ijk.** { *; }
-dontwarn tv.danmaku.ijk.**
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, java.lang.Boolean);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
Glide 的混淆规则:
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep class * extends com.bumptech.glide.module.AppGlideModule {
<init>(...);
}
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
*** rewind();
}
最低SDK版本:minSdkVersion >= 21