Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android塗鴉技術及刮刮樂示例分析

Android塗鴉技術及刮刮樂示例分析

編輯:關於Android編程

概述:

很早之前就想研究一下Android中的塗鴉,其實也說不上是研究了,畢竟都是一些相對比較簡單的知識點。下面就對基於畫布(Canvas)和觸摸事件(onTouchEvent)來實現塗鴉和刮刮樂。

 

 

示例分析:

以下是兩個簡單的入門示例:塗鴉技術和刮刮樂的一些簡單分析和效果展示。

 

1.塗鴉

思路分析及代碼展示

學習過Canvas的同學應該都知道我們可以通過在一個View上覆蓋一個canvas,並實現View的onTouchEvent方法就可以在Canvas上留下觸摸屏幕時的軌跡,對於軌跡的記錄還有一個類需要去了解——Path。關於Canvas更多的知識請點擊這裡查看。

Android在繪制界面的時候會獲得布局中控件的大小、位置等參數之後再去繪制。而這裡我們只是通過onMeasure和onDraw來繪制,沒有用到onLayout是因為這裡只有一個控件,沒有太多動態布局需要處理。對於路徑的記錄則需要onTouchEvent實現。

測量大小:

 

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        
        // 初始化bitmap
        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

繪制:

 

 

protected void onDraw(Canvas canvas) {
        drawPath();
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }

 

路徑繪制:

我們通過Path保存我們觸摸的路徑軌跡。如下:

 

private void drawPath() {
        mFingerPaint.setStyle(Paint.Style.STROKE);
        mCanvas.drawPath(mPath, mFingerPaint);
    }

 

觸摸事件:

對於觸摸事件有一個非常重要而且不可忽視的類就是MotionEvent。它有以下三個常用的動作事件:

1.MotionEvent.ACTION_DOWN // 觸摸按下時

2.MotionEvent.ACTION_MOVE // 觸摸在移動過程中

3.MotionEvent.ACTION_UP // 觸摸離開時

 

下面就看看onTouchEvent事件的實現過程:

 

public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            actionMotionEventDown(x, y);
            break;
            
        case MotionEvent.ACTION_MOVE:
            actionMotionEventMove(x, y);
            break;
        }

        invalidate();
        return true;
    }

上面的代碼中,我們在按下的時候實現了按下的邏輯,在手指在屏幕上移動的時候實現了Move的邏輯。還有別忘了invalidate()。invalidate()函數的主要作用是請求View樹進行重繪,如果你不去調用它,結果就是什麼事情都不會發生。

 

 

效果圖

\

 

2.刮刮樂

思路分析及代碼展示

分析:其實刮刮樂的實現思路跟塗鴉很像,都是在一塊地方瞎畫,並留下痕跡(說笑了,不過也不無道理。^_^)。不過有一點不同的就是我們在刮刮樂的繪制過程中畫筆經過的地方,是變成了透明的了。這裡你可能會說,那簡單了,不就是要我去覆蓋兩層圖片,在去繪制觸摸路徑,只是觸摸路徑的顏色是透明的。真的是這樣的麼?你可以試一試。當然,這樣是行不通的,關於實踐的最終效果大家可以自行嘗試。這裡的關鍵點在於我們要把上面的蒙層擦除且保留下面的底層。這裡就用到了圖形混合技術了。

圖形混合技術一聽名稱是不是就是感覺很高深,不過的確是很牛的技術,不過Java已經給我們封裝好了,我們只要知道怎麼使用即可,而使用它則就不那麼艱難了。

關於圖形混合的詳細描述,大家可以參考這裡,我就不重復制造輪子了。不過我還是要簡單介紹一下Xfermode三個子類下的一個:PorterDuffXfermode。這是一個非常強大的轉換模式,使用它,可以使用圖像合成的16條Porter-Duff規則的任意一條來控制Paint如何與已有的Canvas圖像進行交互。

 

Porter-Duff規則如下:

\

PorterDuff.Mode為枚舉類,一共有16個枚舉值:
1.PorterDuff.Mode.CLEAR
所繪制不會提交到畫布上。
2.PorterDuff.Mode.SRC
顯示上層繪制圖片
3.PorterDuff.Mode.DST
顯示下層繪制圖片
4.PorterDuff.Mode.SRC_OVER
正常繪制顯示,上下層繪制疊蓋。
5.PorterDuff.Mode.DST_OVER
上下層都顯示。下層居上顯示。
6.PorterDuff.Mode.SRC_IN
取兩層繪制交集。顯示上層。
7.PorterDuff.Mode.DST_IN
取兩層繪制交集。顯示下層。
8.PorterDuff.Mode.SRC_OUT
取上層繪制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下層繪制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下層非交集部分與上層交集部分
11.PorterDuff.Mode.DST_ATOP
取上層非交集部分與下層交集部分
12.PorterDuff.Mode.XOR
異或:去除兩圖層交集部分
13.PorterDuff.Mode.DARKEN
取兩圖層全部區域,交集部分顏色加深
14.PorterDuff.Mode.LIGHTEN
取兩圖層全部,點亮交集部分顏色
15.PorterDuff.Mode.MULTIPLY
取兩圖層交集部分疊加後顏色
16.PorterDuff.Mode.SCREEN
取兩圖層全部區域,交集部分變為透明色

 

我們需要的正是:DstOut這一條。代碼中我們是這樣實現的:

 

private void drawPath() {
        mFingerPaint.setStyle(Paint.Style.STROKE);
        // 設置兩張圖片相交時的模式(取下層繪制非交集部分)
        mFingerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mCanvas.drawPath(mPath, mFingerPaint);
    }

測量和繪制過程如下:

 

 

@Override
    protected void onDraw(Canvas canvas) {
        canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2, getHeight() / 2 + mTextBound.height() / 2, mBackPint);
        
        if (!isComplete) {
            drawPath();
            canvas.drawBitmap(mBitmap, 0, 0, null);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        
        // 初始化bitmap
        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);

        // 繪制遮蓋層
        mFingerPaint.setStyle(Paint.Style.FILL);
        mCanvas.drawRoundRect(new RectF(0, 0, width, height), 30, 30, mFingerPaint);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.mask), null, new RectF(0, 0, width, height), null);
    }

此外還有一篇也是使用了此技術的博客,點擊這裡進行查看。

 

 

效果圖

\

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved