这段时间公司项目略忙,这不一有空就学点新的东西并记录下来,之前公司项目中有一个这样的界面效果,一个自定义的进度条控件,其实这东西并不是很难,麻烦就麻烦在细节上,无奈!虽然我并不知道他们是怎么完成这个效果的(猜想可能比较麻烦),再次记录下我自己的实现方式。在此之前得先来学习一下Android中的图形混合模式---PorterDuffXfermode。PorterDuff 是由两个人名的的组合Thomas Porter 和 Tom Duff ,PorterDuff是用于描述数字图像合成的基本手法,通过组合使用 Porter-Duff 操作,可完成任意 2D图像的合成;比如:各种形状的头像,刮刮卡效果等当然今天介绍的进度条也是由它来完成。
PS:其实在此之前我一直只是粗略的看过这个模式,一直没有去亲手实践一番,来记录这篇文章之前我肯定是自己实践过了。也算了了一桩心事吧。
- PorterDuff 的16种模式
首先使用这个模式很简单,只需要调用
Paint
对象的setXfermode(PorterDuffXfermode model)
方法即可,传入PorterDuffXfermode对象,该对象的构造方法如下:
/**
* Create an xfermode that uses the specified porter-duff mode.
*
* @param mode The porter-duff mode that is applied
*/
public PorterDuffXfermode(PorterDuff.Mode mode) {
this.mode = mode;
native_instance = nativeCreateXfermode(mode.nativeInt);
}
需要我们传入上图中16个模式的一种。这16个模式看图就很明白了,就是描述了两种图片相互组合后所形成的效果。
现在我们要实现这样的一种进度效果。
先不用吐槽这个很简单,因为这只是一个最基本的结构,或许还会有其他的样式会附加在上面。
要使用图像混合模式来完成它需要明确2点:
- 确定Src和Dst
- 设置合适的混合模式;
直接看代码,
package com.ggx.xfermodeandproterduff;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/** * Created by John on 2016/6/10. * */
public class PorterDuffXfermodeView extends View{
private static final String TAG = "PorterDuffXfermodeView";
private Paint mBitPaint;
private Bitmap mBGBitmap;
private Bitmap mDstBitmap;
private int mTotalWidth, mTotalHeight;
private int mBitWidth, mBitHeight;
private Rect mSrcRect;
private PorterDuffXfermode mXfermode;
private RectF mDynamicRect;
public PorterDuffXfermodeView(Context context) {
super(context);
init(context);
}
public PorterDuffXfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PorterDuffXfermodeView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);}
}
private void init(Context context) {
//初始化Xfermode的模式
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
//初始化画笔
mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitPaint.setFilterBitmap(true);
mBitPaint.setDither(true);
//获取背景图片
mBGBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.img_step_bg)).getBitmap();
//获取完整进度条图片
mDstBitmap = ((BitmapDrawable) ContextCompat.getDrawable(context, R.drawable.img_step_jd)).getBitmap();
mBitHeight = Math.min(mDstBitmap.getHeight(), DisplayUtil.getMobileHeight(context));
mBitWidth = Math.min(mDstBitmap.getWidth(), DisplayUtil.getMobileWidth(context));
//初始化原矩形大小为给定的背景图的大小
mSrcRect = new Rect(0, 0, mBitWidth, mBitHeight);
//动态变化的矩形
mDynamicRect = new RectF(0, 0, 0, mBitHeight);
}
@Overrideprotected void onDraw(Canvas canvas) {
// 创建存为新图层
canvas.drawBitmap(mBGBitmap, null, mSrcRect, null);
int saveLayerCount = canvas.saveLayer(0, 0, mTotalWidth, mTotalHeight, mBitPaint, Canvas.ALL_SAVE_FLAG);
// 绘制目标图为最终的完全进度条
canvas.drawRoundRect(mDynamicRect, mBitHeight, mBitHeight, mBitPaint);
// 设置混合模式
mBitPaint.setXfermode(mXfermode);
// 绘制源图形
canvas.drawBitmap(mDstBitmap, null, mSrcRect, mBitPaint);
// 清除混合模式
mBitPaint.setXfermode(null);
// 恢复保存的图层;
canvas.restoreToCount(saveLayerCount);
}
@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//设置总宽高
mTotalWidth = w;
mTotalHeight = h;
}
/**
* 设置进度条的数值变化这里就0~100
* * @param value
*/
public void setProgress(int value) {
value = value < 0 ? 0 : value > 100 ? 100 : value;
Log.i(TAG, "进度条增长" + value * (mBitWidth / 100));
ValueAnimator va = ValueAnimator.ofFloat(mDynamicRect.right, value * (mBGBitmap.getWidth() / 100));
va.setDuration(5000);
va.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
mDynamicRect.right = value;
postInvalidate();
}
});
va.start();
}
@Overrideprotected
void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.i(TAG, "释放资源");
if (mBGBitmap != null && !mBGBitmap.isRecycled()) {
mBGBitmap.recycle();
}
if (mDstBitmap != null && !mDstBitmap.isRecycled()) {
mDstBitmap.recycle();
}
}
好困,今天就到此吧