当前位置:操作系统 > 安卓/Android >>

PorterDuff使用实例----实现新浪微博图片下载效果

先上效果图,如demo_sinaweibo.gif

由效果图,下半部分是简单的效果叠加,上半部分是新浪微博加载图片显示进度的效果,显示进度的半透明区域只与根据背景图的非透明区域叠加,背景图的透明区域仍为透明。
为实现此要求,联想到APIDemos中的com.example.android.apis.graphics.Xfermodes,可以自定义组件在组件的绘制过程中设置PorterDuff.Mode即可实现。
另效果图中显示当下载进度超过50%时,重新设置了背景图。

本次自定义组件选择继承ImageView来实现,名为PorterDuffView。将ImageView新增一porterduffMode。在该模式下,将可显示图片加载进度;否则按ImageView原有规则显示图片。


1.PorterDuffView的XML编码

设置PorterDuffView的porterduffMode,可有两种方式,一为在xml中设置,一为在代码设置。

xml中设置的实现:
在/res/values下新建一"attrs.xml",内容如下:
[html] 
<?xml version="1.0" encoding="UTF-8"?> 
<resources> 
    <!--请参阅 
    [android_sdk]\platforms\android-n\data\res\values\attrs.xml 
    --> 
    <declare-styleable name="porterduff.PorterDuffView"> 
        <attr name="porterduffMode" format="boolean"></attr> 
    </declare-styleable> 
</resources> 

在此声明中,属性名为"porterduffMode",对其赋值范围为boolean型。赋值范围的规范可参考:[android_sdk]\platforms\android-n\data\res\values\attrs.xml

有声明后,在layout下的布局文件,需首先在原有基础上添加一命名空间,代码如下:
[html] 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:porterduff="http://schemas.android.com/apk/res/lab.sodino.porterduff" 
   android:orientation="vertical" 
.... .... 
></LinearLayout> 

命名空间名为"porterduff",赋值规则为"http://schemas.android.com/apk/res/"+App包名。
在布局文件中使用PorterDuffView时,几乎与ImageView一致,设置porterduffMode如下:
[html]
<lab.sodino.porterduff.PorterDuffView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/porterDuffView" 
    android:src="@drawable/loading" 
    android:layout_gravity="center" 
    porterduff:porterduffMode="true" 
></lab.sodino.porterduff.PorterDuffView> 

另,在代码中设置porterduffMode为直接调用setPorterDuffMode(boolean),参数为true即可。


2.PorterDuffView的Java编码
需要重写ImageView的onDraw()方法。
当其porterduffMode值为true时,显示图片加载进度。否则按ImageView 的规则显示图片。
由效果图可知,需要生成一半透明的前景图。
生成前景图的代码为:
[java] 
/** 生成一宽与背景图片等同高为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; 

为节约内存消耗,生成的前景图Bitmap其高度只有1像素。那么在onDraw()方法中,需要根据加载进度,循环滴绘制叠加区域。代码如下:
[java] view plaincopy
int tH = height - (int) (progress * height); 
for (int i = 0; i < tH; i++) { 
    canvas.drawBitmap(bitmapFg, tmpW, tmpH + i, paint); 

在onDraw()方法中,调用Paint.setXfermode()绘制完叠加区域后,应再次对其设置值为null取消PorterDuff效果。

加载区域的进度值由PorterDuffView.setProgress()决定,因为每次设定新的进度后,应该调用 invalidate()及时刷新界面。
效果图中进度过50%时更改了背景图,方法为PorterDuffView.setBitmap(),该方法将重新计算Bitmap的宽高,并生成新的前景图,调用ImageView.setImageBitmap()请求对组件重新布局及刷新界面。

本文为Sodino所有,转载请注明出处:http://blog.csdn.net/sodino/article/details/7741236
以下贴出Java代码,XML请看官自行实现:
[java] 
ActPorterDuff.java 
 
package lab.sodino.porterduff; 
 
import android.app.Activity; 
import android.graphics.BitmapFactory; 
import android.os.Bundle; 
import android.widget.SeekBar; 
import android.widget.SeekBar.OnSeekBarChangeListener; 
 
public class ActPorterDuff extends Activity implements OnSeekBarChangeListener { 
    private SeekBar seekbar; 
    private PorterDuffView porterDuffView; 
    private int currentId; 
 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
 
        seekbar = (SeekBar) findViewById(R.id.seekbar); 
        seekbar.setOnSeekBarChangeListener(this); 
        float progress = seekbar.getProgress() * 1.0f / seekbar.getMax(); 
        porterDuffView = (PorterDuffView) findViewById(R.id.porterDuffView); 
        porterDuffView.setProgress(progress); 
    } 
 
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 
        porterDuffView.setProgress(progress * 1.0f / seekbar.getMax()); 
 
        if (progress > 50 && currentId != R.drawable.loading_2) { 
            currentId = R.drawable.loading_2; 
            porterDuffView.setBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.loading_2)); 
        } else if (progress <= 50 && currentId != R.drawable.loading) { 
            currentId = R.drawable.loading; 
            porterDuffView.setBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.loading)); 
        } 
    } 
 
    public void onStartTrackingTouch(SeekBar seekBar) { 
    } 
 
    public void onStopTrackingTouch(SeekBar seekBar) { 
    } 

[java] 
PorterDuffView.java 
 
package lab.sodino.porterduff; 
 
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.g

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,