Canvas開篇之drawBitmap方法講解,canvasdrawbitmap

來源:互聯網
上載者:User

Canvas開篇之drawBitmap方法講解,canvasdrawbitmap


尊重原創,歡迎轉載,轉載請註明: FROM  GA_studio   http://blog.csdn.net/tianjian4592   


前面講了paint,後面會花幾篇主要講講canvas,並且由於最近項目比較緊,所以近期的文章都會“短小精悍”;

paint 作為畫筆,裡面有非常多而強大的設定方法,比如設定顏色過濾器,設定位元影像渲染、漸層,設定映像的混合模式等等,而canvas呢?裡面提供了哪些利器可以為我們所用,一起來看看:


     

   


通過我們可以看到,canvas 裡的方法基本可以分為這麼幾類:

1. save、restore 等與層的儲存和復原相關的方法;

2. scale、rotate、clipXXX 等對畫布進行操作的方法;

3. drawXXX 等一系列繪畫相關的方法;


所以canvas 我們也就可以分上面三塊逐個擊破,今天咱們主要看 drawXXX裡的drawBitmap,看完之後一起做一個漂浮星空的小栗子;

在Canvas 裡 drawBitmap 有如下方法可用 :


而咱們也主要講其中的 drawBitmap(Bitmap,Rect,Rect,Paint);

首先咱們建立一個View,照舊重寫裡面的 onMeasure、onDraw、onSizeChanged,並且在 onSizeChanged 裡拿到view的寬高:

public class DrawBitmapView extends View {    private Resources mResources;    private Paint mBitPaint;    private Bitmap mBitmap;    private Rect mSrcRect, mDestRect;    // view 的寬高    private int mTotalWidth, mTotalHeight;    public DrawBitmapView(Context context) {        super(context);        mResources = getResources();        initBitmap();        initPaint();    }    private void initPaint() {        mBitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mBitPaint.setFilterBitmap(true);        mBitPaint.setDither(true);    }    private void initBitmap() {        mBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.<span style="font-family: Arial, Helvetica, sans-serif;">beautiful_girl</span>))                .getBitmap();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        mTotalWidth = w;        mTotalHeight = h;    }}

上面我們通過

mBitmap = ((BitmapDrawable) mResources.getDrawable(R.drawable.<span style="font-family: Arial, Helvetica, sans-serif;">beautiful_girl</span>))                .getBitmap();

拿到了對應的bitmap,這時候我們如果要將它繪製在螢幕上,需要建立兩個Rect,其實只要明白了這兩個Rect的意義並會靈活運用就可以做出不少效果;

第一個Rect 代表要繪製的bitmap 地區,第二個 Rect 代表的是要將bitmap 繪製在螢幕的什麼地方,我們一起來看下:

此時我先定義兩個Rect,mSrcRect 取值為整個Bitmap 地區 ,mDestRect 取值為view左上方和bitmap同樣大小;

private Rect mSrcRect, mDestRect;

mSrcRect = new Rect(0, 0, mBitWidth, mBitHeight);mDestRect = new Rect(0, 0, mBitWidth, mBitHeight);

在onDraw 裡繪製該位元影像:

canvas.drawBitmap(mBitmap, mSrcRect, mDestRect, mBitPaint);

此時繪製效果如下,在螢幕的左上方出現了個美女:



畫在左上方似乎缺乏美感,我們把美女畫在view的中心,沒錯,我們只需要改變mDestRect:

// 計算左邊位置int left = mHalfWidth - mBitWidth / 2;// 計算上邊位置int top = mHalfHeight - mBitHeight / 2;mDestRect = new Rect(left, top, left + mBitWidth, top + mBitHeight);

位置計算的時候,只需要注意在android螢幕座標系裡,左上方的位置是(0,0),往右往下為正,此時效果如下:


既然可以如此輕易的改變繪製的位置,那咱們不斷的改變bitmap繪製的位置,類比一下translate效果;

我們向外提供兩個介面:

public void startTranslate() {        startTranslate(0, 0, 200, 200, 1000);    }    /**     * 移動位元影像     *      * @param startLeft 起始左邊距     * @param startTop 起始距上邊距離     * @param toLeft 到達左邊距     * @param toTop 到達上邊距     * @param duration 時間長度     */    public void startTranslate(int startLeft, int startTop, int toLeft, int toTop, long duration) {        mStartLeft = startLeft;        mStartTop = startTop;        mToLeft = toLeft;        mToTop = toTop;        // 使用ValueAnimator建立一個過程        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);        valueAnimator.setDuration(duration);        valueAnimator.setInterpolator(new AccelerateInterpolator());        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animator) {                // 不斷重新計算上下左右位置                float fraction = (Float) animator.getAnimatedValue();                int currentLeft = (int) ((mToLeft - mStartLeft) * fraction + mStartLeft);                int currentTop = (int) ((mToTop - mStartTop) * fraction + mStartTop);                if (mDestRect == null) {                    mDestRect = new Rect(currentLeft, currentTop, currentLeft + mBitWidth,                            currentTop + mBitHeight);                }                mDestRect.left = currentLeft;                mDestRect.right = currentLeft + mBitWidth;                mDestRect.top = currentTop;                mDestRect.bottom = currentTop + mBitHeight;                // 重繪                postInvalidate();            }        });        valueAnimator.start();    }

Activity 裡控制view的移動:

final DrawBitmapView drawBitmapView = new DrawBitmapView(this);        setContentView(drawBitmapView, new LayoutParams(LayoutParams.MATCH_PARENT,                LayoutParams.MATCH_PARENT));        drawBitmapView.startTranslate();        drawBitmapView.setOnTouchListener(new OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                Random random = new Random();                int startLeft = random.nextInt(200);                int startTop = random.nextInt(250);                int toLeft = random.nextInt(550) + 200;                int toBottom = random.nextInt(1000) + 250;                drawBitmapView.startTranslate(startLeft, startTop, toLeft, toBottom, 1000);                return true;            }        });    }

點擊之後起始點和到達點隨機產生,此時效果如下:



相信到這裡大家已經能靈活控制bitmap的位置了,順勢咱們再做個水平縮放為0的小例子:

public void startScale(long duration) {        // 使用ValueAnimator建立一個過程        ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 0);        valueAnimator.setDuration(duration);        valueAnimator.setInterpolator(new AccelerateInterpolator());        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animator) {                // 不斷重新計算上下左右位置                float fraction = (Float) animator.getAnimatedValue();                if (mDestRect == null) {                    mDestRect = new Rect(0, 0, mBitWidth,                            mBitHeight);                }                mDestRect.right = (int) (fraction * mBitWidth);                // 重繪                postInvalidate();            }        });        valueAnimator.start();    }

只需要不斷減小mDestRect.right即可,非常簡單,看下效果:



      上面兩個例子都是通過改變mDestRect ,在哪些時候我們需要動態改變mSrcRect 呢?我前面講過一個水波紋的例子,那裡面就是不斷截取水波紋的一部分,進行展示,由於是連續截取,所以視覺感受上是連續波紋效果,有興趣的同學可以看看參考下; 


    好了本篇就講這麼多,有些同學可能會想,尼瑪,這麼簡單的玩意兒能做毛線牛逼動效啊,其實往往再複雜的動效也就是由一個個小點組成的,而思路和方案的選取就已經決定了能否成功的做出酷炫又如絲般順滑的效果,好的思路又往往來源於對簡單方法的深刻理解;

    

    下篇我們就一起完成一個星球浮動的效果!



    轉成gif之後失真嚴重,並且感覺有卡頓,真實情況如夢如幻,如絲般順滑!

    好了,還是不吹牛逼了,這個栗子只是為了加深對這個方法的理解,同時擴充動效繪製的思路!

    註:哪位大神有好的製作gif的方法,還望不吝賜教,目前我是採用的電腦錄屏,然後PS轉gif,感覺失真比較嚴重!



相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.