美文网首页
Android PorterDuffXfermode

Android PorterDuffXfermode

作者: Ggx的代码之旅 | 来源:发表于2016-06-11 02:55 被阅读432次

    这段时间公司项目略忙,这不一有空就学点新的东西并记录下来,之前公司项目中有一个这样的界面效果,一个自定义的进度条控件,其实这东西并不是很难,麻烦就麻烦在细节上,无奈!虽然我并不知道他们是怎么完成这个效果的(猜想可能比较麻烦),再次记录下我自己的实现方式。在此之前得先来学习一下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点:

    1. 确定Src和Dst
    2. 设置合适的混合模式;

    直接看代码,

    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();
        }
    }
    

    好困,今天就到此吧

    相关文章

      网友评论

          本文标题:Android PorterDuffXfermode

          本文链接:https://www.haomeiwen.com/subject/upgsdttx.html