Android 類似一筆畫游戲的Canvas實現(xiàn)

直接上效果:


11.jpg

22.jpg
33.jpg
44.jpg
55.jpg

還實現(xiàn)了前進兵罢,后退,清除功能
下面是主要代碼:

package com.ltmb.demo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.socks.library.KLog;

import java.util.ArrayList;
import java.util.List;

/**
 * @author chenshichun
 * 創(chuàng)建日期:2022/4/25
 * 描述:
 */
public class DrawView extends View implements View.OnClickListener {

    private final Canvas canvas;//聲明畫筆
    private final Paint paint;//聲明畫布
    private final Paint surfacePaint;//聲明畫布
    private final Bitmap bitmap;//聲明位圖
    private final Paint textPaint;//聲明畫布
    private final Context context;
    private final List<PointBean> pointBeanList = new ArrayList();// 點集合
    private final List<PointBean> pointBeanListCopy = new ArrayList();// 點集合備份數(shù)據(jù)但汞,用于前進
    private final List<LineBean> lineBeansList = new ArrayList();// 線集合

    public DrawView(Context context) {
        super(context);
        this.context = context;
        // TODO 自動生成的構(gòu)造函數(shù)存根
        // bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test).copy(Bitmap.Config.ARGB_8888, true);//設(shè)置位圖的寬高
        bitmap = Bitmap.createBitmap(1280, 1800, Bitmap.Config.ALPHA_8);//設(shè)置位圖的寬高
        canvas = new Canvas(bitmap);

        // 點和線paint
        paint = new Paint();//創(chuàng)建一個畫筆
        paint.setStyle(Paint.Style.STROKE);//設(shè)置非填充
        paint.setStrokeWidth(10);//筆寬5像素
        paint.setColor(Color.parseColor("#197AFF"));
        paint.setAntiAlias(true);//鋸齒不顯示
        paint.setDither(true);//設(shè)置圖像抖動處理
        paint.setStrokeJoin(Paint.Join.ROUND);//設(shè)置圖像的結(jié)合方式
        paint.setStrokeCap(Paint.Cap.ROUND);//設(shè)置畫筆為圓形樣式

        // 面paint
        surfacePaint = new Paint(Paint.DITHER_FLAG);//創(chuàng)建一個畫筆
        surfacePaint.setStyle(Paint.Style.FILL);//設(shè)置填充
        surfacePaint.setStrokeWidth(5);//筆寬5像素
        surfacePaint.setColor(Color.parseColor("#54197AFF"));
        surfacePaint.setAntiAlias(true);//鋸齒不顯示
        surfacePaint.setDither(true);//設(shè)置圖像抖動處理
        surfacePaint.setStrokeJoin(Paint.Join.ROUND);//設(shè)置圖像的結(jié)合方式
        surfacePaint.setStrokeCap(Paint.Cap.ROUND);//設(shè)置畫筆為圓形樣式

        // 文字paint
        textPaint = new Paint(Paint.DITHER_FLAG);//創(chuàng)建一個畫筆
        textPaint.setStyle(Paint.Style.FILL);//設(shè)置填充
        textPaint.setStrokeWidth(2);//筆寬5像素
        textPaint.setColor(Color.parseColor("#ffffffff"));
        textPaint.setTextSize(56f);
        textPaint.setAntiAlias(true);//鋸齒不顯示
        textPaint.setDither(true);//設(shè)置圖像抖動處理
        textPaint.setStrokeJoin(Paint.Join.ROUND);//設(shè)置圖像的結(jié)合方式
        textPaint.setStrokeCap(Paint.Cap.ROUND);//設(shè)置畫筆為圓形樣式
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmap, 0, 0, paint);
    }

    private boolean isDraw = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction() & MotionEvent.ACTION_MASK;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                float currentX = event.getX();
                float currentY = event.getY();
                if (isRestart) {
                    PointBean pointBean = new PointBean();
                    pointBean.setX(currentX);
                    pointBean.setY(currentY);
                    pointBeanList.add(pointBean);
                    pointBeanListCopy.add(pointBean);

                    if (pointBeanListCopy.size() < pointBeanList.size()) {// 說明是后退以后再點擊
                        pointBeanList.clear();
                        pointBeanList.addAll(pointBeanListCopy);
                    }

                    drawPointLines(pointBeanList);
                } else {// 點擊設(shè)置長度
                    // 創(chuàng)建線集合數(shù)據(jù)
                    lineBeansList.clear();
                    KLog.d("chenshichun", pointBeanList);
                    for (int i = 0; i < pointBeanList.size(); i++) {
                        LineBean lineBean = new LineBean();
                        if (i + 1 < pointBeanList.size()) {
                            lineBean.x = pointBeanList.get(i).getX();
                            lineBean.y = pointBeanList.get(i).getY();
                            lineBean.x1 = pointBeanList.get(i + 1).getX();
                            lineBean.y1 = pointBeanList.get(i + 1).getY();
                            lineBeansList.add(lineBean);
                        }
                    }

                    KLog.d("chenshichun", lineBeansList);
                    KLog.d("chenshichun", "currentX  " + currentX + "  currentY  " + currentY);
                    isDraw = false;
                    for (LineBean lineBean : lineBeansList) {
                        if (((currentX < lineBean.x && currentX > lineBean.x1)
                                || (currentX > lineBean.x && currentX < lineBean.x1)) &&
                                ((currentY < lineBean.y && currentY > lineBean.y1)
                                        || (currentY > lineBean.y && currentY < lineBean.y1))) {// 點擊的點所在的線
                            Toast.makeText(context, "ss", Toast.LENGTH_SHORT).show();
                            KLog.d("chenshichun", lineBean);
                            textPaint.setColor(getResources().getColor(R.color.white));
                            canvas.drawText("100", (lineBean.x + lineBean.x1) / 2, (lineBean.y + lineBean.y1) / 2, textPaint);
                            invalidate();
                            isDraw = true;
                        }
                    }

                    if (!isDraw) {
                        Toast.makeText(context, "請點擊對應(yīng)線", Toast.LENGTH_SHORT).show();
                    }

                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:

                break;
            case MotionEvent.ACTION_MOVE:
                break;

            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    /*
     * 畫點線面
     * */
    private boolean isRestart = true;
    Path path1;
    Path path2;

    private void drawPointLines(List<PointBean> beanList) {
        // 每次清除畫布
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        if (beanList.size() > 1) {
            path1 = new Path();// 線的顏色藍色
            path2 = new Path();// 面的顏色淡藍色

            //  判斷最后一個點和第一個點重合
            if (Math.abs(beanList.get(0).getX() - beanList.get(beanList.size() - 1).getX()) < 30
                    && Math.abs(beanList.get(0).getY() - beanList.get(beanList.size() - 1).getY()) < 30) {
                beanList.get(beanList.size() - 1).setX(beanList.get(0).getX());
                beanList.get(beanList.size() - 1).setY(beanList.get(0).getY());

                for (int i = 0; i < beanList.size(); i++) {
                    if (i == 0) {
                        path1.moveTo(beanList.get(i).getX(), beanList.get(i).getY());
                        path2.moveTo(beanList.get(i).getX(), beanList.get(i).getY());
                    } else {
                        path1.lineTo(beanList.get(i).getX(), beanList.get(i).getY());
                        path2.lineTo(beanList.get(i).getX(), beanList.get(i).getY());
                    }
                }
                path2.close();
                isRestart = false;
                surfacePaint.setStyle(Paint.Style.FILL);
            } else {
                for (int i = 0; i < beanList.size(); i++) {
                    if (i == 0) {
                        path1.moveTo(beanList.get(i).getX(), beanList.get(i).getY());
                    } else {
                        path1.lineTo(beanList.get(i).getX(), beanList.get(i).getY());
                    }
                }
            }
            canvas.drawPath(path1, paint);
            canvas.drawPath(path2, surfacePaint);
        } else {
            canvas.drawPoint(beanList.get(0).getX(), beanList.get(0).getY(), paint);
        }
        invalidate();//使繪畫動作生效
    }

    @Override

    public void onClick(View v) {


    }

    /*
     * 前進
     * */
    public void forward() {
        if (pointBeanListCopy.size() < pointBeanList.size()) {
            pointBeanListCopy.add(pointBeanList.get(pointBeanListCopy.size()));
            drawPointLines(pointBeanListCopy);
            invalidate();//使繪畫動作生效
        }
    }

    /*
     * 后退
     * */
    public void backOff() {
        isRestart = true;
        pointBeanListCopy.remove(pointBeanListCopy.size() - 1);
        drawPointLines(pointBeanListCopy);
        invalidate();//使繪畫動作生效
    }

    public void clear() {
        isRestart = true;
        pointBeanList.clear();
        pointBeanListCopy.clear();
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        invalidate();//使繪畫動作生效
    }

}


完整代碼:https://github.com/chenshichun/DrawCanvas-android
歡迎收藏點贊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末国瓮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子播瞳,更是在濱河造成了極大的恐慌掸刊,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赢乓,死亡現(xiàn)場離奇詭異忧侧,居然都是意外死亡石窑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門蚓炬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來松逊,“玉大人,你說我怎么就攤上這事肯夏【辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵驯击,是天一觀的道長烁兰。 經(jīng)常有香客問我,道長徊都,這世上最難降的妖魔是什么沪斟? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮暇矫,結(jié)果婚禮上主之,老公的妹妹穿的比我還像新娘。我一直安慰自己李根,他們只是感情好槽奕,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著房轿,像睡著了一般史翘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冀续,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天琼讽,我揣著相機與錄音,去河邊找鬼洪唐。 笑死钻蹬,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凭需。 我是一名探鬼主播问欠,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粒蜈!你這毒婦竟也來了顺献?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枯怖,失蹤者是張志新(化名)和其女友劉穎注整,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡肿轨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年寿冕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椒袍。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡驼唱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驹暑,到底是詐尸還是另有隱情玫恳,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布优俘,位于F島的核電站京办,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兼吓。R本人自食惡果不足惜臂港,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一森枪、第九天 我趴在偏房一處隱蔽的房頂上張望视搏。 院中可真熱鬧,春花似錦县袱、人聲如沸浑娜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筋遭。三九已至,卻和暖如春暴拄,著一層夾襖步出監(jiān)牢的瞬間漓滔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工乖篷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留响驴,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓撕蔼,卻偏偏與公主長得像豁鲤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鲸沮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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