Android自定義刮刮卡刮獎

今天要分享的是Android上的刮刮卡控件隐轩。按照國際慣例,先上效果圖渤早。
主要的功能:

  1. 自定義刮開后的文字职车、圖片;
  2. 自定義覆蓋層的顏色、圖片悴灵;
  3. 刮開大部分刮涂層后扛芽,自動清除剩余刮涂層;

按照國際慣例积瞒,線上效果圖:


刮刮卡.gif

源碼放在最后

一川尖、實現(xiàn)思路

  1. 繪制獎區(qū)文字;
  2. 繪制刮涂層茫孔;
  3. 監(jiān)聽用戶touch事件叮喳,跟隨用戶touch軌跡清除掛涂層對應(yīng)位置的像素;
  4. 監(jiān)聽掛涂層剩余像素缰贝,當(dāng)達(dá)到一個閾值時馍悟,清空所有像素。

二剩晴、繪制獎區(qū)文字

首先需要new一個專門負(fù)責(zé)繪制文字的paint锣咒。然后后面根據(jù)自定義屬性設(shè)置的文字大小、顏色赞弥,以及獎區(qū)的內(nèi)容毅整,使用canvas.drawText()方法去繪制文字。

但是要把文字繪制在刮刮卡的正中間绽左,就需要我們自己去計算drawText的起始點坐標(biāo)悼嫉。這里的思路是:

  1. 在onMeasure中獲取整個刮刮卡的高和寬;
  2. 計算要顯示的文字所占的整個Rect的高和寬拼窥;
  3. 用整個(刮刮卡的寬 - 文字所占的寬)/2得到x軸的起始坐標(biāo)承粤;
  4. 用整個(刮刮卡的高 - 文字所占的高)/2得到y(tǒng)軸的起始坐標(biāo);
//計算獎區(qū)文字區(qū)域的大小闯团,用于后面計算獎區(qū)文字起始點的坐標(biāo)
mPrizeTextPaint.setColor(mPrizeTextColor);
mPrizeTextPaint.setTextSize(mPrizeTextSize);
mTextBound = new Rect();
 mPrizeTextPaint.getTextBounds(mPrizeContent, 0, mPrizeContent.length(), mTextBound);
 //繪制獎區(qū)內(nèi)容辛臊,這里要繪制在整個View的正中間.
canvas.drawText(mPrizeContent, getWidth() / 2 - mTextBound.width() / 2, 
                  getHeight() / 2 + mTextBound.height() / 2, mPrizeTextPaint);

三、繪制刮涂層

這個是繪制整個控件的重點房交。這里的思路是new一個bitmap對象彻舰,把刮涂層涂層以及后面用戶手指刮開的路徑混合在一起,然后通過canvas繪制到這個bitmap上候味。最后在onDraw的時候刃唤,使用整個控件的canvas對象去繪制出這個bitmap對象,從而實現(xiàn)刮涂效果白群。

先在onMeasure中計算出整個刮刮卡的寬和高尚胞,然后new一個一樣大小的bitmap對象。使用一個canvas對象來繪制到這個bitmap中帜慢。

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        //初始化刮涂層的畫布,并將刮涂層的內(nèi)容全部保存到bitmap對象中笼裳。
        //最后在onDraw中調(diào)用控件的canvas去繪制這個bitmap唯卖,從而實現(xiàn)刮獎的效果。
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mCoverCanvas = new Canvas(mBitmap);
        mCoverCanvas.drawColor(Color.parseColor("#c0c0c0"));//先draw src躬柬,后面會draw dist

監(jiān)聽用戶擦除的路徑拜轨。通過重寫onTouchEvent事件。通過一個Path對象來記錄用戶擦除的痕跡允青。每touch一次橄碾,就在Path上增加一條。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mTouchPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                mTouchPath.lineTo(event.getX(), event.getY());
                float dx = Math.abs(x - mLastX);
                float dy = Math.abs(y - mLastY);
                if (dx > 3 || dy > 3) {
                    mTouchPath.lineTo(x, y);
                }
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_UP:
                //計算已經(jīng)刮完的像素
                if (!isCompleted)
                    new Thread(mRunnable).start();
                break;
        }
        if (!isCompleted)
            invalidate();
        return true;//消費掉touch事件
    }

然后設(shè)置涂層畫筆的Xfermode屬性颠锉,也就是圖像的混合模式繪制出來法牲。

paint的Xfermode屬性的使用,參照下面這張圖
paint.Xfermode
然使用的時候遵循先畫Src琼掠,設(shè)置Xfermode屬性皆串,最后畫Dist的順序來把用戶刮涂軌跡Path對象給draw到之前一張沒有被刮的涂層上去。
    /**
     * 繪制用戶手指刮過的路徑
     */
    private void drawPath() {
        mCoverPaint.setStyle(Paint.Style.STROKE);
        mCoverPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mCoverCanvas.drawPath(mTouchPath, mCoverPaint);
    }

經(jīng)過上面的這些操作眉枕,我們定義的bitmap就成了灰色涂層和用戶觸摸軌跡混合的一個對象了。最后就在onDraw中繪制到canvas中就可以了怜森。

canvas.drawBitmap(mBitmap, 0, 0, null);

四速挑、監(jiān)聽刮涂的面積,當(dāng)達(dá)到一定閾值的時候副硅,自動清空剩余的涂層

這里就需要在用戶每次在otionEvent.ACTION_UP的時候去判斷我們涂層的bitmap對象有多少像素的像素值為0了(像素值為0代表透明)姥宝。然后計算一下透明的像素數(shù)量占總像素的百分比。如果這個百分比超過閾值恐疲,那么再重新繪制到額時候腊满,就不去繪制掛涂層,就可以實現(xiàn)清空剩余掛涂層的效果了培己。

為了不因為計算這個像素數(shù)量而引起UI線程阻塞碳蛋,我們另開一個線程來計算。同時設(shè)置一個volatile修飾的布爾對象來標(biāo)識是否達(dá)到閾值省咨。主線程通過這個標(biāo)識來判斷是否需要繪制掛涂層肃弟。

    private Runnable mRunnable = new Runnable()
    {
        @Override
        public void run() {
            int w = getWidth();
            int h = getHeight();

            float wipeArea = 0;
            float totalArea = w * h;
            Bitmap bitmap = mBitmap;
            int[] mPixels = new int[w * h];

            bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);
            //計算被擦除的區(qū)域(也就是像素值為0)的像素數(shù)之和
            for (int i = 0; i < w; i++) {
                for (int j = 0; j < h; j++) {
                    int index = i + j * w;
                    if (mPixels[index] == 0) {
                        wipeArea++;
                    }
                }
            }
            //計算擦除的像素數(shù)與總像素數(shù)的百分比
            if (wipeArea > 0 && totalArea > 0) {
                int percent = (int) (wipeArea * 100 / totalArea);
                if (percent > 60) {
                    isCompleted = true;
                    postInvalidate();
                }
            }
        }
    };

最后獻(xiàn)上源碼,有任何問題的朋友零蓉,歡迎在下面留言笤受。
源碼下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市敌蜂,隨后出現(xiàn)的幾起案子箩兽,更是在濱河造成了極大的恐慌,老刑警劉巖章喉,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汗贫,死亡現(xiàn)場離奇詭異身坐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)芳绩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門掀亥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妥色,你說我怎么就攤上這事搪花。” “怎么了嘹害?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵撮竿,是天一觀的道長。 經(jīng)常有香客問我笔呀,道長幢踏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任许师,我火速辦了婚禮房蝉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘微渠。我一直安慰自己搭幻,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布逞盆。 她就那樣靜靜地躺著檀蹋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪云芦。 梳的紋絲不亂的頭發(fā)上俯逾,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機(jī)與錄音舅逸,去河邊找鬼桌肴。 笑死,一個胖子當(dāng)著我的面吹牛琉历,可吹牛的內(nèi)容都是我干的识脆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼善已,長吁一口氣:“原來是場噩夢啊……” “哼灼捂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起换团,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤悉稠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后艘包,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體的猛,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡耀盗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了卦尊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叛拷。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖岂却,靈堂內(nèi)的尸體忽然破棺而出忿薇,到底是詐尸還是另有隱情,我是刑警寧澤躏哩,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布署浩,位于F島的核電站,受9級特大地震影響扫尺,放射性物質(zhì)發(fā)生泄漏筋栋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一正驻、第九天 我趴在偏房一處隱蔽的房頂上張望弊攘。 院中可真熱鬧,春花似錦姑曙、人聲如沸襟交。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至授瘦,卻和暖如春醋界,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背提完。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工形纺, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徒欣。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓逐样,卻偏偏與公主長得像,于是被迫代替她去往敵國和親打肝。 傳聞我的和親對象是個殘疾皇子脂新,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容