TextView載入html圖片非同步顯示(Picasso)

來源:互聯網
上載者:User

標籤:system   lin   for   length   position   ica   處理   removes   onclick   

項目中有這樣一個需求:

  textview載入一段 html標籤 其中包含 "<Img url= " 圖片非同步展示 而且 根據圖片的比例 寬度滿屏展示。

思路:

  重寫textview Html.fromHtml方法  以及 圖片Picasso展示(後面會附帶Picasso 的兩個轉換類)

感覺網上沒有合適的或者用的是Gilde載入 其實無論是Gilde還是Picasso載入豆豆都能滿足我們的需求。

 

需求描述完畢 上張帥圖:

  

好吧 廢話不多說了 直接上實現代碼 

     RichText:  

public class RichText extends TextView {

private Drawable placeHolder, errorImage;//佔位圖,錯誤圖
private OnImageClickListener onImageClickListener;//圖片點擊回調
private HashSet<Target> targets;
private int d_w = 500;
private int d_h = 500;

public RichText(Context context) {
this(context, null);
}

public RichText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public RichText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

init(context, attrs);
}

private void init(Context context, AttributeSet attrs) {
targets = new HashSet<>();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RichText);
placeHolder = typedArray.getDrawable(R.styleable.RichText_placeHolder);
errorImage = typedArray.getDrawable(R.styleable.RichText_errorImage);

d_w = typedArray.getDimensionPixelSize(R.styleable.RichText_default_width, d_w);
d_h = typedArray.getDimensionPixelSize(R.styleable.RichText_default_height, d_h);

if (placeHolder == null) {
placeHolder = new ColorDrawable(Color.GRAY);
}
placeHolder.setBounds(0, 0, d_w, d_h);
if (errorImage == null) {
errorImage = new ColorDrawable(Color.GRAY);
}
errorImage.setBounds(0, 0, d_w, d_h);
typedArray.recycle();
}


/**
* 設定富文本
*
* @param text 富文本
*/
public void setRichText(String text) {
targets.clear();
Spanned spanned = Html.fromHtml(text, asyncImageGetter, null);
SpannableStringBuilder spannableStringBuilder;
if (spanned instanceof SpannableStringBuilder) {
spannableStringBuilder = (SpannableStringBuilder) spanned;
} else {
spannableStringBuilder = new SpannableStringBuilder(spanned);
}

ImageSpan[] imageSpans = spannableStringBuilder.getSpans(0, spannableStringBuilder.length(), ImageSpan.class);
final List<String> imageUrls = new ArrayList<>();

for (int i = 0, size = imageSpans.length; i < size; i++) {
ImageSpan imageSpan = imageSpans[i];
String imageUrl = imageSpan.getSource();
int start = spannableStringBuilder.getSpanStart(imageSpan);
int end = spannableStringBuilder.getSpanEnd(imageSpan);
imageUrls.add(imageUrl);

final int finalI = i;
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View widget) {
if (onImageClickListener != null) {
onImageClickListener.imageClicked(imageUrls, finalI);
}
}
};
ClickableSpan[] clickableSpans = spannableStringBuilder.getSpans(start, end, ClickableSpan.class);
if (clickableSpans != null && clickableSpans.length != 0) {
for (ClickableSpan cs : clickableSpans) {
spannableStringBuilder.removeSpan(cs);
}
}
spannableStringBuilder.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
super.setText(spanned);
setMovementMethod(LinkMovementMethod.getInstance());
}

private void addTarget(Target target) {
targets.add(target);
}

/**
* 非同步載入圖片(依賴於Picasso)
*/
private Html.ImageGetter asyncImageGetter = new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
final URLDrawable urlDrawable = new URLDrawable();
Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Drawable drawable = new BitmapDrawable(getContext().getResources(), bitmap);
drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
urlDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
urlDrawable.setDrawable(drawable);
RichText.this.setText(getText());
}

@Override
public void onBitmapFailed(Drawable errorDrawable) {
// urlDrawable.setBounds(errorDrawable.getBounds());
urlDrawable.setDrawable(errorDrawable);
}

@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
// urlDrawable.setBounds(placeHolderDrawable.getBounds());
urlDrawable.setDrawable(placeHolderDrawable);
}
};
addTarget(target);
Picasso.with(getContext()).load(source).transform(new ImageTransform()).into(target);//.placeholder(placeHolder).error(errorImage)
return urlDrawable;
}
};

private static final class URLDrawable extends BitmapDrawable {
private Drawable drawable;

@SuppressWarnings("deprecation")
public URLDrawable() {
}

@Override
public void draw(Canvas canvas) {
if (drawable != null)
drawable.draw(canvas);
}

public void setDrawable(Drawable drawable) {
this.drawable = drawable;
}
}

public void setPlaceHolder(Drawable placeHolder) {
this.placeHolder = placeHolder;
this.placeHolder.setBounds(0, 0, d_w, d_h);
}

public void setErrorImage(Drawable errorImage) {
this.errorImage = errorImage;
this.errorImage.setBounds(0, 0, d_w, d_h);
}

public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
this.onImageClickListener = onImageClickListener;
}

public interface OnImageClickListener {
/**
* 圖片被點擊後的回調方法
*
* @param imageUrls 本篇富常值內容裡的全部圖片
* @param position 點擊處圖片在imageUrls中的位置
*/
void imageClicked(List<String> imageUrls, int position);
}
}

// ============================ImageTransform 處理圖片比例展示
public class ImageTransform implements Transformation {

private String Key = "ImageTransform";

@Override
public Bitmap transform(Bitmap source) {//40 是我項目中 的圖片間距
int targetWidth = ScreenUtil.getScreenWidth(App.getContext()) - DisplayUtil.dp2px(App.getContext(), 40);
if (source.getWidth() == 0) {
return source;
}
//如果圖片小於設定的寬度,做處理
if (source.getWidth() < targetWidth) {
double aspectRatio = (double) source.getHeight() / (double) source.getWidth();
int targetHeight = (int) (targetWidth * aspectRatio);

if (targetHeight != 0 && targetWidth != 0) {
Bitmap result = Bitmap.createScaledBitmap(source, targetWidth, targetHeight, false);
if (result != source) {
// Same bitmap is returned if sizes are the same
source.recycle();
}
return result;
} else {
return source;
}
} else {
return source;
}
}

@Override
public String key() {
return Key;
}
}

//=========================其中 40是我項目左右兩邊的間距
配置
<!--attrs 富文本-->
<declare-styleable name="RichText">
<attr name="placeHolder" format="reference" />
<attr name="errorImage" format="reference" />
<attr name="default_width" format="dimension" />
<attr name="default_height" format="dimension" />
</declare-styleable>
/**
* 擷取螢幕的寬度px
*/
public static int getScreenWidth(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();// 建立了一張白紙
windowManager.getDefaultDisplay().getMetrics(outMetrics);// 給白紙設定寬高
return outMetrics.widthPixels;
}
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}

//最後使用
<com.你的包名.RichText/> RichText.setRichText();就行


//=============================================================================擴充 Picasso載入圓形圖片 解決比例失真問題 可不看
/**
* 畢加索 設定圓形頭像
* Created by swplzj on 16/12/10.
*/

public class CircleTransform implements Transformation {


private String Key = "CircleTransform";

private Context mContext;

private int h = 60;
public CircleTransform(Context context) {
this.mContext = context;
}


public CircleTransform(Context context,int height) {
this.mContext = context;
this.h = height;
}


@Override
public Bitmap transform(Bitmap source) {// 60 是我圖標題像的寬高度 壓縮
Bitmap zoomBitmp = BitmapUtils.zoom(source, DisplayUtil.dp2px(mContext, h), DisplayUtil.dp2px(mContext, h));
Bitmap bitmap = BitmapUtils.circleBitmap(zoomBitmp);
source.recycle();
return bitmap;//返回圓形的Bitmap對象
}

/**
* 該方法沒有什麼實際意義,但是要保證其返回的值不能為null!
* @return
*/
@Override
public String key() {
return Key;
}
}


public class BitmapUtils {

/**將矩形的Bitmap對象轉換為圓形的Bitmap
* @param source:待處理的 矩形的Bitmap
* @return :需返回的圓形的Bitmap
*/
public static Bitmap circleBitmap(Bitmap source){
//擷取Bitmap的寬度
int width = source.getWidth();
//返回一個正方形的Bitmap對象
Bitmap bitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
//提供指定寬高的canvas
Canvas canvas = new Canvas(bitmap);
//提供畫筆
Paint paint = new Paint();
paint.setAntiAlias(true);
//背景:在畫布上繪製一個圓
canvas.drawCircle(width / 2, width / 2, width / 2, paint);

//設定圖片相交情況下的處理方式
//setXfermode:設定當繪製的映像出現相交情況時候的處理方式的,它包含的常用模式有哪幾種
//PorterDuff.Mode.SRC_IN 取兩層映像交集部門,只顯示上層映像,注意這裡是指取相交叉的部分,然後顯示上層映像
//PorterDuff.Mode.DST_IN 取兩層映像交集部門,只顯示下層映像
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//前景:在畫布上繪製一個bitmap
canvas.drawBitmap(source, 0, 0, paint);

return bitmap;

}

/**對bitmap進行壓縮處理
* @param source :需要被處理的Bitmap
* @param width 需要壓縮成的寬度 必須為浮點型
* @param height 需要壓縮成的高度 必須為浮點型
* @return 返回壓縮後的Bitmap
* 注意!必須提供參數2,3為浮點型。
*/
public static Bitmap zoom(Bitmap source,float width,float height){
Matrix matrix = new Matrix();
float scaleX = width / source.getWidth();
float scaleY = height / source.getHeight();
matrix.postScale(scaleX, scaleY);

Bitmap bitmap = Bitmap.createBitmap(source,0,0,source.getWidth(),source.getHeight(),matrix,true);
return bitmap;
}
}
遺漏或者不清楚的可以聯絡我QQ群:521039620 Android&Go,Let‘s go!
感謝作者 https://github.com/zzhoujay/RichText (Gilde方式實現)
以及沒提到的網上參考 謝謝大家。

TextView載入html圖片非同步顯示(Picasso)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.