SubsamplingScaleImageView

SubsamplingScaleImageView用于加载Android中长图,大图的展示,它是一个subsampling-scale-image-view库。

第一步:加入依赖

implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'

第二步:使用

它不同于imageview可以使用Glide加载图片,需要通过FileTarget作为桥梁。

Glide.with(mContext).downloadOnly().load(imageInfos.get(position)).addListener(new RequestListener() {

@Override

    public boolean onLoadFailed(@Nullable GlideException e,Object model,Target target,

boolean isFirstResource) {

return true;

}

@Override

    public boolean onResourceReady(File resource,Object model,Target target,DataSource dataSource,

boolean isFirstResource) {

holder.photoView.setVisibility(View.GONE);

holder.dynamicDetialPreviewBg.setVisibility(View.VISIBLE);

holder.dynamicDetialPreviewImage.setVisibility(View.VISIBLE);

getSupportPresenter().loadSuccess(mContext, resource,holder.dynamicDetialPreviewImage,holder.dynamicDetialPreviewBg);

return true;

}

}).into(new FileTarget() {

@Override

    public void onLoadStarted(@Nullable Drawable placeholder) {

super.onLoadStarted(placeholder);

}

});

第三步,使用到的几个重要方法及工具类

方法:

public void loadSuccess(Context context,File resource,SubsamplingScaleImageView imageView,RelativeLayout progressBar) {

String imagePath = resource.getAbsolutePath();

imageView.setVisibility(View.VISIBLE);

setImageSpec(context,imagePath, imageView);

imageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_USE_EXIF);

ImageSource imageSource =ImageSource.uri(Uri.fromFile(new File(imagePath)));

if (ImageUtil.isBmpImageWithMime(imagePath)) {

imageSource.tilingDisabled();

}

imageView.setImage(imageSource);

imageView.setOnImageEventListener(new SubsamplingScaleImageView.OnImageEventListener() {

@Override

        public void onReady() {

progressBar.setVisibility(View.GONE);

}

@Override

        public void onImageLoaded() {

}

@Override

        public void onPreviewLoadError(Exception e) {

}

@Override

        public void onImageLoadError(Exception e) {

}

@Override

        public void onTileLoadError(Exception e) {

}

@Override

        public void onPreviewReleased() {

}

});

}

private void setImageSpec(Context context,String imagePath,SubsamplingScaleImageView imageView) {

boolean isLongImage =ImageUtil.isLongImage(context, imagePath);

if (isLongImage) {

imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_START);

imageView.setMinScale(ImageUtil.getLongImageMinScale(context, imagePath));

imageView.setMaxScale(ImageUtil.getLongImageMaxScale(context, imagePath));

imageView.setDoubleTapZoomScale(ImageUtil.getLongImageMaxScale(context, imagePath));

}else {

boolean isSmallImage =ImageUtil.isSmallImage(context, imagePath);

boolean isWideImage =ImageUtil.isWideImage(context, imagePath);

if (isWideImage) {

imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE);

imageView.setMinScale(ImagePreview.getInstance().getMinScale());

imageView.setMaxScale(ImagePreview.getInstance().getMaxScale());

imageView.setDoubleTapZoomScale(ImageUtil.getWideImageDoubleScale(activity, imagePath));

}else if (isSmallImage) {

imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM);

imageView.setMinScale(ImageUtil.getSmallImageMinScale(activity, imagePath));

imageView.setMaxScale(ImageUtil.getSmallImageMaxScale(activity, imagePath));

imageView.setDoubleTapZoomScale(ImageUtil.getSmallImageMaxScale(activity, imagePath));

}else {

imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE);

imageView.setMinScale(ImagePreview.getInstance().getMinScale());

imageView.setMaxScale(ImagePreview.getInstance().getMaxScale());

imageView.setDoubleTapZoomScale(ImagePreview.getInstance().getMediumScale());

}

}

}

工具类:FileTarget

package com.astro90.android.app.dynamicpreview;

import android.graphics.drawable.Drawable;

import com.bumptech.glide.request.Request;

import com.bumptech.glide.request.target.SizeReadyCallback;

import com.bumptech.glide.request.target.Target;

import com.bumptech.glide.request.transition.Transition;

import java.io.File;

import androidx.annotation.NonNull;

import androidx.annotation.Nullable;

public class FileTarget implements Target {

@Override

    public void onLoadStarted(@Nullable Drawable placeholder) {

}

@Override

    public void onLoadFailed(@Nullable Drawable errorDrawable) {

}

@Override

    public void onResourceReady(@NonNull File resource,@Nullable Transition transition) {

}

@Override

    public void onLoadCleared(@Nullable Drawable placeholder) {

}

@Override

    public void getSize(@NonNull SizeReadyCallback cb) {

cb.onSizeReady(Target.SIZE_ORIGINAL,Target.SIZE_ORIGINAL);

}

@Override

    public void removeCallback(@NonNull SizeReadyCallback cb) {

}

@Nullable

@Override

    public Request getRequest() {

return null;

}

@Override

    public void setRequest(@Nullable Request request) {

}

@Override

    public void onStart() {

}

@Override

    public void onStop() {

}

@Override

    public void onDestroy() {

}

}

ImagePreview

package com.astro90.android.app.dynamicpreview;

public class ImagePreview {

private float minScale =1.0f;// 最小缩放倍数

    private float mediumScale =3.0f;// 中等缩放倍数

    private float maxScale =5.0f;// 最大缩放倍数

    public static ImagePreview getInstance() {

return InnerClass.instance;

}

@Deprecated

    public ImagePreview setScaleLevel(int min,int medium,int max) {

if (max > medium && medium > min && min >0) {

this.minScale = min;

this.mediumScale = medium;

this.maxScale = max;

}else {

throw new IllegalArgumentException("max must greater to medium, medium must greater to min!");

}

return this;

}

public float getMinScale() {

return minScale;

}

public float getMediumScale() {

return mediumScale;

}

public float getMaxScale() {

return maxScale;

}

private static class InnerClass {

private static ImagePreview instance =new ImagePreview();

}

}

ImageUtil

package com.astro90.android.app.dynamicpreview;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Matrix;

import android.media.ExifInterface;

import android.os.Environment;

import android.text.TextUtils;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

public class ImageUtil {

private static final String TAG ="ImageUtil";

public static Bitmap getImageBitmap(String srcPath,float maxWidth,float maxHeight) {

BitmapFactory.Options newOpts =new BitmapFactory.Options();

newOpts.inJustDecodeBounds =true;

Bitmap bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

newOpts.inJustDecodeBounds =false;

int originalWidth =newOpts.outWidth;

int originalHeight =newOpts.outHeight;

float be =1;

if (originalWidth >originalHeight &&originalWidth > maxWidth) {

be =originalWidth / maxWidth;

}else if (originalWidth maxHeight) {

be =newOpts.outHeight / maxHeight;

}

if (be <=0) {

be =1;

}

newOpts.inSampleSize = (int) be;

newOpts.inPreferredConfig =Bitmap.Config.ARGB_8888;

newOpts.inDither =false;

newOpts.inPurgeable =true;

newOpts.inInputShareable =true;

if (bitmap !=null && !bitmap.isRecycled()) {

bitmap.recycle();

}

try {

bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

}catch (OutOfMemoryError e) {

if (bitmap !=null && !bitmap.isRecycled()) {

bitmap.recycle();

}

Runtime.getRuntime().gc();

}catch (Exception e) {

Runtime.getRuntime().gc();

}

if (bitmap !=null) {

bitmap =rotateBitmapByDegree(bitmap,getBitmapDegree(srcPath));

}

return bitmap;

}

public static int getBitmapDegree(String path) {

int degree =0;

try {

ExifInterface exifInterface =new ExifInterface(path);

int orientation =

exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL);

switch (orientation) {

case ExifInterface.ORIENTATION_ROTATE_90:

degree =90;

break;

case ExifInterface.ORIENTATION_ROTATE_180:

degree =180;

break;

case ExifInterface.ORIENTATION_ROTATE_270:

degree =270;

break;

default:

degree =0;

break;

}

}catch (IOException e) {

e.printStackTrace();

}

return degree;

}

public static Bitmap rotateBitmapByDegree(Bitmap bm,int degree) {

Bitmap returnBm =null;

Matrix matrix =new Matrix();

matrix.postRotate(degree);

try {

returnBm =Bitmap.createBitmap(bm,0,0, bm.getWidth(), bm.getHeight(),matrix,true);

}catch (OutOfMemoryError e) {

e.printStackTrace();

}

if (returnBm ==null) {

returnBm = bm;

}

if (bm != returnBm) {

bm.recycle();

}

return returnBm;

}

public static Bitmap resizeImage(Bitmap origin,int newWidth,int newHeight) {

if (origin ==null) {

return null;

}

int height = origin.getHeight();

int width = origin.getWidth();

float scaleWidth = ((float) newWidth) /width;

float scaleHeight = ((float) newHeight) /height;

Matrix matrix =new Matrix();

matrix.postScale(scaleWidth,scaleHeight);

Bitmap newBM =Bitmap.createBitmap(origin,0,0,width,height,matrix,false);

if (!origin.isRecycled()) {

origin.recycle();

}

return newBM;

}

public static String saveBitmapBackPath(Bitmap bm)throws IOException {

String path =Environment.getExternalStorageDirectory() +"/ShareLongPicture/.temp/";

File targetDir =new File(path);

if (!targetDir.exists()) {

try {

targetDir.mkdirs();

}catch (Exception e) {

e.printStackTrace();

}

}

String fileName ="temp_LongPictureShare_" +System.currentTimeMillis() +".jpeg";

File savedFile =new File(path +fileName);

if (!savedFile.exists()) {

savedFile.createNewFile();

}

BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream(savedFile));

bm.compress(Bitmap.CompressFormat.JPEG,100,bos);

bos.flush();

bos.close();

return savedFile.getAbsolutePath();

}

public static int getOrientation(String imagePath) {

int degree =0;

try {

ExifInterface exifInterface =new ExifInterface(imagePath);

int orientation =

exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL);

switch (orientation) {

case ExifInterface.ORIENTATION_ROTATE_90:

return 90;

case ExifInterface.ORIENTATION_ROTATE_180:

return 180;

case ExifInterface.ORIENTATION_ROTATE_270:

return 270;

default:

return 0;

}

}catch (Exception e) {

e.printStackTrace();

}

return 0;

}

public static int[]getWidthHeight(String imagePath) {

if (imagePath.isEmpty()) {

return new int[]{0,0};

}

BitmapFactory.Options options =new BitmapFactory.Options();

options.inJustDecodeBounds =true;

try {

Bitmap originBitmap =BitmapFactory.decodeFile(imagePath,options);

}catch (Exception e) {

e.printStackTrace();

}

// 使用第一种方式获取原始图片的宽高

        int srcWidth =options.outWidth;

int srcHeight =options.outHeight;

// 使用第二种方式获取原始图片的宽高

        if (srcHeight == -1 || srcWidth == -1) {

try {

ExifInterface exifInterface =new ExifInterface(imagePath);

srcHeight =

exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH,ExifInterface.ORIENTATION_NORMAL);

srcWidth =

exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH,ExifInterface.ORIENTATION_NORMAL);

}catch (IOException e) {

e.printStackTrace();

}

}

// 使用第三种方式获取原始图片的宽高

        if (srcWidth <=0 || srcHeight <=0) {

Bitmap bitmap2 =BitmapFactory.decodeFile(imagePath);

if (bitmap2 !=null) {

srcWidth =bitmap2.getWidth();

srcHeight =bitmap2.getHeight();

try {

if (!bitmap2.isRecycled()) {

bitmap2.recycle();

}

}catch (Exception e) {

e.printStackTrace();

}

}

}

int orient =getOrientation(imagePath);

if (orient ==90 ||orient ==270) {

return new int[]{srcHeight, srcWidth};

}

return new int[]{srcWidth, srcHeight};

}

public static boolean isLongImage(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

float w =wh[0];

float h =wh[1];

float imageRatio = (h /w);

float phoneRatio =PhoneUtil.getPhoneRatio(context.getApplicationContext()) +0.1F;

boolean isLongImage = (w >0 &&h >0) && (h >w) && (imageRatio >=phoneRatio);

//Print.d(TAG, "isLongImage = " + isLongImage);

        return isLongImage;

}

public static boolean isWideImage(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

float w =wh[0];

float h =wh[1];

float imageRatio = (w /h);

//float phoneRatio = PhoneUtil.getPhoneRatio(context.getApplicationContext()) + 0.1F;

        boolean isWideImage = (w >0 &&h >0) && (w >h) && (imageRatio >=2);

//Print.d(TAG, "isWideImage = " + isWideImage);

        return isWideImage;

}

public static boolean isSmallImage(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

boolean isSmallImage =wh[0]

//Print.d(TAG, "isSmallImage = " + isSmallImage);

        return isSmallImage;

}

public static float getLongImageMinScale(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

float imageWid =wh[0];

float phoneWid =PhoneUtil.getPhoneWid(context.getApplicationContext());

return phoneWid /imageWid;

}

public static float getLongImageMaxScale(Context context,String imagePath) {

return getLongImageMinScale(context, imagePath) *2;

}

public static float getWideImageDoubleScale(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

float imageHei =wh[1];

float phoneHei =PhoneUtil.getPhoneHei(context.getApplicationContext());

return phoneHei /imageHei;

}

public static float getSmallImageMinScale(Context context,String imagePath) {

int[]wh =getWidthHeight(imagePath);

float imageWid =wh[0];

float phoneWid =PhoneUtil.getPhoneWid(context.getApplicationContext());

return phoneWid /imageWid;

}

public static float getSmallImageMaxScale(Context context,String imagePath) {

return getSmallImageMinScale(context, imagePath) *2;

}

public static Bitmap getImageBitmap(String srcPath,int degree) {

boolean isOOM =false;

BitmapFactory.Options newOpts =new BitmapFactory.Options();

newOpts.inJustDecodeBounds =true;

Bitmap bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

newOpts.inJustDecodeBounds =false;

float be =1;

newOpts.inSampleSize = (int)be;

newOpts.inPreferredConfig =Bitmap.Config.RGB_565;

newOpts.inDither =false;

newOpts.inPurgeable =true;

newOpts.inInputShareable =true;

if (bitmap !=null && !bitmap.isRecycled()) {

bitmap.recycle();

}

try {

bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

}catch (OutOfMemoryError e) {

isOOM =true;

if (bitmap !=null && !bitmap.isRecycled()) {

bitmap.recycle();

}

Runtime.getRuntime().gc();

}catch (Exception e) {

isOOM =true;

Runtime.getRuntime().gc();

}

if (isOOM) {

try {

bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

}catch (Exception e) {

newOpts.inPreferredConfig =Bitmap.Config.RGB_565;

bitmap =BitmapFactory.decodeFile(srcPath,newOpts);

}

}

if (bitmap !=null) {

if (degree ==90) {

degree +=180;

}

bitmap =rotateBitmapByDegree(bitmap, degree);

int ttHeight = (1080 * bitmap.getHeight() / bitmap.getWidth());

if (bitmap.getWidth() >=1080) {

bitmap =zoomBitmap(bitmap,1080,ttHeight);

}

}

return bitmap;

}

private static Bitmap zoomBitmap(Bitmap bitmap,int width,int height) {

int w = bitmap.getWidth();

int h = bitmap.getHeight();

Matrix matrix =new Matrix();

float scaleWidth = ((float) width /w);

float scaleHeight = ((float) height /h);

matrix.postScale(scaleWidth,scaleHeight);

return Bitmap.createBitmap(bitmap,0,0,w,h,matrix,true);

}

public static String getImageTypeWithMime(String path) {

BitmapFactory.Options options =new BitmapFactory.Options();

options.inJustDecodeBounds =true;

BitmapFactory.decodeFile(path,options);

String type =options.outMimeType;

// ”image/png”、”image/jpeg”、”image/gif”

        if (TextUtils.isEmpty(type)) {

type ="";

}else {

type = type.substring(6);

}

return type;

}

public static boolean isGifImageWithMime(String path) {

return "gif".equalsIgnoreCase(getImageTypeWithMime(path));

}

public static boolean isBmpImageWithMime(String path) {

return "bmp".equalsIgnoreCase(getImageTypeWithMime(path));

}

public static boolean isGifImageWithUrl(String url) {

return url.toLowerCase().endsWith("gif");

}

}

PhoneUtil

package com.astro90.android.app.dynamicpreview;

import android.content.Context;

import android.util.DisplayMetrics;

import android.view.WindowManager;

public class PhoneUtil {

public static int getPhoneWid(Context context) {

WindowManager windowManager =

(WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics metric =new DisplayMetrics();

windowManager.getDefaultDisplay().getMetrics(metric);

return metric.widthPixels;

}

public static int getPhoneHei(Context context) {

WindowManager windowManager =

(WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics metric =new DisplayMetrics();

windowManager.getDefaultDisplay().getMetrics(metric);

return metric.heightPixels;

}

public static float getPhoneRatio(Context context) {

return ((float)getPhoneHei(context)) / ((float)getPhoneWid(context));

}

public static int px2dp(Context context,float pxValue) {

final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;

return (int) (pxValue /scale +0.5f);

}

public static int dp2px(Context context,float dipValue) {

final float scale = context.getApplicationContext().getResources().getDisplayMetrics().density;

return (int) (dipValue *scale +0.5f);

}

}

第四步,清除Glide的缓存

在OnDestroy()中销毁

new Thread(new Runnable() {

@Override

    public void run() {

Glide.get(mContext.getApplicationContext()).clearDiskCache();

}

}).start();

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容