Android的動畫詳解

一: 傳統 View 動畫(Tween/Frame)

1.1 Tween 動畫

主要有 4 中:縮放、平移、漸變、旋轉


文件位置: res/anim/filename.xml

編譯資源的數據類型:an Animation

資源引用:

Java: R.anim.filename

XML: @[package:]anim/filename


布局文件必須有一個獨立的根元素,可以是?,,?,?,?(持有一組其它的動畫元素,甚至可以是內嵌的 set 元素) 中的一個

1.1.1?

一個持有其它動畫元素的容器?,?,?,或者其它??元素

屬性

android:interpolator

應用于動畫的插值器。該值必須是一個指定了插值器資源的引用(不是一個插值器的類名),在平臺中有缺省的插值器資源可以使用,或者你可以創建自己的插值器資源,可以看下面關于插值器的討論。

android:shareInterpolator

Boolean 值, true:代表在所有的子元素中共享同一個插值器

1.1.2?

A fade-in or fade-out animation. Represents an AlphaAnimation. 一個漸入漸出的動畫,對應的 java 類為 AlphaAnimation。

屬性

android:fromAlpha

android:toAlpha

代表動畫開始和結束時透明度,0.0 表示完全透明,1.0 表示完全不透明,Float 值

1.1.3?

可以實現動態調控件尺寸的效果,通過設置 pivotX 和 pivotY 你可以指定 image 縮放的中心點,比如:如果這些值是 0,則表示左上角,所有的縮放變化將沿著右下角的軌跡運動。對應的類為:ScaleAnimation

屬性

android:fromXScale

android:toXScale

android:fromYScale

android:toYScale

Float 值,為動畫起始到結束時,X、Y 坐標上的伸縮尺寸

0.0 表示收縮到沒有

1.0 表示正常無伸縮

android:pivotX

android:pivotY

代表縮放的中軸點 X/Y 坐標,浮點值

如果我們想表示中軸點為圖像的中心,我們可以把兩個屬性值定義成 0.5 或者 50%。

1.1.4?

代表一個水平、垂直的位移。對應的類為 TranslateAnimation. 屬性

android:fromXDelta 屬性代表起始 X 方向的位置

android:toXDelta

android:fromYDelta

android:toYDelta

代表動畫起始或者結束 X / Y 方向上的位置,Float 或者百分比值

浮點數 num%、num%p 分別相對于自身或者父控件

如果以浮點數字表示,是一個絕對值,代表相對自身原始位置的像素值;

如果以 num%表示,代表相對于自己的百分比,比如 toXDelta 定義為 100%就表示在 X 方向上移動自己的 1 倍距離

如果以 num%p 表示,代表相對于父類組件的百分比。

1.1.5?

是旋轉動畫,與之對應的 Java 類是 RotateAnimation

屬性

android:fromDegrees

android:toDegrees

代表起始和結束的角度,浮點值,單位:度

android:pivotX 屬性代表旋轉中心的 X 坐標值

android:pivotY 屬性代表旋轉中心的 Y 坐標值

Float 值或者百分比

這兩個屬性也有三種表示方式,但是 X 軸都是相對方向都是 Left,Y 軸都是相對于 Top

浮點數、num%、num%p;

數字方式代表相對于自身左邊緣的像素值,

num%方式代表相對于自身左邊緣或頂邊緣的百分比,

num%p 方式代表相對于父容器的左邊緣或頂邊緣的百分比

屬性

android:fromDegrees

android:toDegrees

開始和結束時的弧度位置,單位是度,Float 值

調用代碼

另外,在動畫中,如果我們添加了 android:fillAfter="true"后,這個動畫執行完之后保持最后的狀態;android:duration="integer"代表動畫持續的時間,單位為毫秒。

1.1.6 插值器

用于修改一個動畫過程中的速率,可以定義各種各樣的非線性變化函數,比如加速、減速等

在 Android 中所有的插值器都是 Interpolator 的子類,通過 android:interpolator 屬性你可以引用不同的插值器。下面是幾種插值器:

你可以通過下面的方式使用它們:

自定義插值器?如果你對系統提供的插值器不滿意,我們可以創建一個插值器資源修改插值器的屬性,比如修改 AnticipateInterpolator 的加速速率,調整 CycleInterpolator 的循環次數等。為了完成這種需求,我們需要創建 XML 資源文件,然后將其放于/res/anim 下,然后再動畫元素中引用即可。我們先來看一下幾種常見的插值器可調整的屬性:

我們先來看一下幾種常見的插值器可調整的屬性:

<accelerateDecelerateInterpolator> 無

?<accelerateInterpolator> android:factor 浮點值,加速速率,默認為 1

?<anticipateInterploator> android:tension 浮點值,起始點后退的張力、拉力數,默認為 2

?<anticipateOvershootInterpolator> android:tension 同上 android:extraTension 浮點值,拉力的倍數,默認為 1.5(2 * 1.5)

?<bounceInterpolator> 無

?<cycleInterplolator> android:cycles int,循環的個數,默認為 1

?<decelerateInterpolator> android:factor 浮點值,減速的速率,默認為 1

?<linearInterpolator> 無

?<overshootInterpolator> 浮點值,超出終點后的張力、拉力,默認為 2

比如:res/anim/my_overshoot_interpolator.xml:

如果簡單的修改插值器的屬性值還不能夠滿足我們的需求,那么就自己來通過實現 Interpolator 接口來定義自己的插值器了 因為上面所有的 Interpolator 都實現了 Interpolator 接口,這個接口定義了一個方法:float getInterpolation(float input); 此方法由系統調用,input 代表動畫的時間,在 0 和 1 之間,也就是開始和結束之間。

線性(勻速)插值器定義如下:

加速減速插值器定義如下:

1.2 Frame 動畫

文件目錄:res/drawable/filename.xml

編譯資源數據類型 AnimationDrawable

資源引用:

Java: R.drawable.filename

XML: @[package:]drawable.filename

1.2.1?

必須作為根元素,包含一個或者多個根元素

屬性:android:oneshot :true:只執行一次動畫,false:循環執行

1.2.2?

A single frame of animation. Must be a child of a??element. 一幀獨立動畫,必須是?的子元素

屬性

android:drawable

Drawable 資源,用于這一幀的圖片

android:duration

Integer 類型.該幀的時長,單位為毫秒 milliseconds.

res/anim/rocket.xml:

調用代碼:

二. Property Animation

2.1 Property Animation 的工作方式

Property Animation 動畫有兩個步聚:

1.計算屬性值

2.為目標對象的屬性設置屬性值,即應用和刷新動畫

2.1.1 計算屬性值

過程一:計算已完成動畫分數 elapsed fraction?為了執行一個動畫,你需要創建一個 ValueAnimator,并且指定目標對象屬性的開始、結束值和持續時間。在調用 start 后的整個動畫過程中, ValueAnimator 會根據已經完成的動畫時間計算得到一個 0 到 1 之間的分數,代表該動畫的已完成動畫百分比。0 表示 0%,1 表示 100%。

過程二:計算插值(動畫變化率)interpolated fraction?當 ValueAnimator 計算完已完成動畫分數后,它會調用當前設置的 TimeInterpolator,去計算得到一個 interpolated(插值)分數,在計算過程中,已完成動畫百分比會被加入到新的插值計算中。

過程三:計算屬性值?當插值分數計算完成后,ValueAnimator 會根據插值分數調用合適的 TypeEvaluator 去計算運動中的屬性值。

以上分析引入了兩個概念:已完成動畫分數(elapsed fraction)、插值分數( interpolated fraction )。

2.2 核心類

此圖轉載自xushuaic博客

2.2.1 Interpolators

插值器:時間的函數,定義了動畫的變化律。

插值器只需實現一個方法:getInterpolation(float input),其作用就是把 0 到 1 的 elapsed fraction 變化映射到另一個 interpolated fraction。 Interpolator 接口的直接繼承自TimeInterpolator,內部沒有任何方法,而TimeInterpolator只有一個getInterpolation方法,所以所有的插值器只需實現getInterpolation方法即可。

傳入參數是正常執行動畫的時間點,返回值是調用者真正想要它執行的時間點。傳入參數是{0,1},返回值一般也是{0,1}。{0,1}表示整段動畫的過程。中間的 0.2、0.3 等小數表示在整個動畫(原本是勻速的)中的位置,其實就是一個比值。如果返回值是負數,會沿著相反的方向執行。如果返回的是大于 1,會超出正方向執行。也就是說,動畫可能在你指定的值上下波動,大多數情況下是在指定值的范圍內。

getInterpolation(float input)改變了默認動畫的時間點 elapsed fraction,根據時間點 interpolated fraction 得到的是與默認時間點不同的屬性值,插值器的原理就是通過改變實際執行動畫的時間點,提前或延遲默認動畫的時間點來達到加速/減速的效果。動畫插值器目前都只是對動畫執行過程的時間進行修飾,并沒有對軌跡進行修飾。

簡單點解釋這個方法,就是當要執行 input 的時間時,通過 Interpolator 計算返回另外一個時間點,讓系統執行另外一個時間的動畫效果。

2.2.2 Evaluators

Evaluators 告訴屬性動畫系統如何去計算一個屬性值。它們通過 Animator 提供的動畫的起始和結束值去計算一個動畫的屬性值。 屬性系統提供了以下幾種 Evaluators: 1.IntEvaluator

2.FloatEvaluator

3.ArgbEvaluator

這三個由系統提供,分別用于計算 int,float,color 型(十六進制)屬性的計算器

4.TypeEvaluator

一個用于用戶自定義計算器的接口,如果你的對象屬性值類型,不是 int,float,或者 color 類型,你必須實現這個接口,去定義自己的數據類型。

TypeEvaluator接口只有一個方法,就是evaluate()方法,它允許你使用的 animator 返回一個當前動畫點的屬性值。

TimeInterpolator 和 TypeEvaluator 的區別

首先明確動畫屬性值的計算包括三步,其中第二步和第三步分別需要借助TimeInterpolator和TypeEvluator完成。

TypeEvaluator所做的是根據數據結構計算最終的屬性值,允許你定義自己的數據結構,這是官方對它的真正定義,如果你所定義的屬性值的數據類型不是 float、int、color 類型,那么你需要實現 TypeEvaluator 接口的evaluate()方法,自己進行屬性值的計算

Interpolator更傾向于你定義一種運動的變化率,比如勻速、加速、減速等,官方對 Interpolator 的定義也確實是這樣的:

A time interpolator defines the rate of change of an >animation. This allows animations to have non-linear >motion, such as acceleration and deceleration.

對于自定義高級動畫時,弄清TimeInterpolator和TypeEvaluator非常重要,如果你希望要自定義自己的動畫,那么這兩個函數肯定是關鍵部分,一個是定義動畫變化率,一個是定義數據結構和屬性值計算方式,兩者共同決定了一個動畫的運動。

2.2.3 ValueAnimator

屬性動畫中的主要的時序引擎,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。包含了所有計算動畫值的核心函數。也包含了每一個動畫時間上的細節,信息,一個動畫是否重復,是否監聽更新事件等,并且還可以設置自定義的計算類型。

使用 ValueAnimator 實現動畫需要手動更新:

2.2.4 ObjectAnimator

繼承自ValueAnimator,允許你指定要進行動畫的對象以及該對象的一個屬性。該類會根據計算得到的新值自動更新屬性。也就是說上 Property Animation 的兩個步驟都實現了。大多數的情況,你使用ObjectAnimator就足夠了,因為它使得目標對象動畫值的處理過程變得簡單,不用再向ValueAnimator那樣自己寫動畫更新的邏輯。但ObjectAnimator有一定的限制,比如它需要目標對象的屬性提供指定的處理方法,這個時候你需要根據自己的需求在ObjectAnimator和ValueAnimator中做個選擇了,看哪種實現更簡便。

ObjectAnimator的自動更新功能,依賴于屬性身上的setter和getter方法,所以為了讓ObjectAnimator能夠正確的更新屬性值,你必須遵從以下規范:

1.該對象的屬性必須有get和set方法(方法的格式必須是駝峰式),方法格式為 set(),因為 ObjectAnimator 會自動更新屬性,它必須能夠訪問到屬性的setter方法,比如屬性名為foo,你就需要一個setFoo()方法,如果 setter 方法不存在,你有三種選擇:

a.添加 setter 方法

b.使用包裝類。通過該包裝類通過一個有效的 setter 方法獲取或者改變屬性值的方法,然后應用于原始對象,比如 NOA 的AnimatorProxy。

c.使用 ValueAnimator 代替

(這 3 點的意思總結起來就是一定要有一個setter方法,讓ObjectAnimator能夠訪問到)

1.如果你為 ObjectAnimator 的工廠方法的可變參數只傳遞了一個值,那么會被作為動畫的結束值。

2.注意,屬性的getter方法和setter方法必須必須是相對應的,比如你構造了一個如下的ObjectAnimator,那么getter和setter方法就應該為:

3.根據動畫的目標屬性或者對象不同,你可能需要調用某一個 View 的invalidate方法,根據新的動畫值去強制屏幕重繪該 View。可以在onAnimateonUpdate()回調方法中去做。比如,對一個 Drawable 的顏色屬性進行動畫,只有當對象重繪自身的時候,才會導致該屬性的更新,(不像平移或者縮放那樣是實時的)。一個 View 的所有 setter 屬性方法,比如setAlpha()和setTranslationX()都可以適當的更新 View。因此你不需要在重繪的時候為這些方法傳遞新的值。更多關于 Listener 的信息,可以參考第四部分 Animation Listeners。

簡單總結下:?當你不希望向外暴露Setter方法的時候,或者希望獲取到動畫值統一做處理的話,亦或只需要一個簡單的時序機制(擁有動畫的各種值)的話,那么你可以選擇使用ValueAnimator,它更簡單。如果你就是希望更新動畫,為了簡便,可以使用ObjectAnimator,但自定義的屬性必須有setter和getter方法,并且它們必須都是標準的駝峰式(確保內部能夠調用),必須有結束值。你可以實現Animator.AnimatorListener接口根據自己的需求去更新 View。

2.2.5 AnimatorSet

提供組合動畫能力的類。并可設置組中動畫的時序關系,如同時播放、有序播放或延遲播放。Elevator會告訴屬性動畫系統如何計算一個屬性的值,它們會從Animator類中獲取時序數據,比如開始和結束值,并依據這些數據計算動畫的屬性值。

小結:?TypeEvaluator

定義了屬性值的計算方式,有 int,float,color 類型,根據屬性的開始、結束值和插值一起計算出當前時間的屬性值,終極方法,整個動畫屬性值計算過程的結尾。

TimeInterpolation

插值器都必須實現的接口,定義了動畫的變化率,如線性,非線性。

ValueAnimator與ObjectAnimator:

兩者都可以進行屬性動畫,但是ObjectAnimator更加簡單,不用去做更新屬性值的計算,但是必須要提供標準的setter和getter方法,讓ObjectAnimator能夠獲取和更新屬性值。

2.2.6 ViewPropertyAnimator

可以方便的為某個 View 的多個屬性添加并行的動畫,只使用一個ViewPropertyAnimator對象就可以完成。它的行為更像一個ObjectAnimator,因為它修改的是對象的實際屬性值。但它為一次性給多個屬性添加動畫提供了方便,而且使用ViewPropertyAnimator的代碼更連貫更易讀。

下面的代碼段分別展示了使用多個ObjectAnimator對象、一個ObjectAnimator對象、?ViewPropertyAnimator同時為一個 View 的 X 和 Y 屬性添加動畫的示例:

多個 ObjectAnimator 結合 AnimatorSet 實現

一個 ObjectAnimator 結合多個 PropertyValuesHolder 實現



ViewPropertyAnimator: 只需一行代碼

myView.animate().x(50f).y(100f);//myView.animate()直接返回一個 ViewPropertyAnimator 對象

2.2.7 PropertyValuesHolder

顧名思義,該類持有屬性,相關屬性值的操作以及屬性的 setter,getter 方法的創建,屬性值以 Keyframe 來承載,最終由 KeyframeSet 統一處理。

2.2.8 KeyFrame

一個keyframe對象由一對 time / value 的鍵值對組成,可以為動畫定義某一特定時間的特定狀態。

每個keyframe可以擁有自己的插值器,用于控制前一幀和當前幀的時間間隔間內的動畫。

Keyframe.ofFloat(0f,0f);?第一個參數為:要執行該幀動畫的時間節點(elapsed time / duration)

第二個參數為屬性值。

因此如果你想指定某一特定時間的特定狀態,那么簡單的使用 ObjectAnimator就滿足不了你了,因為,ObjectAnimator.ofInt(....)類似的工廠方法,無法指定特定的時間點的狀態。

每個 KeyFrame 的 Interpolator

每個KeyFrame其實也有個Interpolator。如果沒有設置,默認是線性的。之前為Animator設置的Interpolator是整個動畫的,而系統允許你為每一KeyFrame的單獨定義Interpolator,系統這樣做的目的是允許你在某一個keyFrame做特殊的處理,也就是整體上是按照你的插值函數來計算,但是,如果你希望某個或某些KeyFrame會有不同的動畫表現,那么你可以為這個keyFrame設置Interpolator。

因此,Keyframe 的定制性更高,你如果想精確控制某一個時間點的動畫值及其運動規律,你可以自己創建特定的 Keyframe

Keyframe 使用

為了實例化一個keyframe對象,你必須使用某一個工廠方法:ofInt(), ofFloat(), or ofObject() 去獲取合適的keyframe類型,然后你調用ofKeyframe工廠方法去獲取一個PropertyValuesHolder對象,一旦你擁有了該對象,你可以將 PropertyValuesHolder 作為參數獲取一個Animator,如下:

2.2.9 KeyFrameSet

根據 Animator 傳入的值,為當前動畫創建一個特定類型的 KeyFrame 集合。

通常通過 ObjectAnimator.ofFloat(...)進行賦值時,這些值其實是通過一個 KeyFrameSet 來維護的

比如:

調用者傳入的 values 為 50,100,200,則 numKeyframs = 3,那么創建出相應的 Keyframe 為: Keyframe(0,50),Keyframe(1/2,100),Keyframe(1,200), 時間點 0,1/2,1 都是按比例劃分的

2.3 在 XML 中聲明屬性動畫

通過在 XML 中定義的動畫,可以很方便的在多個 Activities 中重用而且更容易編輯,復用性強。為了區分新的屬性動畫,從 3.1 開始,你應res/animator/下存放屬性動畫的資源文件,使用animator文件夾是可選的,但是如果你想在 Eclipse ADT 插件中使用布局編輯工具(ADT 11.0.0+),就必須在res/animator文件夾下存放了,因為 ADT 只會查找res/animator文件夾下的屬性動畫資源文件。

屬性動畫支持的 Tag 有

ValueAnimator - <animator>

ObjectAnimator - <objectAnimator>

AnimatorSet - <set>

目錄?res/animator/filename.xm

編譯后的資源為

ValueAnimator,?ObjectAnimator, or?AnimatorSet

XML 文件的根元素必須為<set>,<objectAnimator>, or <valueAnimator>之一。也可以在一個 set 中組織不同的動畫,包含其它<set>元素,也就是說,可以嵌套。


2.3.2 元素介紹

2.3.2.1?

動畫集合節點,有一個屬性 ordering,表示它的子動畫啟動方式是先后有序的還是同時。

屬性

sequentially:動畫按照先后順序

together (default) :動畫同時啟動

2.3.2.2?

一個對象的一個屬性,相應的 Java 類為:ObjectAnimator

屬性

android:propertyName:

String 類型,必須要設定的值,代表要執行動畫的屬性,通過名字引用,比如你可以指定了一個 View 的"alpha" 或者 "backgroundColor",這個 objectAnimator 元素沒有暴露 target 屬性,因此不能夠在 XML 中執行一個動畫,必須通過調用loadAnimator()?填充你的 XML 動畫資源,并且調用setTarget()?應用到擁有這個屬性的目標對象上。

android:valueTo

Float、int 或者 color,也是必須值,表明了動畫結束的點,顏色由 6 位十六進制的數字表示。

android:valueFrom

相對應 valueTo,動畫的起始點,如果沒有指定,系統會通過屬性身上的 get 方法獲取,顏色也是 6 位十六進制的數字表示。

android:duration

動畫的時長,int 類型,以毫秒為單位,默認為 300 毫秒。

android:startOffset

動畫延遲的時間,從調用 start 方法后開始計算,int 型,毫秒為單位,

android:repeatCount

一個動畫的重復次數,int 型,”-1“表示無限循環,”1“表示動畫在第一次執行完成后重復執行一次,也就是兩次,默認為 0,不重復執行。

android:repeatMode

重復模式:int 型,當一個動畫執行完的時候應該如何處理。該值必須是正數或者是 -1,

“reverse”

會使得按照動畫向相反的方向執行,可實現類似鐘擺效果。

“repeat”

會使得動畫每次都從頭開始循環。

android:valueType

關鍵參數,如果該 value 是一個顏色,那么就不需要指定,因為動畫框架會自動的處理顏色值。有 intType 和 floatType 兩種:分別說明動畫值為 int 和 float 型。

2.3.2.3 <animator>

在一個特定的時間里執行一個動畫。相對應的是 ValueAnimator.所有的屬性和一樣 android:valueTo

android:valueFrom

android:duration

android:startOffset

android:repeatCount

android:repeatMode

android:valueType

Value Description

floatType (default)

res/animator/property_animator.xml:

為了執行該動畫,必須在代碼中將該動畫資源文件填充為一個 AnimationSet 對象,然后在執行動畫前,為目標對象設置所有的動畫集合。

簡便的方法就是通過 setTarget 方法為目標對象設置動畫集合,代碼如下:

三 View anim 與 property anim 的比較

View anim 系統

view animation system 提供的能力只能夠為 View 添加動畫。因此如果你想為非 View 對象添加動畫,就必須自己去實現, view animation system 在 View 動畫的展現方面也是有約束的,只暴露了 View 的很少方面。比如 View 支持縮放和旋轉,但不支持背景顏色的動畫。

view animation system 的另一劣勢是,其改變的是 View 的繪制效果,真正的 View 的屬性保持不變,比如無論你在對話中如何縮放 Button 的大小,Button 的有效點擊區域還是沒有應用到動畫時的區域,其位置與大小都不變。

但是 View animation system 只需花費很少時間創建而且只需很少的代碼。如果 View 動畫完成了你所有的動作,或者你存在的代碼已經達到了你想要的效果,就沒必要使用 property 動畫系統了。

property anim 系統

完全彌補了 View anim System 的缺陷,你可以為一個對象的任何屬性添加動畫,(View 或者非 View),同時對象自己也會被修改。 并且當屬性變化的時候,property Anim 系統會自動的刷新屏幕。

屬性動畫系統在處理動畫方面也更加強勁。更高級的,你可以指定動畫的屬性,比如顏色,位置,大小,定義動畫的插值器并且同步多個動畫。

并且在 Property Animation 中,改變的是對象的實際屬性,如 Button 的縮放,Button 的位置與大小屬性值都改變了。而且 Property Animation 不止可以應用于 View,還可以應用于任何對象。

平時使用的簡單動畫特效,使用 View 動畫就可以滿足,但是如果你想做的更加復雜,比如背景色的動畫,或者不僅是 View,還希望對其它對象添加動畫等,那么你就得考慮使用 Property 動畫了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容