自定義view實現涂鴉(畫板)功能 (一)

之前在csdn上發了一次,之后可能轉戰簡書了,為避免發發(二)的時候讓人不明所以,所以決定還是重發一次保證完整性
新手寫的比較low,主要目的還是讓自己長記性怕時間長忘記了,所以簡單記錄下
csdn自定義view實現涂鴉(畫板)功能

下面進入正文:

介紹

自定義view實現涂鴉功能,包括撤銷、恢復、重做、保存以及橡皮擦(在風格中實現)功能,小模塊包括畫筆顏色調整、畫筆尺寸調整、畫筆類型(包括正常畫筆以及橡皮擦功能),之后又陸續實現了畫圓、畫矩形以及畫箭頭的功能,這里我們先完成前面的需求

功能模塊

撤銷:
/** 
     * 撤銷 
     * 撤銷的核心思想就是將畫布清空, 
     * 將保存下來的Path路徑最后一個移除掉, 
     * 重新將路徑畫在畫布上面。 
     */  
    public void undo() {  
        if (savePath != null && savePath.size() > 0) {  
            DrawPath drawPath = savePath.get(savePath.size() - 1);  
            deletePath.add(drawPath);  
            savePath.remove(savePath.size() - 1);  
            redrawOnBitmap();  
        }  
    }  
重做:
/** 
     * 重做:重做的思路就更簡單了就是刪除所有已保存的路徑即可 
     * 但是我建議將刪除的路徑存入另一個集合可以用來恢復 
    */  
    public void redo() {  
        if (savePath != null && savePath.size() > 0) {  
            savePath.clear();  
            redrawOnBitmap();  
        }  
    }  
完成以上兩項功能的重要模塊:
private void redrawOnBitmap() {  
        initCanvas();  
        Iterator<DrawPath> iter = savePath.iterator();  
        while (iter.hasNext()) {  
            DrawPath drawPath = iter.next();  
            mCanvas.drawPath(drawPath.path, drawPath.paint);  
        }  
        invalidate();// 刷新  
    }  

原理:通過onTouch()方法完成,當down時創建path類,并記錄起點,up時獲取重點位置,并將該條路徑存入path實體類中,之后將該path存入一個集合savepath集合中。撤銷時,刪除最上層的path,重做則是刪除所有path即可。

恢復:
/** 
     * 恢復,恢復的核心就是將刪除的那條路徑重新添加到savapath中重新繪畫即可 
     */  
    public void recover() {  
        if (deletePath.size() > 0) {  
            //將刪除的路徑列表中的最后一個,也就是最頂端路徑取出(棧),并加入路徑保存列表中  
            DrawPath dp = deletePath.get(deletePath.size() - 1);  
            savePath.add(dp);  
            //將取出的路徑重繪在畫布上  
            mCanvas.drawPath(dp.path, dp.paint);  
            //將該路徑從刪除的路徑列表中去除  
            deletePath.remove(deletePath.size() - 1);  
            invalidate();  
        }  
    }  

原理很簡單存到本地即可,但是我們在存儲時可以記錄當前時間,以當前時間為圖片名字以示區別,注意:可以發廣播,不發的話可能造成用戶無法在圖庫中查看到(如果配置的是臨時路徑建議不添加)

樣式修改:畫板樣式,畫筆尺寸,畫筆顏色

//以下為樣式修改內容  
    //設置畫筆樣式  
    public void selectPaintStyle(int which) {  
        if (which == 0) {  
            currentStyle = 1;  
            setPaintStyle();  
        }  
        //當選擇的是橡皮擦時,設置顏色為白色  
        if (which == 1) {  
            currentStyle = 2;  
            setPaintStyle();  
            mPaint.setStrokeWidth(20);  
        }  
    }  
    //選擇畫筆大小  
    public void selectPaintSize(int which){  
        int size =Integer.parseInt(this.getResources().getStringArray(R.array.paintsize)[which]);  
        currentSize = size;  
        setPaintStyle();  
    }  
    //設置畫筆顏色  
    public void selectPaintColor(int which){  
        currentColor = paintColor[which];  
        setPaintStyle();  
    }  
//初始化畫筆樣式  
    private void setPaintStyle() {  
        mPaint = new Paint();  
        mPaint.setStyle(Paint.Style.STROKE);  
        mPaint.setStrokeJoin(Paint.Join.ROUND);// 設置外邊緣  
        mPaint.setStrokeCap(Paint.Cap.ROUND);// 形狀  
        mPaint.setAntiAlias(true);  
        mPaint.setDither(true);  
        if (currentStyle == 1) {//普通畫筆功能  
            mPaint.setStrokeWidth(currentSize);  
            mPaint.setColor(currentColor);  
        } else {//橡皮擦  
            mPaint.setAlpha(0);  
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//這兩個方法一起使用才能出現橡皮擦效果  
            mPaint.setColor(Color.TRANSPARENT);  
            mPaint.setStrokeWidth(50);  
            currentDrawGraphics = DRAW_PATH;//使用橡皮擦時默認用線的方式擦除  
        }  
    }

橡皮擦功能:
基本原理:橡皮擦就是用和畫布顏色一致顏色的畫筆在屏幕觸摸,簡接實現橡皮擦的功能。
1)初始化畫筆,并且設置畫筆的顏色為白色(這里其實要設置為畫布的顏色)。
2)設置畫筆的大小為合適的大小。
3)用一個變量記住橡皮擦的顏色,用于在其他操作后重新使用橡皮擦。

以上為簡易的橡皮擦主要使用白色來覆蓋,但當背景圖為一張照片時是不可行的,因為白色會很明顯的展示在背景圖上,而且需要注意的是:即使是將畫筆顏色變為透明色也是不可行的,綜上我們選擇用渲染模式來處理
這里選擇渲染模式Xfermode的DIS_IN,這樣我們處理后會發現出現黑色陰影邊框,效果實現了,但是bug非常明顯
之后選擇渲染模式的CLEAR這個模式會擦除所有像素點,但是發現是以黑色線條的形式去擦除的
通過STACK OVER FLOW網站超找到兩種解決辦法:
1.改變touch_move方法的path畫圖的相關方法,效果實現了但是對撤銷和重做造成了一定影響,最終沒有選用

private void touch_move(float x, float y) {  
        float dx = Math.abs(x - mX);  
        float dy = Math.abs(mY - y);  
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
            // 從x1,y1到x2,y2畫一條貝塞爾曲線,更平滑(直接用mPath.lineTo也可以)  
           // mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);  
            mPath.lineTo(mX, mY);  
            mCanvas.drawPath(mPath, mPaint);  
            //將一條完整的路徑保存下來(相當于入棧操作)  
            savePath.add(dp);  
            mPath.reset();  
            mPath.moveTo(mX, mY);  
            mX = x;  
            mY = y;  
        }  
    }  
    private void touch_up() {  
        mPath = null;// 重新置空  
        //mPath.reset();  
    } 

2.最終發現只需要設置默認type就能解決該問題

setLayerType(LAYER_TYPE_SOFTWARE,null);//設置默認樣式,去除dis-in的黑色方框以及clear模式的黑線效果

橡皮擦相關代碼:

if (currentStyle == 1) {//正常畫筆  
            mPaint.setStrokeWidth(currentSize);  
            mPaint.setColor(currentColor);  
        } else {//橡皮擦  
            mPaint.setAlpha(0);  
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));  
            mPaint.setColor(Color.TRANSPARENT);  
            mPaint.setStrokeWidth(50);  
        }  

注意 mPaint.setAlpha(0);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));兩者搭配使用

設置畫筆大小的功能:
1)初始化畫筆。
2)設置畫筆的大小為所選擇的大小。
3)用一個變量記住當前畫筆的大小,用于在進行其他操作后還保持之前設置的畫筆大小。

設置畫筆顏色的功能:
1)初始化畫筆。
2)設置畫筆的顏色為所選擇的顏色。
3)用一個變量記住當前畫筆的顏色,用于在進行其他操作后還保持之前設置的畫筆顏色。

以下為完整代碼:
效果:

20160527170522184.png

自定義TuyaView:

/** 
 *  
 * View實現涂鴉、撤銷以及重做功能 
 */  
import android.content.Context;  
import android.content.Intent;  
import android.graphics.Bitmap;  
import android.graphics.Bitmap.CompressFormat;  
import android.graphics.BitmapFactory;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Matrix;  
import android.graphics.Paint;  
import android.graphics.Path;  
import android.graphics.PorterDuff;  
import android.graphics.PorterDuffXfermode;  
import android.net.Uri;  
import android.os.Environment;  
import android.util.Log;  
import android.view.MotionEvent;  
import android.view.View;  
import java.io.File;  
import java.io.FileOutputStream;  
import java.text.SimpleDateFormat;  
import java.util.ArrayList;  
import java.util.Date;  
import java.util.Iterator;  
import java.util.List;  
public class TuyaView extends View {  
    private Context context;  
    private Bitmap mBitmap;  
    private Canvas mCanvas;  
    private Path mPath;  
    private Paint mBitmapPaint;// 畫布的畫筆  
    private Paint mPaint;// 真實的畫筆  
    private float mX, mY;// 臨時點坐標  
    private static final float TOUCH_TOLERANCE = 4;  
    // 保存Path路徑的集合  
    private static List<DrawPath> savePath;  
    // 保存已刪除Path路徑的集合  
    private static List<DrawPath> deletePath;  
    // 記錄Path路徑的對象  
    private DrawPath dp;  
    private int screenWidth, screenHeight;  
    private int currentColor = Color.RED;  
    private int currentSize = 5;  
    private int currentStyle = 1;  
    private int[] paintColor;//顏色集合  
    private class DrawPath {  
        public Path path;// 路徑  
        public Paint paint;// 畫筆  
    }  
    public TuyaView(Context context, int w, int h) {  
        super(context);  
        this.context = context;  
        screenWidth = w;  
        screenHeight = h;  
        paintColor = new int[]{  
                Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.BLACK, Color.GRAY, Color.CYAN  
        };  
        setLayerType(LAYER_TYPE_SOFTWARE,null);//設置默認樣式,去除dis-in的黑色方框以及clear模式的黑線效果  
        initCanvas();  
        savePath = new ArrayList<DrawPath>();  
        deletePath = new ArrayList<DrawPath>();  
    }  
    public void initCanvas() {  
        setPaintStyle();  
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);  
        //畫布大小  
        mBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);  
        mBitmap.eraseColor(Color.argb(0, 0, 0, 0));  
        mCanvas = new Canvas(mBitmap);  //所有mCanvas畫的東西都被保存在了mBitmap中  
        mCanvas.drawColor(Color.TRANSPARENT);  
    }  
    //初始化畫筆樣式  
    private void setPaintStyle() {  
        mPaint = new Paint();  
        mPaint.setStyle(Paint.Style.STROKE);  
        mPaint.setStrokeJoin(Paint.Join.ROUND);// 設置外邊緣  
        mPaint.setStrokeCap(Paint.Cap.ROUND);// 形狀  
        mPaint.setAntiAlias(true);  
        mPaint.setDither(true);  
        if (currentStyle == 1) {  
            mPaint.setStrokeWidth(currentSize);  
            mPaint.setColor(currentColor);  
        } else {//橡皮擦  
            mPaint.setAlpha(0);  
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));  
            mPaint.setColor(Color.TRANSPARENT);  
            mPaint.setStrokeWidth(50);  
        }  
    }  
    @Override  
    public void onDraw(Canvas canvas) {  
        //canvas.drawColor(0xFFAAAAAA);  
        // 將前面已經畫過得顯示出來  
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);  
        if (mPath != null) {  
            // 實時的顯示  
            canvas.drawPath(mPath, mPaint);  
        }  
    }  
    private void touch_start(float x, float y) {  
        mPath.moveTo(x, y);  
        mX = x;  
        mY = y;  
    }  
    private void touch_move(float x, float y) {  
        float dx = Math.abs(x - mX);  
        float dy = Math.abs(mY - y);  
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
            // 從x1,y1到x2,y2畫一條貝塞爾曲線,更平滑(直接用mPath.lineTo也可以)  
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);  
            //mPath.lineTo(mX,mY);  
            mX = x;  
            mY = y;  
        }  
    }  
    private void touch_up() {  
        mPath.lineTo(mX, mY);  
        mCanvas.drawPath(mPath, mPaint);  
        //將一條完整的路徑保存下來  
        savePath.add(dp);  
        mPath = null;// 重新置空  
    }  
    /** 
     * 撤銷 
     * 撤銷的核心思想就是將畫布清空, 
     * 將保存下來的Path路徑最后一個移除掉, 
     * 重新將路徑畫在畫布上面。 
     */  
    public void undo() {  
        if (savePath != null && savePath.size() > 0) {  
            DrawPath drawPath = savePath.get(savePath.size() - 1);  
            deletePath.add(drawPath);  
            savePath.remove(savePath.size() - 1);  
            redrawOnBitmap();  
        }  
    }  
    /** 
     * 重做 
     */  
    public void redo() {  
        if (savePath != null && savePath.size() > 0) {  
            savePath.clear();  
            redrawOnBitmap();  
        }  
    }  
    private void redrawOnBitmap() {  
        /*mBitmap = Bitmap.createBitmap(screenWidth, screenHeight, 
                Bitmap.Config.RGB_565); 
        mCanvas.setBitmap(mBitmap);// 重新設置畫布,相當于清空畫布*/  
        initCanvas();  
        Iterator<DrawPath> iter = savePath.iterator();  
        while (iter.hasNext()) {  
            DrawPath drawPath = iter.next();  
            mCanvas.drawPath(drawPath.path, drawPath.paint);  
        }  
        invalidate();// 刷新  
    }  
    /** 
     * 恢復,恢復的核心就是將刪除的那條路徑重新添加到savapath中重新繪畫即可 
     */  
    public void recover() {  
        if (deletePath.size() > 0) {  
            //將刪除的路徑列表中的最后一個,也就是最頂端路徑取出(棧),并加入路徑保存列表中  
            DrawPath dp = deletePath.get(deletePath.size() - 1);  
            savePath.add(dp);  
            //將取出的路徑重繪在畫布上  
            mCanvas.drawPath(dp.path, dp.paint);  
            //將該路徑從刪除的路徑列表中去除  
            deletePath.remove(deletePath.size() - 1);  
            invalidate();  
        }  
    }  
    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
        float x = event.getX();  
        float y = event.getY();  
        switch (event.getAction()) {  
            case MotionEvent.ACTION_DOWN:  
                // 每次down下去重新new一個Path  
                mPath = new Path();  
                //每一次記錄的路徑對象是不一樣的  
                dp = new DrawPath();  
                dp.path = mPath;  
                dp.paint = mPaint;  
                touch_start(x, y);  
                invalidate();  
                break;  
            case MotionEvent.ACTION_MOVE:  
                touch_move(x, y);  
                invalidate();  
                break;  
            case MotionEvent.ACTION_UP:  
                touch_up();  
                invalidate();  
                break;  
        }  
        return true;  
    }  
    //保存到sd卡  
    public void saveToSDCard() {  
        //獲得系統當前時間,并以該時間作為文件名  
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");  
        Date curDate = new Date(System.currentTimeMillis());//獲取當前時間  
        String str = formatter.format(curDate) + "paint.png";  
        File file = new File("sdcard/" + str);  
        FileOutputStream fos = null;  
        try {  
            fos = new FileOutputStream(file);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        mBitmap.compress(CompressFormat.PNG, 100, fos);  
        //發送Sd卡的就緒廣播,要不然在手機圖庫中不存在  
        Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED);  
        intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));  
        context.sendBroadcast(intent);  
        Log.e("TAG", "圖片已保存");  
    }  
    //以下為樣式修改內容  
    //設置畫筆樣式  
    public void selectPaintStyle(int which) {  
        if (which == 0) {  
            currentStyle = 1;  
            setPaintStyle();  
        }  
        //當選擇的是橡皮擦時,設置顏色為白色  
        if (which == 1) {  
            currentStyle = 2;  
            setPaintStyle();  
        }  
    }  
    //選擇畫筆大小  
    public void selectPaintSize(int which) {  
        //int size = Integer.parseInt(this.getResources().getStringArray(R.array.paintsize)[which]);  
        currentSize = which;  
        setPaintStyle();  
    }  
    //設置畫筆顏色  
    public void selectPaintColor(int which) {  
        currentColor = paintColor[which];  
        setPaintStyle();  
    }  
}  

MainActivity:

package com.banhai.paintboard;  
import android.content.DialogInterface;  
import android.support.v7.app.AlertDialog;  
import android.support.v7.app.AppCompatActivity;  
import android.os.Bundle;  
import android.view.Display;  
import android.view.View;  
import android.view.Window;  
import android.widget.Button;  
import android.widget.FrameLayout;  
import android.widget.SeekBar;  
import android.widget.Toast;  
public class MainActivity extends AppCompatActivity implements View.OnClickListener{  
    private FrameLayout frameLayout;  
    private Button btn_undo;  
    private Button btn_redo;  
    private Button btn_save;  
    private Button btn_recover;  
    private TuyaView tuyaView;//自定義涂鴉板  
    private Button btn_paintcolor;  
    private Button btn_paintsize;  
    private Button btn_paintstyle;  
    private SeekBar sb_size;  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        requestWindowFeature(Window.FEATURE_NO_TITLE);  
        setContentView(R.layout.activity_main);  
        initView();  
        initData();  
        initListener();  
    }  
    private void initView() {  
        frameLayout = (FrameLayout) findViewById(R.id.fl_boardcontainer);  
        btn_undo = (Button) findViewById(R.id.btn_last);  
        btn_redo = (Button) findViewById(R.id.btn_redo);  
        btn_save = (Button) findViewById(R.id.btn_savesd);  
        btn_recover = (Button) findViewById(R.id.btn_recover);  
        btn_paintcolor = (Button) findViewById(R.id.btn_paintcolor);  
        btn_paintsize = (Button) findViewById(R.id.btn_paintsize);  
        btn_paintstyle = (Button) findViewById(R.id.btn_paintstyle);  
        sb_size = (SeekBar) findViewById(R.id.sb_size);  
    }  
    private void initData() {  
        //雖然此時獲取的是屏幕寬高,但是我們可以通過控制framlayout來實現控制涂鴉板大小  
        Display defaultDisplay = getWindowManager().getDefaultDisplay();  
        int screenWidth = defaultDisplay.getWidth();  
        int screenHeight = defaultDisplay.getHeight();  
        tuyaView = new TuyaView(this,screenWidth,screenHeight);  
        frameLayout.addView(tuyaView);  
        tuyaView.requestFocus();  
        tuyaView.selectPaintSize(sb_size.getProgress());  
    }  
    private void initListener() {  
        btn_undo.setOnClickListener(this);  
        btn_redo.setOnClickListener(this);  
        btn_save.setOnClickListener(this);  
        btn_recover.setOnClickListener(this);  
        btn_paintcolor.setOnClickListener(this);  
        btn_paintsize.setOnClickListener(this);  
        btn_paintstyle.setOnClickListener(this);  
        sb_size.setOnSeekBarChangeListener(new MySeekChangeListener());  
    }  
     class MySeekChangeListener implements SeekBar.OnSeekBarChangeListener {  
        @Override  
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {  
            tuyaView.selectPaintSize(seekBar.getProgress());  
            //Toast.makeText(MainActivity.this,"當前畫筆尺寸為"+seekBar.getProgress(),Toast.LENGTH_SHORT ).show();  
        }  
         @Override  
         public void onStartTrackingTouch(SeekBar seekBar) {  
             tuyaView.selectPaintSize(seekBar.getProgress());  
             //Toast.makeText(MainActivity.this,"當前畫筆尺寸為"+seekBar.getProgress(),Toast.LENGTH_SHORT ).show();  
         }  
         @Override  
        public void onStopTrackingTouch(SeekBar seekBar) {}  
    }  
    @Override  
    public void onClick(View v) {  
        switch (v.getId()){  
            case R.id.btn_last://撤銷  
                tuyaView.undo();  
                break;  
            case R.id.btn_redo://重做  
                tuyaView.redo();  
                break;  
            case R.id.btn_recover://恢  
                tuyaView.recover();  
                break;  
            case R.id.btn_savesd://保存  
                tuyaView.saveToSDCard();  
                break;  
            case R.id.btn_paintcolor:  
                sb_size.setVisibility(View.GONE);  
                showPaintColorDialog(v);  
                break;  
            case R.id.btn_paintsize:  
                sb_size.setVisibility(View.VISIBLE);  
                break;  
            case R.id.btn_paintstyle:  
                sb_size.setVisibility(View.GONE);  
                showMoreDialog(v);  
                break;  
        }  
    }  
    private int select_paint_color_index = 0;  
    private int select_paint_style_index = 0;  
    //private int select_paint_size_index = 0;  
    public void showPaintColorDialog(View parent){  
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);  
        alertDialogBuilder.setTitle("選擇畫筆顏色:");  
        alertDialogBuilder.setSingleChoiceItems(R.array.paintcolor, select_paint_color_index, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  
                select_paint_color_index = which;  
                tuyaView.selectPaintColor(which);  
                dialog.dismiss();  
            }  
        });  
        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  
                dialog.dismiss();  
            }  
        });  
        alertDialogBuilder.create().show();  
    }  
/* 
//彈出畫筆大小選項對話框 
    public void showPaintSizeDialog(View parent){ 
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this); 
        alertDialogBuilder.setTitle("選擇畫筆大小:"); 
        alertDialogBuilder.setSingleChoiceItems(R.array.paintsize, select_paint_size_index, new DialogInterface.OnClickListener() { 
            @Override 
            public void onClick(DialogInterface dialog, int which) { 
                select_paint_size_index = which; 
                tuyaView.selectPaintSize(which); 
                dialog.dismiss(); 
            } 
        }); 
        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() { 
            @Override 
            public void onClick(DialogInterface dialog, int which) { 
                dialog.dismiss(); 
            } 
        }); 
        alertDialogBuilder.create().show(); 
    } 
*/  
//彈出選擇畫筆或橡皮擦的對話框  
    public void showMoreDialog(View parent){  
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);  
        alertDialogBuilder.setTitle("選擇畫筆或橡皮擦:");  
        alertDialogBuilder.setSingleChoiceItems(R.array.paintstyle, select_paint_style_index, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  
                select_paint_style_index = which;  
                tuyaView.selectPaintStyle(which);  
                dialog.dismiss();  
            }  
        });  
        alertDialogBuilder.setNegativeButton("取消", new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  
                dialog.dismiss();  
            }  
        });  
        alertDialogBuilder.create().show();  
    }  
}  
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,173評論 4 61
  • 親聞私耳語, 仙請赴天霆。 惶恐閑云客, 疑為在幔亭。 文/閑云 2017.03.02
    2b4c67af34a7閱讀 149評論 1 0
  • “我昨天晚上夢到你了。” 我們很久不聯系了。我,她和另外兩個女孩是小學很有名的“時代姐妹花”。她是林蕭,雯是顧里,...
    老煙嗓和小奶音YE閱讀 245評論 0 0
  • 浣溪沙 · 題青花瓷雕“采茶”(步客家葦笛韻) 頂笠未將容玉遮,身姿婀娜綻青花。手提巧籃采春芽。 側耳肩頭飄蝶影,...
    補缺樓丨胡德棒閱讀 264評論 2 4
  • javascript中apply、call和bind的區別 在JS中,這三者都是用來改變函數的this對象的指向的...
    lyzaijs閱讀 8,328評論 1 23