Android 的揭露(CircularReveal)動畫

完整叫法應該是圓形揭露動畫庶弃,下文簡稱揭露動畫征峦,因為 Android 系統(tǒng)中只提供了這圓形的(Circular)揭露動畫哼御!

所謂揭露動畫,就是一種用于 View 之間冶匹,甚至界面之間的特殊過渡動畫效果。

AndroidPlatform 的 android.view 包下有個 ViewAnimationUtils 類求妹,這是使用系統(tǒng)所提供揭露動畫的唯一入口揩懒,其對外暴露的唯一接口如下:

Public methods
static Animator! createCircularReveal(view: View!, centerX: Int, centerY: Int, startRadius: Float, endRadius: Float)Returns an Animator which can animate a clipping circle.

通過其靜態(tài)的 createCircularReveal 方法來構造一個動畫(Animator)對象,具體其實是個 RevealAnimator 類對象被辑,進而可以實現(xiàn)一種炫酷(到底炫不炫酷就很主觀了)的動畫效果燎悍!

靠動圖來闡明揭露之意再合適不過,為此我寫了個小 demo盼理,運行效果如下:

App 的揭露效果:

App揭露

Activity 的揭露效果:

Activity揭露

普通 View 的揭露效果:

View揭露

幾圖勝千言谈山!以上就是所謂的揭露動畫。Demo 源碼(Kotlin)我已放至 Github宏怔,源碼在此勾哩,下面我們好好聊下這種過渡動畫的具體實現(xiàn)。

墻裂建議結合 Demo 閱讀本文举哟,另外 Demo 中的代碼注釋十分詳細思劳,讀者可以試試如果僅根據(jù) Demo 中的源碼注釋就能理解上面效果背后的所有原理……下面的正文我還是建議你讀一下!

正文

基礎 API

先來聊聊揭露動畫 Api 的基礎用法妨猩。

上面說到揭露動畫對外暴露的唯一使用接口是 ViewAnimationUtils 類的一個靜態(tài)方法 createCircularReveal潜叛。看此方法的完整簽名有五個參數(shù),用于在方法內部構造一個揭露動畫以返回給用例:

createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius)

第一個參數(shù)是個 View威兜,揭露動畫的應用對象必須是一個 View销斟,這點不難理解。

第二個參數(shù)是圓形揭露效果的圓心 X 軸坐標椒舵,同理第三個參數(shù)是 Y 軸坐標蚂踊。

第三個參數(shù)是圓形揭露效果的開始半徑,同理第四個參數(shù)是圓形揭露效果的終止半徑笔宿,開始半徑傳 0犁钟,終止半徑傳 View 的寬度或高度就是個典型的從無到有的揭露(顯示)過程,反之泼橘,開始半徑傳 View 的寬度或高度涝动,終止半徑傳 0 就是個從有到無的反揭露(隱藏)過程。

拿到此方法返回的 Animator 對象我們就可以隨時控制 View 進行揭露動畫了炬灭。

是不是很簡單醋粟?

View 級別的揭露動畫

我們先來看看最簡單的普通 View 的揭露動畫效果(上面第三張圖)其具體代碼是怎樣的,

/* Demo 的關鍵代碼文件結構
appreveal
            │  MainActivity.kt
            │  SecondActivity.kt //普通 View 的揭露效果見 Demo 里的這個文件中的代碼
            │
            ├─base
            │      BaseActivity.kt //Activity 和 App 層面的揭露動畫效果主要見 Demo 里此文件中的代碼
            │
            ├─ext
            │      ActicityExtension.kt
            │
            └─util
                   StatusBarUtil.kt
*/

普通 View 的揭露動畫見 Demo 里的 SecondActivity重归,其布局如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="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:background="@android:color/white"
    tools:context=".SecondActivity">
    <!--我們要對這個藍色背景 View 做揭露和反揭露動畫-->
    <View
        android:id="@+id/viewBg"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@android:color/holo_blue_bright"
        android:visibility="visible"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintVertical_bias="0.1"
        android:text="@string/app_second"
        android:textSize="30sp"/>

    <!--點擊這個按鈕開始揭露米愿、反揭露動畫-->
    <Button
        android:id="@+id/btnReveal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_reveal_r"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

SecondActivity 中設置點擊中間的按鈕開始 id 為 viewBg 界面控件的揭露動畫,關鍵代碼如下:

//中間按鈕的點擊事件
btnReveal.setOnClickListener { view ->
            //系統(tǒng)提供的揭露動畫需 5.0 及以上的 sdk 版本
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                return@setOnClickListener
            }
            //動畫開始半徑和結束半徑鼻吮,兩者相對關系可用于控制是揭露還是反揭露育苟,也即是從無到有還是從有到無
            val startRadius:Float
            val endRadius:Float
            if (viewBg.visibility == View.VISIBLE){
                //從有到無,即反揭露
                startRadius = viewBg.height.toFloat()
                endRadius = 0f
            }else{
                //從無到有狈网,即揭露效果
                startRadius = 0f
                endRadius = viewBg.height.toFloat()
            }
            val location = IntArray(2)
            view.getLocationInWindow(location)
            //關鍵代碼宙搬,構建一個揭露動畫對象,注意圓形揭露動畫的圓心以及開始半徑和結束半徑是如何計算出來的拓哺,應該很好理解勇垛,這里不做過多解釋
            val animReveal = ViewAnimationUtils.createCircularReveal(viewBg,
                    location[0] + view.width/2,
                    location[1] + view.height/2,
                    startRadius,
                    endRadius

            )
            //構建好了揭露動畫對象,開始設置動畫的一些屬性和相關監(jiān)聽
            animReveal.duration = 400
            animReveal.interpolator = LinearInterpolator()
            animReveal.addListener(onStart = {
                viewBg.visibility = View.VISIBLE
            },onEnd = {
                if (startRadius != 0f){
                    viewBg.visibility = View.INVISIBLE
                    btnReveal.setText(R.string.app_reveal)
                }else{
                    viewBg.visibility = View.VISIBLE
                    btnReveal.setText(R.string.app_reveal_r)
                }
            })
            animReveal.start()
        }

代碼真機運行的具體界面效果如下:

View揭露

基本使用如此士鸥,為界面中的某個 View 應用揭露動畫效果還是很簡單的闲孤,下面我們看看如何為應用內 Activity 間的切換(上面Activity 的揭露效果一圖)應用我們炫酷(主觀上的)的揭露動畫效果。

Activity 級別的揭露動畫

首先我們會遇到兩個問題:

  1. 揭露動畫用于 Activity 切換時烤礁,我們該把揭露動畫應用于哪個 View(揭露動畫的應用對象必須是一個 View)讼积?
  2. 何時開始執(zhí)行揭露動畫?

根據(jù)我們得 Demo脚仔,一一作答勤众。

揭露動畫用于 Activity 切換時,最合適的對象肯定是此 Activity 相關 Window 的根視圖鲤脏,真正的根視圖们颜,沒錯正是此 Activity 的 Window 的 DecorView(DecorView 不是很了解吕朵?相關知識參考這篇博文)。

至于揭露動畫的開始時機窥突,太早或太晚都不好努溃。首先不能太早,如果當前 View 還未 Attach 到 Window 上就對其應用揭露動畫會拋出異常阻问,其次不能太晚梧税,不然會嚴重影響動畫的視覺效果。

經作者實踐称近,這個最好的揭露動畫開始時機在視圖的可見性剛變?yōu)閷τ脩艨梢姇r最佳第队!我們通過為 View 的 ViewTreeObserver 設置一個 OnGlobalLayoutListener 回調可完美監(jiān)聽到這個最佳時機~

我把相關實現(xiàn)代碼全都放在了 Demo 的 BaseActivity 類里,用例 Activity 只要繼承 BaseActivity 即可在打開時應用揭露動畫效果煌茬。這里注意為了動畫的連貫性我們需要把 Activity 揭露動畫開始的圓心坐標從它的上個 Activity 里通過 Intent 傳遞過來斥铺,這點并不難實現(xiàn)彻桃。關鍵代碼如下:

//將 Activity 的揭露效果寫在 Base 類中坛善,需要揭露動畫效果時繼承
abstract class BaseActivity : AppCompatActivity(){
    companion object {
        //手動往 intent 里傳入上個界面的點擊位置坐標
        val CLICK_X = "CLICK_X"
        val CLICK_Y = "CLICK_Y"
    }
    private var onGlobalLayout : ViewTreeObserver.OnGlobalLayoutListener? = null
    //揭露(進入)動畫
    var mAnimReveal : Animator? = null
    //反揭露(退出)動畫
    var mAnimRevealR : Animator? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        circularReveal(intent)
    }

    //Activity 揭露(進入)動畫,進入時使用
    private fun circularReveal(intent: Intent?){
        //系統(tǒng)提供的揭露動畫需 5.0 及以上的 sdk 版本邻眷,當我們獲取不到上個界面的點擊區(qū)域時就不展示揭露動畫眠屎,因為此時沒有合適的錨點
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || 
                (intent?.sourceBounds == null && intent?.hasExtra(CLICK_X)?.not()?:true)) return
        val rect = intent?.sourceBounds
        val v = window.decorView
        v.visibility = View.INVISIBLE

        @SuppressWarnings
        onGlobalLayout = object : ViewTreeObserver.OnGlobalLayoutListener{
            override fun onGlobalLayout() {//此時既是開始揭露動畫的最佳時機
                mAnimReveal?.removeAllListeners()
                mAnimReveal?.cancel()
                mAnimReveal = ViewAnimationUtils.createCircularReveal(v,
                        rect?.centerX()?:intent?.getIntExtra(CLICK_X, 0)?:0,
                        rect?.centerY()?:intent?.getIntExtra(CLICK_Y, 0)?:0,
                        0f,
                        v.height.toFloat()
                )
                mAnimReveal?.duration = 400
                mAnimReveal?.interpolator = LinearInterpolator()
                mAnimReveal?.addListener(onEnd = {
                    onGlobalLayout?.let {
                        //我們需要在揭露動畫進行完后及時移除回調
                        v?.viewTreeObserver?.removeOnGlobalLayoutListener(it)
                    }
                })
                mAnimReveal?.start()
            }
        }
        //視圖可見性發(fā)生變化時的回調,回調里正是開始揭露動畫的最佳時機
        v.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayout)
    }

    //Activtiy 反揭露(退出)動畫肆饶,即退出時的過渡動畫改衩,
    //這么起名可能不恰當,其實還是同樣的動畫驯镊,
    //只不過揭露的起始和終結半徑跟上面相比反過來了
    private fun circularRevealReverse(intent: Intent?){
        //系統(tǒng)提供的揭露動畫需 5.0 及以上的 sdk 版本葫督,當我們獲取不到上個界面的點擊區(qū)域時就不展示揭露動畫,因為此時沒有合適的錨點
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || 
                (intent?.sourceBounds == null && intent?.hasExtra(CLICK_X)?.not()?:true)) {
            super.onBackPressed()
            return
        }
        val rect = intent?.sourceBounds
        val v = window.decorView
        mAnimRevealR?.removeAllListeners()
        mAnimRevealR?.cancel()
        mAnimRevealR = ViewAnimationUtils.createCircularReveal(v,
                rect?.centerX()?:intent?.getIntExtra(CLICK_X, 0)?:0,
                rect?.centerY()?:intent?.getIntExtra(CLICK_Y, 0)?:0,
                v.height.toFloat(),
                0f

        )
        mAnimRevealR?.duration = 400
        mAnimRevealR?.interpolator = LinearInterpolator()
        mAnimRevealR?.addListener(onEnd = {
            v.visibility = View.GONE
            super.onBackPressed()
        })
        mAnimRevealR?.start()
    }

    //回退時應用反揭露動畫
    override fun onBackPressed() {
        circularRevealReverse(intent)
    }

    //省略的其他代碼板惑,見 Demo 里的 BaseActivity
    ...
}

MainActivity 里打開 SecondActivity(繼承了 BaseActivity) 的代碼:

btnNext.setOnClickListener {view ->
            val intent = Intent(this, SecondActivity::class.java)
            val location = IntArray(2)
            view.getLocationInWindow(location)
            //把點擊按鈕的中心位置坐標傳過去作為 SecondActivity 的揭露動畫圓心
            intent.putExtra(CLICK_X, location[0] + view.width/2)
            intent.putExtra(CLICK_Y, location[1] + view.height/2)
            startActivity(intent)
        }

我們重點看下 BaseActivity 的 circularReveal 方法橄镜,此方法在 onCreate 方法里被調用了一次,它的功能就是給整個 Activity 加上合適的揭露動畫效果冯乘,即在 DecorView 剛對用戶可見時開始構建并執(zhí)行揭露動畫洽胶。

方法里的判斷有個條件:intent?.sourceBounds == null,這里的 intent?.sourceBounds 是什么東西裆馒?其實在當前應用內姊氓,為 Activity 間切換時應用揭露動畫效果完全可以不判斷這個條件,此代碼是寫給文章最后才會聊到的整個 App 的揭露效果(上面 App 的揭露效果那張圖)的喷好。Intent 類里面有個方法簽名如下:

open Rect? getSourceBounds()Get the bounds of the sender of this intent, in screen coordinates.

此方法返回一個 Rect 翔横,里面存儲著桌面(Launcher)里本應用的圖標的位置信息,后面會詳細說到梗搅,且先略過不談禾唁。

onBackPressed 方法中調用了執(zhí)行反揭露動畫的方法 circularRevealReverse舔亭。

其他代碼經過上面的鋪墊結合注釋應該很好理解,最終運行到真機上動畫效果如下:

Activity揭露

還有很重要的一點蟀俊,因為 Activity 的 Window 會自帶有背景色(一般為黑色)钦铺,所以我們需要對 Activity 的主題做些定制,以保證揭露動畫的效果:

<!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <!--背景透明且屏蔽系統(tǒng)默認的 Activity 過渡動畫-->
    <style name="trans_no_anim" parent="AppTheme">
        <!--屏蔽系統(tǒng)默認的 Activity 過渡動畫-->
        <item name="android:windowAnimationStyle">@null</item>

        <!--單純實現(xiàn) Activity 窗口背景透明-->
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

對 Activity 使用揭露動畫必須在清單文件中把其主題設置成 trans_no_anim肢预。

App 級別的揭露動畫

最后要聊到的揭露動畫應用場景比較有意思矛洞。

我們能不能給整個 App 加上一個完美的揭露動畫效果呢?

此處所謂完美的揭露動畫效果烫映,即我們每次從 Launcher(Android 系統(tǒng)的 Launcher沼本,即系統(tǒng)桌面,按 Home 鍵會回到的那個地方锭沟,也叫啟動器抽兆。注意 Launcher 在安卓系統(tǒng)中是個單獨的 APP,從桌面點擊應用圖標啟動應用的時候 Launcher 會把圖標的位置信息通過 intent 一路傳到應用的 Launcher Activity族淮,相關知識還請讀者自行 Google) 里點擊我們的應用圖標辫红,不管應用是不是初次啟動,不管停留在哪個界面祝辣,都能通過揭露動畫打開或回到我們應用贴妻,在我們的應用中,通過回退按鈕(back 鍵)回到 Launcher 時都能通過反揭露動畫收起我們應用(通過 Home 鍵回到 Launcher 時不應用反揭露動畫蝙斜,因為全面屏手勢正在 Android 系統(tǒng)中普及名惩,其會令反揭露動畫效果不佳,此時用系統(tǒng)的默認動畫最好)孕荠。已知揭露動畫必須有個圓心娩鹉,此處這個圓心必然應該是 Launcher 中我們應用圖標的中心位置的坐標。前文有提到稚伍,這個坐標的相關信息可通過 Launcher Activity 的 Intent 的 getSourceBounds() 方法獲得(非 Launcher Activity 通過此方法獲取到的只是個 null)弯予。這里會有個問題,即 Launcher 中的圖標槐瑞,其位置可是會隨時變化的(由用戶手動拖動)熙涤!完美的效果必然要能適應坐標隨時會變化的啟動圖標。大概效果會是這樣:

App揭露

答案是很遺憾困檩,經作者本人實踐祠挫,通過 Android 提供的現(xiàn)有 API 無法實現(xiàn)這種給整個 App 加上一個完美揭露動畫效果的需求!反正作者本人的嘗試以失敗而終悼沿!

從上面的動圖可以看出等舔,我?guī)缀蹙鸵昝缹崿F(xiàn)這種效果了。問題就出在 Launcher 中的圖標糟趾,其位置可能會隨時變化(由用戶手動拖動)慌植,而我找不到及時更新 Launcher 圖標位置信息的方法甚牲!

先來看看光上圖所示效果是如何實現(xiàn)的。

還記得上面貼的比較重要的 BaseActivity 的代碼嗎蝶柿,上面沒貼全丈钙,其下面還有代碼(注意結合上面貼過的代碼看):

//將 Activity 的揭露效果寫在 Base 類中,需要揭露動畫效果時繼承
abstract class BaseActivity : AppCompatActivity(){
    //省略上文已貼過的代碼
    ...
    ...

    override fun onDestroy() {
        //及時釋放資源以保證代碼健壯性
        mAnimReveal?.removeAllListeners() 
        mAnimReveal?.cancel()
        mAnimRevealR?.removeAllListeners()
        mAnimRevealR?.cancel()
        //及時釋放資源以保證代碼健壯性
        onGlobalLayout?.let {
            window.decorView.viewTreeObserver?.removeOnGlobalLayoutListener(it)
        }
        super.onDestroy()
    }

    //這個方法很重要交汤,如果我們應用的啟動圖標在桌面上的位置有變化雏赦,可在此收到新的位置信息,然而經作者本人實踐作用十分有限
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        circularReveal(intent)
        //更新intent
        this.intent = intent
    }
}

注意 onNewIntent 方法芙扎,我們就是在這里更新本應用的啟動圖標在 Launcher 中的位置信息的星岗。

如何更新的呢?

已知點擊桌面上的圖標初次啟動應用時戒洼,圖標的位置信息會通過 intent 傳遞給應用的 Launcher Activity俏橘,應用如果已經啟動,只是退居后臺圈浇,此時再點擊啟動圖標回到應用寥掐,會調用 onNewIntent 方法嗎?

一般不會汉额,然而當從清單文件中把 Launcher Activity 的啟動模式設置成 standard 外的任意一種時曹仗,只要 Launcher Activity 在棧頂榨汤,從桌面點擊啟動圖標就會回調其 onNewIntent 方法蠕搜,這個方法傳入的 intent 參數(shù)中保存著應用啟動圖標在 Launcher 中的最新坐標信息!

比如我們把 MainActivity 的啟動模式設置成 singleTop:

<activity
            android:name=".MainActivity"
            android:launchMode="singleTop"> <!-- 只要 Activity 的 lanuchMode 不是 standard 的收壕,當此 Activity 處于自己所在任務棧的棧頂時妓灌,每次點擊桌面中本應用的啟動圖標時都會觸發(fā)此 Activity 的 onNewIntent 方法 -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

即可實現(xiàn)上圖所示的效果。

注意上文所言的限制條件蜜宪,Launcher Activity 必須在棧頂虫埂,且點擊啟動圖標時只有 Launcher Activity 可能會被回調 onNewIntent 方法!作者本人始終沒找到系統(tǒng)中有別的接口來更新或者獲取最新的本應用圖標的位置信息圃验!

正因如此掉伏,所以我最后得出的結論是我們無法給整個 App 加上一個完美的揭露動畫效果,只能在有限的條件下(不去太關心應用啟動圖標的位置隨時可能被用戶更改這件事)給 App 加上一個乍看上去還行的揭露動畫效果澳窑,如上圖所示斧散!

全文終。

未完待續(xù)摊聋。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末鸡捐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子麻裁,更是在濱河造成了極大的恐慌箍镜,老刑警劉巖源祈,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異色迂,居然都是意外死亡香缺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門歇僧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赫悄,“玉大人,你說我怎么就攤上這事馏慨」』矗” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵写隶,是天一觀的道長倔撞。 經常有香客問我,道長慕趴,這世上最難降的妖魔是什么痪蝇? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮冕房,結果婚禮上躏啰,老公的妹妹穿的比我還像新娘。我一直安慰自己耙册,他們只是感情好给僵,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著详拙,像睡著了一般帝际。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饶辙,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天蹲诀,我揣著相機與錄音,去河邊找鬼弃揽。 笑死脯爪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的矿微。 我是一名探鬼主播痕慢,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冷冗!你這毒婦竟也來了守屉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蒿辙,失蹤者是張志新(化名)和其女友劉穎拇泛,沒想到半個月后滨巴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡俺叭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年恭取,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熄守。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜈垮,死狀恐怖,靈堂內的尸體忽然破棺而出裕照,到底是詐尸還是另有隱情攒发,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布晋南,位于F島的核電站惠猿,受9級特大地震影響,放射性物質發(fā)生泄漏负间。R本人自食惡果不足惜偶妖,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望政溃。 院中可真熱鬧趾访,春花似錦、人聲如沸董虱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽空扎。三九已至藏鹊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間转锈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工楚殿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撮慨,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓脆粥,卻偏偏與公主長得像砌溺,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子变隔,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345