Android 自定義View----離屏緩衝和圖像混合模式(圓形頭像)

這裏主要了解下離屏緩衝和圖像混合模式,可能在自定義view的時候會用到,繪製的內容也非常簡單,一個簡單的圓形頭像

繪製大概分爲5步:

1,開啓離屏緩衝

2,繪製一個圓

3,設置圖像混合模式   https://www.cnblogs.com/libertycode/p/6290497.html

4,繪製bitmap

5,繪製完成後使用 restoreToCount 將離屏緩衝的繪製內容拿回來

/**
 * 離屏緩衝和圖像混合模式(圓形頭像)
 */
public class HeadPhotoView extends View {

    private float imgWidth = UnitUtil.dp2px(260);
    private float mPadding = UnitUtil.dp2px(50);

    private Paint mPaint;
    private Bitmap mBitmap;
    // 圖像混合模式
    Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    RectF savedArea = new RectF();

    public HeadPhotoView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.RED);
        mBitmap = getAvatar((int) imgWidth);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        savedArea.set(
                mPadding, mPadding,
                mPadding + imgWidth, mPadding + imgWidth
        );
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /*
        和save幾乎一樣,唯一區別相比save會把繪製內容挪到離屏緩衝去
        必須設置,否則PorterDuffXfermode無效

        離屏緩衝還可通過setLayerType(LAYER_TYPE_HARDWARE,null)設置:
        三個參數
            setLayerType(LAYER_TYPE_HARDWARE,null);         開啓硬件加速外會額外有一個離屏緩衝,耗性能
            setLayerType(LAYER_TYPE_SOFTWARE,null);         關閉硬件加速
            setLayerType(LAYER_TYPE_NONE,null);             開啓硬件加速

        官方詳解用途:在開啓動畫之前通過setLayerType()開啓離屏緩衝,動畫結束時再關閉;
                      對自定義屬性動畫無用,只是自帶的屬性動畫有用
             例: view.setLayerType(View.LAYER_TYPE_HARDWARE,null);
                  ObjectAnimator animator = ObjectAnimator.ofFloat(view,"rotationY",180);
                  animator.addListener(new AnimatorListenerAdapter(){
                        @Override
                        public void onAnimationEnd(Animator animation){
                            view.setLayerType(LAYER_TYPE_NONE,null)
                        }
                  });
                  animator.start();

         對比saveLayer():
            saveLayer比較靈活,在繪製的過程中就可以加,官方建議少用,方法很重
            setLayerType()相比saveLayer不靈活,而且是全局的,比如在此類中可在{}中添加setLayerType(LAYER_TYPE_HARDWARE,null)開啓離屏緩衝,
                            這樣就是全局開啓離屏緩衝,也就意味着侷限性,假設你在此類中做疊加繪製之前有其他繪製內容,就不能使用
         */

        int saved = canvas.saveLayer(savedArea, mPaint);

        // 繪製一個圓(繪製橢圓是因爲座標點好計算,寬高一樣就是圓)
        canvas.drawOval(
                mPadding, mPadding,
                mPadding + imgWidth, mPadding + imgWidth,
                mPaint
        );

        // 設置圖像混合模式,進行疊加繪製
        mPaint.setXfermode(xfermode);

        // 繪製bitmap
        canvas.drawBitmap(
                mBitmap,
                mPadding, mPadding, // 左上padding
                mPaint
        );

        mPaint.setXfermode(null);

        // 繪製完成後使用 restoreToCount 將離屏緩衝的繪製內容拿回來
        canvas.restoreToCount(saved);

    }

    Bitmap getAvatar(int width) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        // inJustDecodeBounds爲true,不返回bitmap,只返回這個bitmap的尺寸
        options.inJustDecodeBounds = true;
        // 從資源中讀取(比較浪費資源,所以上面設置爲true,只獲取圖片寬高)
        BitmapFactory.decodeResource(getResources(), R.drawable.qyn, options);
        // 再設置爲false,最後要返回bitmap
        options.inJustDecodeBounds = false;
        // 根據縮放比例重新計算寬高
        options.inDensity = options.outWidth;
        options.inTargetDensity = width;
        return BitmapFactory.decodeResource(getResources(), R.drawable.qyn, options);
    }

}

硬件加速:CPU把繪製內容轉換爲GPU操作,然後交給GPU進行,由GPU負責真正的繪製,這就叫硬件繪製,使用GPU繪製就叫做硬件加速;

 

離屏緩衝:單獨的一個繪製View的區域

 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章