自定義View實現(xiàn)圓形水波進度條

每次聽到某大牛談論自定義View双絮,頓時敬佩之心浴麻,如滔滔江水連綿不絕,心想我什么時候能有如此境界囤攀,好了软免,心動不如行動,于是我開始了自定義View之路抚岗,雖然過程有坎坷或杠,但是結(jié)果我還是挺滿意的。我知道大牛還遙不可及宣蔚,但是我已使出洪荒之力向抢。此篇博客記錄本人初入自定義View之路。

既然是初出茅廬胚委,自然是按部就班的進行,先來一張效果圖


這里寫圖片描述

項目源碼【傳送門】

自定義屬性

自定義屬性挟鸠,就是在資源文件夾下values目錄中創(chuàng)建一個attrs.xml文件,
文件結(jié)構(gòu)如下所示亩冬,atrr標簽就是我們要自定義的一些屬性艘希,name就是自定義屬性的名字,那么format是做什么的呢硅急?

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="">
        <attr name="centerText" format=""></attr>
        <attr name=" ">
            <enum name=""  value=" "></enum>
            <enum name="" value=" "></enum>
        </attr>
    </declare-styleable>
</resources>

format是屬性對應的值的類型覆享,有十個值

  • enm 枚舉類型,例 android:orientation="vertical" 此值有horizontal营袜,和 vertical
  • dimension 尺寸值
  • color 顏色值撒顿,例 android:textColor = "#00FF00"
  • boolean 布爾值,true or false
  • flag 位或運算
  • float 浮點型
  • fraction 百分數(shù)荚板,
  • reference 參考某一資源ID,例 android:background = "@drawable/ic_launcher"
  • string 字符串類型
  • integer 整型值

知道了這些值得含義凤壁,就可以自定義我們自己的屬性了吩屹,對于這個進度條,我們可以自定義圓的半徑拧抖,顏色煤搜,和圓中心文本的大小,顏色唧席,文本擦盾,最后attrs.xml文件為

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomBallView">
        <attr name="centerText" format="string"></attr>
        <attr name="centerTextSize" format="dimension"></attr>
        <attr name="centerTextColor" format="color"></attr>
        <attr name="ballColor" format="color"></attr>
        <attr name="ballRadius" format="dimension"></attr>
    </declare-styleable>
</resources>

布局文件配置相關(guān)內(nèi)容

在布局文件要配置我們自定義的屬性,首先要自定義命名空間袱吆,

這里寫圖片描述

如上圖厌衙,如果在as中命名空間寫成http://schemas.android.com/apk/res/包名 此時as會報錯距淫,這是gradle造成的绞绒,在eclipse中如果自定義的屬性 是不能用res-auto的 必須得替換成你自定義view所屬的包名,如果你在恰好使用的自定義屬性被做成了lib 那就只能使用res-auto了榕暇,而在android-studio里蓬衡,無論你是自己寫自定義view 還是引用的lib里的自定義的view 都只能使用res-auto這個寫法。以前那個包名的寫法 在android-studio里是被廢棄無法使用的
所以配置后的布局文件如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:customBallView="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.xh.customball.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:text="Hello World!" />

    <com.example.xh.customball.CustomBall
        android:background="@color/colorPrimary"
        android:layout_centerInParent="true"
        android:layout_margin="10dp"
        customBallView:centerText="30%"
        customBallView:centerTextSize="28dp"
        customBallView:centerTextColor="#000000"
        customBallView:ballColor="@color/colorAccent"
        customBallView:ballRadius="30dp"
        android:layout_width="260dp"
        android:layout_height="260dp">
    </com.example.xh.customball.CustomBall>
</LinearLayout>

自定義控件

有了上邊的操作彤枢,接下來就開始到了真正自定義控件的時候了狰晚,創(chuàng)建一個CustomBall類繼承View類,先看構(gòu)造方法缴啡,我們寫成構(gòu)造方法最終調(diào)用三個參數(shù)的構(gòu)造方法壁晒,獲取自定義屬性的值及初始化工作就在三個參數(shù)構(gòu)造方法中進行。下面我先先來繪制一個圓业栅,文字畫在圓心試試手秒咐,效果如圖


這里寫圖片描述

當然繪制這個圖形,首先獲取我們自定義屬性值碘裕,可通過下面獲取屬性值
注意通過TypedArray 獲取屬性值后要執(zhí)行typedArray.recycle();回收內(nèi)存携取,防止內(nèi)存泄漏。

/**
* 獲取自定義屬性
*/
TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.customBallView);
        centerText=typedArray.getString(R.styleable.customBallView_centerText);
        Log.e("TAG","centerText"+centerText);
        centerTextSize=typedArray.getDimension(R.styleable.customBallView_centerTextSize,24f);
        centerTextColor=typedArray.getColor(R.styleable.customBallView_centerTextColor,0xFFFFFF);
        ballColor=typedArray.getColor(R.styleable.customBallView_ballColor,0xFF4081);
        radius=typedArray.getDimension(R.styleable.customBallView_ballRadius,260f);
        typedArray.recycle();

初始化畫筆

    /**
     * 初始化畫筆
     */
    private void initPaint() {
        roundPaint = new Paint();
        roundPaint.setColor(ballColor);
        roundPaint.setAntiAlias(true);//抗鋸齒
        fontPaint = new Paint();
        fontPaint.setTextSize(centerTextSize);
        fontPaint.setColor(centerTextColor);
        fontPaint.setAntiAlias(true);
        fontPaint.setFakeBoldText(true);//粗體

    }

接下來我們先畫一個圓帮孔,先通過下面方法獲取空間本身的寬和高雷滋,然后調(diào)用canvas.drawCircle(width/2, height/2, radius, roundPaint);畫圓,在原點設(shè)置為控件中心位置文兢,即點(width/2, height/2)晤斩,半徑為radius,畫筆roundPaint姆坚,接下來繪制文字澳泵,將位子繪制在圓的中心。

        width = getWidth() ;
        height = getHeight();

如果我們通過canvas.drawText(centerText, width/2, height/2, fontPaint);繪制文字的話旷偿,發(fā)現(xiàn)文字并不是在中心位置烹俗,那么我們可以做一下調(diào)整爆侣,canvas.drawText(centerText, width/2, height/2, fontPaint);先通過float textWidth = fontPaint.measureText(centerText);獲取文字的寬度,canvas.drawText(centerText, width/2-textWidth /2, height/2, fontPaint);此時文字依然不在中心幢妄,那么此時我們研究一下文字到底是怎么繪制的兔仰,為什么坐標試試中心了,繪制出來的效果依然有偏差呢蕉鸳。

要關(guān)注文字繪制的話乎赴,F(xiàn)ontMetrics這個類是必須要知道的因為它的作用是測量文字,它里面呢就定義了top,ascent,descent,bottom,leading五個成員變量其他什么也沒有潮尝。先看源碼

public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }

這個類是Paint的靜態(tài)內(nèi)部類榕吼,通過注釋我們就知道了每個變量的含義,為了更生動的理解這幾個變量含義勉失,我們通過下面的一張圖來分別解釋每個變量的含義

這里寫圖片描述
  • Baseline(基線) 在Android中羹蚣,文字的繪制都是從Baseline處開始的
  • ascent(上坡度)Baseline往上至文字“最高處”的距離我們稱之為ascent,
  • descent(下坡度)Baseline往下至文字“最低處”的距離我們稱之為descent(下坡度)
  • leading(行間距)表示上一行文字的descent到該行文字的ascent之間的距離
  • top 對于ascent上面還有一部分內(nèi)邊距乱凿,內(nèi)邊距加上ascent即為top值
  • bottom descent和內(nèi)邊距的加上descent距離

值得注意的一點顽素,Baseline上方的值為負,下方的值為正如下圖文字30%的ascent,descent徒蟆,top,bottom胁出。

這里寫圖片描述

通過上面的分析,我們就得出了將文本繪制中心的代碼如下

//測量文字的寬度
float textWidth = fontPaint.measureText(centerText);
        float x = width / 2 - textWidth / 2;
        Paint.FontMetrics fontMetrics = fontPaint.getFontMetrics();
        float dy = -(fontMetrics.descent + fontMetrics.ascent) / 2;
        float y = height / 2  + dy;
        canvas.drawText(centerText, x, y, fontPaint);

至此這個簡單自定義的View基本實現(xiàn)段审,此時我改了布局配置文件為寬高

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

或者

        android:layout_width="match_parent"
        android:layout_height="match_parent"

Oh my God全蝶,為什么效果是一樣的啊,此時再回到自定義的類寺枉,我們發(fā)現(xiàn)我們沒有實現(xiàn)onMeasure里面測量的代碼抑淫,接下來讓我們實現(xiàn)onMeasure操作,如下

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //測量模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //測量規(guī)格大小
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;
        if (widthMode == MeasureSpec.EXACTLY) {
            width=widthSize;
        } else if (widthMode == MeasureSpec.AT_MOST) {
            width=(int)Math.min(widthSize,radius*2);
        } else {

            width=windowWidth;
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            height=heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            height=(int)Math.min(heightSize,radius*2);
        } else {
            height=windowHeight;
        }
        setMeasuredDimension(width,height);
    }

測量主要依靠MeasureSpec型凳,MeasureSpec(測量規(guī)格)是一個32位的int數(shù)據(jù).其中高2位代表SpecMode即某種測量模式,低32位為SpecSize代表在該模式下的規(guī)格大小丈冬,測量模式有三種

  • EXACTLY 確切的,在布局文件中設(shè)置的寬高是固定的甘畅,此時測量大小就是我們設(shè)置的寬高
  • AT_MOST 至多埂蕊,不能超出
  • UNSPECIFIED 未指定

MeasureSpec的詳細解釋

通過上面的分析,繪制此圖形的完整代碼為 點擊查看

控件升級

上面我們已經(jīng)實現(xiàn)了圓形和文本的繪制疏唾,那么接下來蓄氧,我們先開始實現(xiàn)中心新進度的更新繪制。先看效果圖

這里寫圖片描述

通過效果圖槐脏,我們看到實現(xiàn)此效果就是不斷的更新進度值喉童,然后重繪,顿天,那么我們只需開啟一個線程實現(xiàn)更新進度值堂氯,為了更好的控制我們再加點擊事件蔑担,當單機時開始增大進度,雙擊時暫停進度咽白,并彈出Snackbar啤握,其中有一個重置按鈕,點擊重置時將進度設(shè)置為0晶框,重繪界面排抬。

  • 響應點擊事件
    因為要實現(xiàn)雙擊事件,我們可以直接用GestureDetector(手勢檢測)授段,通過這個類我們可以識別很多的手勢蹲蒲,主要是通過他的onTouchEvent(event)方法完成了不同手勢的識別GestureDetector里有一個內(nèi)部類 SimpleOnGestureListener。SimpleOnGestureListener類是GestureDetector提供給我們的一個更方便的響應不同手勢的類侵贵,這個類實現(xiàn)了上述兩個接口(OnGestureListener, OnDoubleTapListener届搁,但是所有的方法體都是空的),該類是static class模燥,也就是說它實際上是一個外部類咖祭。程序員可以在外部繼承這個類,重寫里面的手勢處理方法
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {
//單擊抬起
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
//長按
        public void onLongPress(MotionEvent e) {
        }
//滾動
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            return false;
        }
//快速滑動
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            return false;
        }
//
        public void onShowPress(MotionEvent e) {
        }

        public boolean onDown(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }

        public boolean onSingleTapConfirmed(MotionEvent e) {
            return false;
        }

        public boolean onContextClick(MotionEvent e) {
            return false;
        }
    }

下面是我們自定繼承SimpleOnGestureListener蔫骂,由于我們只要響應單擊和雙擊事件,那么我們只需要重寫onDoubleTap雙擊()牺汤,onSingleTapConfirmed(單擊)方法即可辽旋,

    public class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            getHandler().removeCallbacks(singleTapThread);
            singleTapThread=null;
            Snackbar.make(CustomBall.this, "暫停進度,是否重置進度檐迟?", Snackbar.LENGTH_LONG).setAction("重置", new OnClickListener() {
                @Override
                public void onClick(View v) {
                    currentProgress=0;
                    invalidate();
                }
            }).show();
            return super.onDoubleTap(e);
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Snackbar.make(CustomBall.this, "單機了", Snackbar.LENGTH_LONG).setAction("Action", null).show();
            startProgressAnimation();
            return super.onSingleTapConfirmed(e);
        }
    }

當點擊時Snackbar做個提醒單擊了View,然后調(diào)用startProgressAnimation()方法初始化一個線程补胚,通過postDelayed將線程加入的消息隊列,延遲100ms執(zhí)行追迟,通過singleTapThread == null判斷條件溶其,避免過多的創(chuàng)建對象

    private void startProgressAnimation() {
        if (singleTapThread == null) {
            singleTapThread = new SingleTapThread();
            getHandler().postDelayed(singleTapThread, 100);
        }
    }

我們將SingleTapThread 實現(xiàn)Runnable接口,在run方法里書寫我們的處理邏輯敦间,其實很簡單瓶逃,先判斷當前進度值是不是大于最大進度(100),如果小于最大的值廓块,我們就將currentProgress(當前進度值)加1的操作厢绝,然后調(diào)用invalidate()方法重繪界面,之后還需要再次將線程加入消息隊列带猴,依然延遲100ms執(zhí)行昔汉。對于當如果當前進度已經(jīng)加載到100%,此時我們將此線程從消息隊列移除。

    private class SingleTapThread implements Runnable {
        @Override
        public void run() {
            if (currentProgress < maxProgress) {
                currentProgress++;
                invalidate();
                getHandler().postDelayed(singleTapThread, 100);

            } else {
                getHandler().removeCallbacks(singleTapThread);
            }
        }
    }

接下來還需要注冊事件拴清,我們可以在onDraw()方法中通過GestureDetector的構(gòu)造方法可以將自定義的MyGestureDetector對象傳遞進去靶病,然后通setOnTouchListener設(shè)置監(jiān)聽器会通,這樣GestureDetector能處理不同的手勢了

      if (detector==null){
            detector = new GestureDetector(new MyGestureDetector());
            setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return detector.onTouchEvent(event);
                }
            });

        }

還有最重要的一點是,View默認是不可點擊的娄周,所以我們需要 setClickable(true)設(shè)置View可點擊的渴语,OK,到這里我們就完成的中心進度值得更新昆咽,接下來就開始繪制里面的波浪形狀驾凶,效果圖如下


這里寫圖片描述

實現(xiàn)水波浪效果

水波紋效果是通過二階貝塞爾曲線實現(xiàn)的,先簡單看下什么是貝塞爾曲線

在數(shù)學的數(shù)值分析領(lǐng)域中掷酗,貝塞爾曲線(英語:Bézier curve)是電腦圖形學中相當重要的參數(shù)曲線调违。更高維度的廣泛化貝塞爾曲線就稱作貝塞爾曲面,其中貝塞爾三角是一種特殊的實例泻轰。
貝塞爾曲線于1962年技肩,由法國工程師皮埃爾·貝塞爾(Pierre Bézier)所廣泛發(fā)表,他運用貝塞爾曲線來為汽車的主體進行設(shè)計浮声。貝塞爾曲線最初由Paul de Casteljau于1959年運用de Casteljau算法開發(fā)虚婿,以穩(wěn)定數(shù)值的方法求出貝塞爾曲線 - - - - -維基百科

  • 線性貝塞爾曲線
    給定點P0、P1泳挥,線性貝塞爾曲線只是一條兩點之間的直線然痊。這條線由下式給出:
這里寫圖片描述

繪制效果為

這里寫圖片描述
  • 二次方貝塞爾曲線
    二次方貝塞爾曲線的路徑由給定點P0、P1屉符、P2的函數(shù)B(t)追蹤:
這里寫圖片描述
這里寫圖片描述
  • 三次方貝塞爾曲線
    P0剧浸、P1、P2矗钟、P3四個點在平面或在三維空間中定義了三次方貝塞爾曲線唆香。曲線起始于P0走向P1,并從P2的方向來到P3吨艇。一般不會經(jīng)過P1或P2躬它;這兩個點只是在那里提供方向資訊。P0和P1之間的間距东涡,決定了曲線在轉(zhuǎn)而趨進P2之前冯吓,走向P1方向的“長度有多長”。
    曲線的參數(shù)形式為:


    這里寫圖片描述

當然貝塞爾曲線是一個很復雜的東西软啼,他可以延伸N階貝塞爾曲線桑谍,如果想要真正搞明白,想自定義比較復雜或者比較酷炫的動畫祸挪,那高等數(shù)學知識必須要搞明白锣披,很多時候,我們只需要了解二次貝塞爾曲線就可以了,或者說雹仿,即使貝塞爾曲線不是那么熟悉增热,也不用怕,android API 封裝了常用的貝塞爾曲線胧辽,我們只需要傳入坐標就可以實現(xiàn)很多動畫峻仇。

首先我們需要初始化貝塞爾曲線區(qū)域的畫筆設(shè)置。其中重要的一點就是setXfermode()方法邑商,此方法可以設(shè)置與其他繪制圖形的交集摄咆,合集,補集等運算,在這個項目中人断,我們使用了交集(繪制貝塞爾曲線區(qū)域和圓區(qū)域的交集)

       progressPaint = new Paint();
        progressPaint.setAntiAlias(true);
        progressPaint.setColor(progressColor);
        //取兩層繪制交集吭从。顯示上層
        progressPaint.setXfermode(new                 PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

初始化畫筆后,就開始繪制我們的圖形恶迈,先初始化一個
寬和高都為radius * 2的正方形畫布作為緩沖區(qū)畫布涩金,我們可以先在緩沖區(qū)畫布繪制,繪制完成后一次再繪制到畫布上暇仲。

        bitmap = Bitmap.createBitmap((int) radius * 2, (int) radius * 2, Bitmap.Config.ARGB_8888);

        bitmapCanvas = new Canvas(bitmap);

然后繪制圓心(width / 2, height / 2)半徑為radius的圓

bitmapCanvas.drawCircle(width / 2, height / 2, radius, roundPaint);

水波從圓的最下方開始(進度為0),到最上方(進度最大值maxProgress)結(jié)束步做,那么我們需要根據(jù)當前進度值動態(tài)計算水波的高度

 float y = (1 - (float) currentProgress / maxProgress) * radius * 2
這里寫圖片描述

如圖,我們就可以先將path.lineTo將每個點連起來,可以先從(width,y)繪制奈附,那么需要調(diào)用path.moveTo(width, y);方法將操作點移動到該坐標上全度,接下下就開始依次連接其余三個點(width,height),(0,height),(0,y)。由于我們之前畫筆設(shè)置的是取交集(progressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)))桅狠,所以此時會繪制與圓相交的部分讼载,也就是圓內(nèi)的部分。

這里寫圖片描述

下面就是繪制貝塞爾曲線

            path.rQuadTo(space, -d, space * 2, 0);
            path.rQuadTo(space, d, space * 2, 0);

第一個是繪制向下彎曲中跌,第二個是繪制向上彎曲。為了從左到右都繪制曲線菇篡,我們根據(jù)圓的直徑計算一下漩符,需要幾次才能平鋪,然后循環(huán)執(zhí)行上面兩句驱还,直到平鋪圓形區(qū)域嗜暴,為了展示當進度增大時將波紋幅度降低的效果(直到進度為100%,幅度降為0)我們根據(jù)當前進度值動態(tài)計算了幅度值,計算方法如下

float d = (1 - (float) currentProgress / maxProgress) *space;

由于我們需要以實心的方式繪制區(qū)域议蟆,那么我們調(diào)用
path.close();將所畫區(qū)域封閉闷沥,也就是實心的效果。

        path.close();
        bitmapCanvas.drawPath(path, progressPaint);

Ok咐容,到這里舆逃,自定義的水波形狀的進度條就完成了,再次上效果圖
(注:此水波左右移動是后來加的效果,具體實現(xiàn)點擊代碼查看

這里寫圖片描述

由于本人目前水平有限路狮,文字若有不足的地方虫啥,歡迎指正,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奄妨,一起剝皮案震驚了整個濱河市涂籽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌砸抛,老刑警劉巖评雌,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異直焙,居然都是意外死亡景东,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門箕般,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耐薯,“玉大人,你說我怎么就攤上這事丝里∏酰” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵杯聚,是天一觀的道長臼婆。 經(jīng)常有香客問我,道長幌绍,這世上最難降的妖魔是什么颁褂? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮傀广,結(jié)果婚禮上颁独,老公的妹妹穿的比我還像新娘。我一直安慰自己伪冰,他們只是感情好誓酒,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贮聂,像睡著了一般靠柑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吓懈,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天歼冰,我揣著相機與錄音,去河邊找鬼耻警。 笑死隔嫡,一個胖子當著我的面吹牛甸怕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畔勤,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蕾各,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了庆揪?” 一聲冷哼從身側(cè)響起式曲,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缸榛,沒想到半個月后吝羞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡内颗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年钧排,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片均澳。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡恨溜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出找前,到底是詐尸還是另有隱情糟袁,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布躺盛,位于F島的核電站项戴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏槽惫。R本人自食惡果不足惜周叮,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望界斜。 院中可真熱鬧仿耽,春花似錦、人聲如沸各薇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽得糜。三九已至,卻和暖如春晰洒,著一層夾襖步出監(jiān)牢的瞬間朝抖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工谍珊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留治宣,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像侮邀,于是被迫代替她去往敵國和親坏怪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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

  • 版權(quán)聲明:本文為博主原創(chuàng)文章绊茧,未經(jīng)博主允許不得轉(zhuǎn)載铝宵。系列教程:Android開發(fā)之從零開始系列源碼:github....
    Anlia閱讀 9,396評論 11 83
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載华畏。微博:厲圣杰微信公眾號:牙鍋子(基本不更)源碼:CircleP...
    牙鍋子閱讀 17,412評論 24 86
  • 概述 對于一些耗時操作鹏秋,例如加載大文件,如果不給用戶一個動態(tài)加載的友好提示界面亡笑,就會讓用戶感覺應用卡死了侣夷,所以今天...
    小蕓論閱讀 764評論 2 5
  • 一、概述 1. 四線格與基線 小時候仑乌,我們在剛開始學習寫字母時百拓,用的本子是四線格的,我們必須把字母按照規(guī)則寫在四線...
    addapp閱讀 7,629評論 2 17
  • 時間是個不等人的東西晰甚,一晃一個月過去了衙传,一晃一年過去了,又一晃十年過去了压汪。他總是在不經(jīng)意間偷偷的溜走粪牲。同時,也帶走...
    文齋而閱讀 159評論 0 0