package com.bzh.mysimplefresco.lib;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.NinePatch;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.bzh.mysimplefresco.R;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.AbstractDraweeController;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.controller.ControllerListener;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.generic.RoundingParams;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imageformat.ImageFormat;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.request.Postprocessor;
import java.io.File;
/**
* ========================================================== <br>
* <b>版权</b>: 别志华 版权所有(c) 2015 <br>
* <b>作者</b>: 别志华 biezhihua@163.com<br>
* <b>创建日期</b>: 2015/7/12 16:20 <br>
* <b>版本</b>: V5.0 <br>
* <b>修订历史</b>: <br>
* ========================================================== <br>
*/
public class MySimpleDraweeView extends SimpleDraweeView {
// 默认的宽高比例
public static final float DEF_RATIO = 2.0f;
private Context mContext;
private Postprocessor mPostProcessor; // 后处理器(在图片下载完成后对图片进行处理-截取/缩放等)
private ControllerListener mControllerListener; // 下载监听器
private ResizeOptions mResizeOptions; // 图片缩放,优先级非常高;缩放的尺寸并不是按照指定的尺寸,而是根据内部来计算出一个合适的值;
private ScalingUtils.ScaleType mDraweeViewScaleType;// 图片缩放类型,默认为CENTER_CROP
private Drawable mProgressBar; // 加载进度
private Drawable mPlaceholderDrawable; // 加载背景
private Drawable mGifChartOverlay; // GIF的覆盖物图
private Drawable mLongChartOverlay; // 长图的覆盖物图
private Drawable mNumberChartOverlay; // 数字的覆盖物图
private boolean mAutoPlayAnimations = false; // 是否自动播放GIF图-不自动播放
private boolean isCutGif; // 是否裁剪GIF
private double mHeightRatio; // 宽高比例
private int mTargetImageSize = -1; // 指定的图片尺寸
private int mIsReplacePngBg2TargetColor = -1; // 是否处理PNG图片的透明背景为指定颜色
private ImageRequest.ImageType mImageType; // 图片类型-默认
private ImageFormat mImageFormat = ImageFormat.JPEG;// 图片类型-默认JPEG
private ImageRequest.RequestLevel mLowestPermittedRequestLevel;// 图片加载的请求类型-默认FULL_FETCH
private String uriPathTag; // 加载图片的TAG,用于不重复加载图片
public MySimpleDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
super(context, hierarchy);
init(context);
}
public MySimpleDraweeView(Context context) {
super(context);
init(context);
}
public MySimpleDraweeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
init(context);
}
public MySimpleDraweeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
init(context);
}
public void init(Context context) {
if (!isInEditMode()) {
this.mContext = context;
mPlaceholderDrawable = new ColorDrawable(Color.GRAY);
}
mPostProcessor = new MyBasePostProcessor(this);
mImageType = ImageRequest.ImageType.DEFAULT;
mControllerListener = new DefaultBaseControllerListener();
mDraweeViewScaleType = ScalingUtils.ScaleType.CENTER_CROP;
mLowestPermittedRequestLevel = ImageRequest.RequestLevel.FULL_FETCH;
}
/**
* 是否设置GIF标识
*/
public MySimpleDraweeView setGifChartIdentify(final boolean isShowGifIdentify) {
if (isShowGifIdentify) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mGifChartOverlay = mContext.getDrawable(R.mipmap.identify_gif);
} else {
mGifChartOverlay = mContext.getResources().getDrawable(R.mipmap.identify_gif);
}
} else {
mGifChartOverlay = null;
}
return this;
}
/**
* 设置长图标识
*/
public MySimpleDraweeView setLongChartIdentify(final int imageWidth, final int imageHeight) {
return setLongChartIdentify(imageHeight > imageWidth * DEF_RATIO);
}
/**
* 设置数字标识,内部会判断是否大于1
*/
public MySimpleDraweeView setNumberChartIdentify(int number) {
if (number > 1) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.identify_number);
byte[] chunk = bitmap.getNinePatchChunk();
if (NinePatch.isNinePatchChunk(chunk)) {
mNumberChartOverlay = new MyNinePatchDrawable(getResources(), bitmap, chunk, NinePatchChunk.deserialize(chunk).mPaddings, null, number + "");
} else {
mNumberChartOverlay = null;
}
} else {
mNumberChartOverlay = null;
}
return this;
}
/**
* 加载url图片
*/
public MySimpleDraweeView setDraweeViewUrl(final String url) {
return setDraweeViewUri(Uri.parse(url));
}
/**
* 加载本地资源图片
*/
public MySimpleDraweeView setDraweeViewResId(final int resId) {
return setDraweeViewUri(getUriByResId(resId));
}
/**
* 加载uri图片
*/
public MySimpleDraweeView setDraweeViewUri(final Uri uri) {
return setControllerByType(uri, "NORMAL");
}
/**
* 加载url圆形图片
*/
public MySimpleDraweeView setRoundDraweeViewUrl(final String url) {
return setRoundDraweeViewUri(Uri.parse(url));
}
/**
* 加载本地资源圆形图片
*/
public MySimpleDraweeView setRoundDraweeViewResId(final int resId) {
return setRoundDraweeViewUri(getUriByResId(resId));
}
/**
* 加载uri圆形图片
*/
public MySimpleDraweeView setRoundDraweeViewUri(final Uri uri) {
return setControllerByType(uri, "ROUND");
}
/**
* 根据图片宽高设置控件尺寸
*/
public MySimpleDraweeView setWidthAndHeight(final float width, final float height) {
float picRatio = height / width;
if (picRatio >= DEF_RATIO) {
picRatio = DEF_RATIO;
}
this.setHeightRatio(picRatio);
return this;
}
public MySimpleDraweeView setMaxWidthLayoutParams(final int maxWidth, final int width, final int height) {
float widthRatio = (float) width / (float) maxWidth;
float tmpheight = ((float) height / widthRatio);
float ratio = tmpheight / maxWidth;
if (ratio > DEF_RATIO) {
ratio = DEF_RATIO;
}
tmpheight = maxWidth * ratio;
// 设置单张图片的布局
ViewGroup.LayoutParams layoutparams = getLayoutParams();
layoutparams.height = (int) tmpheight;
layoutparams.width = maxWidth;
setLayoutParams(layoutparams);
return this;
}
/**
* 指定的PNG图片的透明背景颜色为白色
*/
public MySimpleDraweeView replacePNGBackground2White() {
return replacePNGBackground(Color.WHITE);
}
/**
* 如果不为-1说明需要替换PNG的透明背景色
*/
public int isReplacePNGBackground() {
return mIsReplacePngBg2TargetColor;
}
/**
* 是否需要替换PNG图片的透明背景为指定的颜色,需要则设置指定的颜色值
*/
public MySimpleDraweeView replacePNGBackground(int targetColor) {
if (targetColor == -1) {
throw new RuntimeException("颜色值不能指定为-1");
}
this.mIsReplacePngBg2TargetColor = targetColor;
return this;
}
/**
* 截取图片的大小
* TODO:待重构
*/
public int getTargetImageSize() {
return mTargetImageSize;
}
/**
* TODO: 待重构
*/
public void setTargetImageSize(int targetImageSize) {
this.mTargetImageSize = targetImageSize;
}
public ImageFormat getImageFormat() {
return mImageFormat;
}
/**
* 是否剪切GIF的第一帧
*/
public void setIsCutGif(boolean isCutGif) {
this.isCutGif = isCutGif;
}
/**
* 是否自动播放GIF,默认False
*/
public MySimpleDraweeView setAutoPlayAnimations(boolean mAutoPlayAnimations) {
this.mAutoPlayAnimations = mAutoPlayAnimations;
return this;
}
public MySimpleDraweeView setControllerListener(ControllerListener mControllerListener) {
this.mControllerListener = mControllerListener;
return this;
}
public MySimpleDraweeView setResizeOptions(ResizeOptions resizeOptions) {
this.mResizeOptions = resizeOptions;
return this;
}
public MySimpleDraweeView setProgressBar(Drawable mProgressBar) {
this.mProgressBar = mProgressBar;
return this;
}
public MySimpleDraweeView setDraweeViewScaleType(ScalingUtils.ScaleType mDraweeViewScaleType) {
this.mDraweeViewScaleType = mDraweeViewScaleType;
return this;
}
public MySimpleDraweeView setPlaceholderDrawable(Drawable placeholderDrawable) {
this.mPlaceholderDrawable = placeholderDrawable;
return this;
}
public MySimpleDraweeView setLowestPermittedRequestLevel(ImageRequest.RequestLevel mLowestPermittedRequestLevel) {
this.mLowestPermittedRequestLevel = mLowestPermittedRequestLevel;
return this;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////私有方法///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 图片加载完成时,为控件设置Tag
*/
private class DefaultBaseControllerListener extends BaseControllerListener<ImageInfo> {
@Override
public void onFinalImageSet(String id, ImageInfo imageInfo, Animatable animatable) {
super.onFinalImageSet(id, imageInfo, animatable);
MySimpleDraweeView.this.setTag(R.id.uriPath, uriPathTag);
}
}
// 正常
private void setHierarchy() {
if (mContext == null) {
throw new IllegalArgumentException("Context is not null");
}
final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(mContext.getResources())
.setFadeDuration(this.getFadeDuration())
.setOverlay(this.getMyOverlay())
.setActualImageScaleType(this.getDraweeViewScaleType())
.setProgressBarImage(this.getProgressBar(), ScalingUtils.ScaleType.CENTER_INSIDE)
.setPlaceholderImage(this.getPlaceholderDrawable(), ScalingUtils.ScaleType.CENTER_CROP)
.build();
super.setHierarchy(hierarchy);
}
// 圆形
private void setRoundHierarchy() {
if (mContext == null) {
throw new IllegalArgumentException("Context is not null");
}
Drawable defaultIcon;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
defaultIcon = mContext.getDrawable(R.mipmap.round_default_icon);
} else {
defaultIcon = mContext.getResources().getDrawable(R.mipmap.round_default_icon);
}
final GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(mContext.getResources())
.setPlaceholderImage(defaultIcon)
.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP)
.setRoundingParams(RoundingParams.asCircle())
.build();
super.setHierarchy(hierarchy);
}
private ImageRequest getImageRequest(MySimpleDraweeView view, Uri uri) {
switch (mImageFormat) {
case JPEG:
case PNG:
return ImageRequestBuilder
.newBuilderWithSource(uri)
.setImageType(view.getImageType())
.setLowestPermittedRequestLevel(view.getLowestPermittedRequestLevel())
.setPostprocessor(view.getPostProcessor())//修改图片
.setResizeOptions(view.getResizeOptions())
.setAutoRotateEnabled(true)
.setLocalThumbnailPreviewsEnabled(true)
.setProgressiveRenderingEnabled(false)
.build();
case GIF:
if (uri.getScheme().toLowerCase().contains("file") && isCutGif()) {
// 针对本地Gif预览时做特殊处理,裁剪出第一帧并显示
File file = new File(uri.getPath());
File cutFile = Utils.getCopyFile(file);
Uri newUri = new Uri.Builder().scheme("file").path(cutFile.getAbsolutePath()).build();
return ImageRequestBuilder
.newBuilderWithSource(newUri)
.setLowestPermittedRequestLevel(view.getLowestPermittedRequestLevel())
.setPostprocessor(view.getPostProcessor())
.setResizeOptions(view.getResizeOptions())
.setAutoRotateEnabled(true).build();
} else {
return ImageRequestBuilder
.newBuilderWithSource(uri)
.setLowestPermittedRequestLevel(view.getLowestPermittedRequestLevel())
.setAutoRotateEnabled(true)
.build();
}
}
throw new RuntimeException("must have a ImageRequest");
}
private MySimpleDraweeView setControllerByType(final Uri uri, final String type) {
uriPathTag = uri.toString();
this.setImageFormat(uriPathTag);
if (noRepeatLoadImage(uriPathTag)) {
if ("NORMAL".equals(type)) {
setHierarchy();
} else if ("ROUND".equals(type)) {
setRoundHierarchy();
}
final AbstractDraweeController controller = Fresco.newDraweeControllerBuilder()
.setAutoPlayAnimations(this.getAutoPlayAnimations())//自动播放图片动画
.setControllerListener(this.getControllerListener())
.setImageRequest(getImageRequest(this, uri))
.setOldController(this.getController())
.build();
super.setController(controller);
}
return this;
}
/**
* 获取遮盖物
* 数字 > GIF > 长图
*/
private Drawable getMyOverlay() {
if (null != mNumberChartOverlay) {
return mNumberChartOverlay;
} else if (null != mGifChartOverlay) {
return mGifChartOverlay;
} else if (null != mLongChartOverlay) {
return mLongChartOverlay;
}
return new ColorDrawable(Color.TRANSPARENT);
}
private ControllerListener getControllerListener() {
return mControllerListener;
}
private ScalingUtils.ScaleType getDraweeViewScaleType() {
return mDraweeViewScaleType;
}
private int getFadeDuration() {
return 0;
}
private Drawable getPlaceholderDrawable() {
return mPlaceholderDrawable;
}
private ImageRequest.RequestLevel getLowestPermittedRequestLevel() {
return mLowestPermittedRequestLevel;
}
private ImageRequest.ImageType getImageType() {
return mImageType;
}
private Postprocessor getPostProcessor() {
return mPostProcessor;
}
private ResizeOptions getResizeOptions() {
return mResizeOptions;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mHeightRatio > 0.0) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) (width * mHeightRatio);
super.setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
private boolean getAutoPlayAnimations() {
return mAutoPlayAnimations;
}
private Drawable getProgressBar() {
return mProgressBar;
}
/**
* 判定Tag和Url是否相等,相等代表图片已经加载过,不需要从新加载
*/
private boolean noRepeatLoadImage(String imgUrl) {
return !(TextUtils.isEmpty(imgUrl) || TextUtils.isEmpty(this.getTag(R.id.uriPath) + "")) && !(this.getTag(R.id.uriPath) + "").equals(imgUrl);
}
/**
* 是否设置长图标识
*/
public MySimpleDraweeView setLongChartIdentify(final boolean isLongChartIdentify) {
if (isLongChartIdentify) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mLongChartOverlay = mContext.getDrawable(R.mipmap.identify_long);
} else {
mLongChartOverlay = mContext.getResources().getDrawable(R.mipmap.identify_long);
}
} else {
mLongChartOverlay = null;
}
return this;
}
private Uri getUriByResId(int resId) {
// 增加对资源id类型的图片类型判断
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), resId, opts);
if (opts.outMimeType.equals("image/png")) {
mImageFormat = ImageFormat.PNG;
}
return new Uri.Builder().scheme("res").path(String.valueOf(resId)).build();
}
private boolean isCutGif() {
return isCutGif;
}
private void setHeightRatio(double ratio) {
if (ratio != mHeightRatio) {
mHeightRatio = ratio;
requestLayout();
}
}
private void setImageFormat(final String url) {
if (url.toLowerCase().endsWith("gif")) {
mImageFormat = ImageFormat.GIF;
} else if (url.toLowerCase().endsWith("jpeg") || url.toLowerCase().endsWith("jpg")) {
mImageFormat = ImageFormat.JPEG;
} else if (url.toLowerCase().endsWith("png")) {
mImageFormat = ImageFormat.PNG;
}
}
}