android 实现图片加载效果

本文介绍了一个自定义组件,通过使用 PorterDuff 模式和 BitmapDrawable 实现了类似新浪微博的图片加载效果,包括下载进度显示、前景色和文字颜色设定以及字体大小调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先贴图:

代码如下:

package com.android.activity;

import java.text.DecimalFormat;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

/**
 * 自定义组件实现新浪微博的图片加载效果。<br/>
 * 
 * 
 * 
 */
public class PorterDuffView extends ImageView {
	private static final String TAG = "PorterDuffView";
	/** 前景Bitmap高度为1像素。采用循环多次填充进度区域。 */
	public static final int FG_HEIGHT = 1;
	/** 下载进度前景色 (铺上的红色)*/
	// public static final int FOREGROUND_COLOR = 0x77123456;
	public static final int FOREGROUND_COLOR = 0x77ff0000;
	/** 下载进度条文字颜色。 */
	public static final int TEXT_COLOR = 0xff7fff00;
	/** 进度百分比字体大小。 */
	public static final int FONT_SIZE = 30;
	private Bitmap bitmapBg, bitmapFg;
	private Paint paint;
	/** 标识当前进度。 */
	private float progress;
	/** 标识进度图片的宽度与高度。 */
	private int width, height;
	/** 格式化输出百分比。 */
	private DecimalFormat decFormat;
	/** 进度百分比文本的锚定Y中心坐标值。 */
	private float txtBaseY;
	/** 标识是否使用PorterDuff模式重组界面。 */
	private boolean porterduffMode;
	/** 标识是否正在下载图片。 */
	private boolean loading;

	public PorterDuffView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context, attrs);
	}

	/** 生成一宽与背景图片等同高为1像素的Bitmap,。 */
	private static Bitmap createForegroundBitmap(int w) {
		Bitmap bm = Bitmap.createBitmap(w, FG_HEIGHT, Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bm);
		Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
		p.setColor(FOREGROUND_COLOR);
		c.drawRect(0, 0, w, FG_HEIGHT, p);
		return bm;
	}

	private void init(Context context, AttributeSet attrs) {
		if (attrs != null) {
			TypedArray typedArr = context.obtainStyledAttributes(attrs,
					R.styleable.PorterDuffView);
			porterduffMode = typedArr.getBoolean(
					R.styleable.PorterDuffView_porterduffMode, false);
		}
		Drawable drawable = getDrawable();
		if (porterduffMode && drawable != null
				&& drawable instanceof BitmapDrawable) {
			bitmapBg = ((BitmapDrawable) drawable).getBitmap();
			width = bitmapBg.getWidth();
			height = bitmapBg.getHeight();
			bitmapFg = createForegroundBitmap(width);//得到高度为1的红色前景色
		} else {
			// 不符合要求,自动设置为false。
			porterduffMode = false;
		}

		paint = new Paint();
		paint.setFilterBitmap(false);
		paint.setAntiAlias(true);
		paint.setTextSize(FONT_SIZE);
		Paint.FontMetrics fontMetrics = paint.getFontMetrics();
		// 注意观察本输出:
		// ascent:单个字符基线以上的推荐间距,为负数
		Log.i(TAG, "ascent:" + fontMetrics.ascent//
				// descent:单个字符基线以下的推荐间距,为正数
				+ " descent:" + fontMetrics.descent //
				// 单个字符基线以上的最大间距,为负数
				+ " top:" + fontMetrics.top //
				// 单个字符基线以下的最大间距,为正数
				+ " bottom:" + fontMetrics.bottom//
				// 文本行与行之间的推荐间距
				+ " leading:" + fontMetrics.leading);
		// 在此处直接计算出来,避免了在onDraw()处的重复计算
		txtBaseY = (height - fontMetrics.bottom - fontMetrics.top) / 2;

		decFormat = new DecimalFormat("0.0%");
	}

	public void onDraw(Canvas canvas) {
		if (porterduffMode) {
			int tmpW = (getWidth() - width) / 2, tmpH = (getHeight() - height) / 2;
			// 画出背景图
			canvas.drawBitmap(bitmapBg, tmpW, tmpH, paint);
			// 设置PorterDuff模式
			paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
			// canvas.drawBitmap(bitmapFg, tmpW, tmpH - progress * height,
			// paint);
			int tH = height - (int) (progress * height);
			for (int i = 0; i < tH; i++) {
				canvas.drawBitmap(bitmapFg, tmpW, tmpH + i, paint);
			}

			// 立即取消xfermode
			paint.setXfermode(null);
			int oriColor = paint.getColor();
			paint.setColor(TEXT_COLOR);
			paint.setTextSize(FONT_SIZE);
			String tmp = decFormat.format(progress);
			float tmpWidth = paint.measureText(tmp);
			canvas.drawText(decFormat.format(progress), tmpW
					+ (width - tmpWidth) / 2, tmpH + txtBaseY, paint);
			// 恢复为初始值时的颜色
			paint.setColor(oriColor);
		} else {
			Log.i(TAG, "onDraw super");
			super.onDraw(canvas);
		}
	}

	public void setProgress(float progress) {
		if (porterduffMode) {
			this.progress = progress;
			// 刷新自身。
			invalidate();
		}
	}


	public boolean isLoading() {
		return loading;
	}

	public void setLoading(boolean loading) {
		this.loading = loading;
	}

	public void setPorterDuffMode(boolean bool) {
		porterduffMode = bool;
	}
}


//图片加载类

package com.android.activity;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;


public class DownloadImgTask extends AsyncTask<String, Float, Bitmap> {
	private static final String TAG="DownloadImgTask";    
	private PorterDuffView pdView;
        

        public DownloadImgTask(PorterDuffView pdView) {
                this.pdView = pdView;
        }

        /** 下载准备工作。在UI线程中调用。 */
        protected void onPreExecute() {
        	Log.i(TAG, "onPreExecute");
        }

        /** 执行下载。在背景线程调用。 */
        protected Bitmap doInBackground(String... params) {
        	Log.i(TAG, "doInBackground:" + params[0]);
                HttpClient httpClient = new DefaultHttpClient();
                HttpGet httpGet = new HttpGet(params[0]);
                InputStream is = null;
                ByteArrayOutputStream baos = null;
                try {
                        HttpResponse httpResponse = httpClient.execute(httpGet);
                        printHttpResponse(httpResponse);
                        HttpEntity httpEntity = httpResponse.getEntity();
                        long length = httpEntity.getContentLength();
                        Log.i(TAG, "content length=" + length);
                        is = httpEntity.getContent();
                        if (is != null) {
                                baos = new ByteArrayOutputStream();
                                byte[] buf = new byte[128];
                                int read = -1;
                                int count = 0;
                                while ((read = is.read(buf)) != -1) {
                                        baos.write(buf, 0, read);
                                        count += read;
                                        publishProgress(count * 1.0f / length);
                                }
                                Log.i(TAG, "count=" + count + " length=" + length);
                                byte[] data = baos.toByteArray();
                                Bitmap bit = BitmapFactory.decodeByteArray(data, 0, data.length);
                                return bit;
                        }
                } catch (ClientProtocolException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                } finally {
                        try {
                                if (baos != null) {
                                        baos.close();
                                }
                                if (is != null) {
                                        is.close();
                                }
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                }
                return null;
        }

        /** 更新下载进度。在UI线程调用。onProgressUpdate */
        protected void onProgressUpdate(Float... progress) {
                pdView.setProgress(progress[0]);
        }

        /** 通知下载任务完成。在UI线程调用。 */
        protected void onPostExecute(Bitmap bit) {
        		Log.i(TAG, "onPostExecute");
                pdView.setPorterDuffMode(false);
                pdView.setLoading(false);
                pdView.setImageBitmap(bit);
        }

        protected void onCancelled() {
        		Log.i(TAG, "DownloadImgTask cancel...");
                super.onCancelled();
        }

        private void printHttpResponse(HttpResponse httpResponse) {
                Header[] headerArr = httpResponse.getAllHeaders();
                for (int i = 0; i < headerArr.length; i++) {
                        Header header = headerArr[i];
                        Log.i(TAG, "name[" + header.getName() + "]value[" + header.getValue() + "]");
                }
                HttpParams params = httpResponse.getParams();
                Log.i(TAG, String.valueOf(params));
                Log.i(TAG, String.valueOf(httpResponse.getLocale()));
        }
}

//主activity

package com.android.activity;

import android.app.Activity;
import android.os.Bundle;

public class ActAsyncTaskActivity extends Activity{
    private PorterDuffView pViewA;
    public static final String[] STRING_ARR = {//
    "http://developer.android.com/images/home/android-jellybean.png",//
                    "http://developer.android.com/images/home/design.png",//
                    "http://developer.android.com/images/home/google-play.png",//
                    "http://developer.android.com/images/home/google-io.png" };

    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            pViewA = (PorterDuffView) findViewById(R.id.pViewA);
            
            if (pViewA.isLoading() == false) {
                DownloadImgTask task = new DownloadImgTask(pViewA);
                task.execute(STRING_ARR[pViewA.getId() % STRING_ARR.length]);
                pViewA.setPorterDuffMode(true);
                pViewA.setLoading(true);
                pViewA.setProgress(0);
                pViewA.invalidate();
        }
    }

}

//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:porterduff="http://schemas.android.com/apk/res/com.android.activity"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
	<ScrollView 
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    android:orientation="vertical"
	    >
	    <LinearLayout 
	        android:layout_width="fill_parent"
		    android:layout_height="wrap_content"
		    android:orientation="vertical"
		    >
		    <com.android.activity.PorterDuffView
				android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:id="@+id/pViewA"
		        android:src="@drawable/weibo1"
		        android:layout_gravity="center"
		        porterduff:porterduffMode="true"
			    />
		   
		    
		</LinearLayout>
	</ScrollView>
</LinearLayout>


附上源码下载地址:

http://download.youkuaiyun.com/detail/duanyu218/5046973









                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值