【Android 動畫】幀動畫、補間動畫、屬性動畫

分類

Android 官方提供了兩種動畫:

  • 屬性動畫(Property Animation)通過改變對象的屬性實現動畫效果;
  • 視圖動畫(View Animation)作用于 View 的動畫,視圖動畫又可以分為兩類:
  • 幀動畫(Frame Animation)通過一組圖片有序播放實現動畫視覺效果;
  • 補間動畫(Tween Animation)通過對視圖進行一系列的動作變化實現動畫效果;

一、幀動畫

幀動畫其實是 Drawable,用作 View 的背景,在 res/drawable 目錄下通過 <animation-list> 標簽定義

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot=""
    android:variablePadding=""
    android:visible="">
    <item android:drawable="" android:duration=""/>
</animation-list>

對應的 Drawable 的子類是 AnimationDrawable 類,構造方法:

public AnimationDrawable()

添加一幀動畫:

public void addFrame(@NonNull Drawable frame, int duration)

獲取到 AnimationDrawable 對象之后調用 start() 方法開始動畫

二、補間動畫

Animation

Animation 類位于 android.view.animation 包下,直接子類有五個。

1、Animation

a.xml 屬性
Xml Animation

上面列出了 Animation 類的所有 xml 屬性以及相關的方法。

  • android:duration:動畫的執行時間,單位毫秒;
  • android:fillBefore:動畫結束時畫面停留在此動畫的第一幀; 默認值為 true;
  • android:fillAfter:動畫結束是畫面停留在此動畫的最后一幀。默認值為false;
  • android:repeatCount:動畫重復執行的次數;
  • android:repeatMode:動畫重復執行模式,有 restart 和 reverse 兩種;
  • android:startOffset:動畫開始的延遲時間;
  • android:detachWallpaper:是否在壁紙上運行;
  • android:zAdjustment:被設置動畫的內容運行時在Z軸上的位置(top/bottom/normal),默認為 normal;
  • android:interpolator:插值器;
b.監聽器

AnimationListener

Animation 類內部定義監聽器 AnimationListener,定義了在動畫開始、結束、重復時的回調方法,通過 setAnimationListener 方法設置。

c.一些 public 方法

除了設置 xml 屬性的 setter 方法之外,還有一些常用的 public 方法:

public void start()
public void startNow()
public void setStartTime(long startTimeMillis)
public void reset()
public void cancel()
//設置動畫背景顏色,如果為 0,則沒有背景
public void setBackgroundColor(@ColorInt int bg)
d.定義

動畫有兩種定義方式,一種是在 res/anim 目錄中定義,通過 AnimationUtils#loadAnimation() 方法加載另一種是直接在代碼中通過構造方法創建對象。
視圖動畫只能給 View 使用,所以是通過 View 的方法開始動畫和清除動畫的

public void startAnimation(Animation animation)
public void clearAnimation()

2、TranslateAnimation(平移動畫)

a.xml 文件定義

在 res/anim 目錄中定義:

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta=""
    android:fromYDelta=""
    android:toXDelta=""
    android:toYDelta=""
    >
</translate>

使用 translate 標簽,動畫的起始點和結束點是 View 的左上角坐標,通過偏移量的方式來定義:

  • android:fromXDelta="",android:fromYDelta="":起始點 x,y 坐標,可以為** 數值、百分數、百分數p,數值表示當前 View 的左上角加上 數值px 作為起始點,即以 View 左上角為原點的坐標,百分數表示當前 View 的左上角加上 View寬高 * 百分數 作為起始點,百分數p表示當前 View 的左上角加上 父控件寬高 * 百分數 **作為起始點;
  • android:toXDelta="", android:toYDelta="":結束點 x,y 坐標,取值同上;
b.代碼定義

public 的構造方法:

public TranslateAnimation (Context context, AttributeSet attrs)
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
public TranslateAnimation (int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)

第三個構造方法不僅規定了起始點和結束點 x,y 坐標,還規定了每一個偏移值的類型,類型是在 Animation 類中以靜態常量的方式來定義的:


Type

有三種值 ABSOLUTE(絕對)、RELATIVE_TO_SELF(相對自身)、RELATIVE_TO_PARENT(相對父控件)
默認值為 ABSOLUTE,所以第二個構造方法中的參數為絕對數值

2、ScaleAnimation

a.xml 文件定義
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX=""
    android:pivotY=""
    android:fromXScale=""
    android:fromYScale=""
    android:toXScale=""
    android:toYScale=""
    >
</scale>

scale 標簽定義,縮放中心點默認為 View 左上角,通過偏移量來定義:

  • android:pivotX="",android:pivotY="":縮放中心點 x,y 坐標,可以為** 數值、百分數、百分數p,數值表示當前 View 的左上角加上 數值px 作為中心點,百分數表示當前 View 的左上角加上 View寬高 * 百分數 作為中心點,百分數p表示當前 View 的左上角加上 父控件寬高 * 百分數 **作為中心點;
  • android:fromXScale="",android:fromYScale="",android:toXScale="",android:toYScale="":開始時和結束時 x 方向和 y 方向縮放比例,1.0表示無變化;
b.代碼定義
public ScaleAnimation (Context context, AttributeSet attrs)
public ScaleAnimation (float fromX, float toX, float fromY, float toY)
public ScaleAnimation (float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)
public ScaleAnimation (float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

第二個構造方法只確定了縮放比例,縮放中心點默認為 View 左上角;
第三個構造方法除了定義了縮放比例,還定義了絕對數值類型的所方中心點偏移量;
第四個構造方法規定了縮放中心點偏移量的類型;

3、RotateAnimation

a.xml 文件定義
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX=""
    android:pivotY=""
    android:fromDegrees=""
    android:toDegrees=""
    android:drawable=""
    android:visible=""
    >
</rotate>

使用 rotate 標簽,需要聲明的屬性為旋轉的中心點和旋轉角度:

  • android:pivotX="",android:pivotY="":旋轉中心點坐標相對 View 左上角坐標偏移量,取值和默認值和 TranslateAnimation 平移坐標以及 ScaleAnimation 縮放中心點坐標相同;
  • android:fromDegrees="",android:toDegrees="":旋轉起始角度和結束角度,正值為順時針度數,負值為逆時針度數;
b.代碼定義

構造方法:

public RotateAnimation (Context context, AttributeSet attrs)
public RotateAnimation (float fromDegrees, float toDegrees)
public RotateAnimation (float fromDegrees, float toDegrees, float pivotX, float pivotY)
public RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

第二個構造方法只確定了旋轉角度,旋轉中心點默認為 View 左上角,第二個構造方法旋轉中心點偏移量為絕對數值,第三個構造方法規定了旋轉中心點偏移量的類型;

4.AlphaAnimaion

a.xml 文件定義

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha=""
    android:toAlpha=""
    >
</alpha>

只需要聲明起始和結束的透明度值,取值為 0.0~1.0,0.0表示全透明,1.0表示完全不透明

b.代碼定義

構造方法:

public AlphaAniamtion(Context context,AttributeSet attrs)
public AlphaAnimation (float fromAlpha, float toAlpha)

5.AnimationSet

a.xml 文件定義
<set xmlns:android="http://schemas.android.com/apk/res/android"
    >
    ...
    ...
</set>

通過 set 標簽定義,和其它四個 Animation 類的使用方法相同

b.代碼定義

構造方法:

public AnimationSet(Context context, AttributeSet attrs)
public AnimationSet(boolean shareInterpolator)

通過 addAnimation 方法來添加一個動畫

public void addAnimation (Animation a)

6.Interpolate

見下文。

三、屬性動畫

Animator

Animator 類位于 android.animation 包下,有兩個直接子類 AnimatorSet 和 ValueAnimator,兩個間接子類 ObjectAnimator 和 TimeAnimator

1、視圖動畫和屬性動畫的區別

  1. 視圖動畫作用對象只限制為 View,而屬性動畫作用對象不限為
    View,可以是任何對象。
  2. 視圖動畫只能改變 View 的位置或者視覺效果,并不能改變其屬性。

2、Animator

Animator 是一個抽象類,為子類定義了一些方法和接口

public 方法
public void start()
public void cancel()
public void end()
public void pause()
public void resume()
public abstract void setStartDelay(long startDelay);
public abstract Animator setDuration(long duration);
public abstract void setInterpolator(TimeInterpolator value);
public void addListener(AnimatorListener listener)
public void removeListener(AnimatorListener listener)
public void addPauseListener(AnimatorPauseListener listener) 
public void removePauseListener(AnimatorPauseListener listener)
public void removeAllListeners()
監聽器
AnimatorListener
AnimatorPauseListener

3、ValueAnimator

Animator 同樣有兩種定義方式,一種是通過 xml 文件定義,然后通過 AnimatorInflater#loadAnimator() 方法加載動畫,和補間動畫不同的是在 res/animator 目錄下面,另一種是在代碼中使用相應的方法定義。

xml 文件定義
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration=""
    android:interpolator=""
    android:repeatCount=""
    android:repeatMode=""
    android:startOffset=""
    android:valueFrom=""
    android:valueTo=""
    android:valueType="">
</animator>

<animator> 標簽定義的是 ValueAnimator 對象,上面列出了定義動畫時使用到的屬性,其中 android:valueType 屬性聲明了值的類型,有 intType、floatType、colorType、pathType 四種類型。
還可以使用 propertyValuesHolderkeyframe 標簽定義 ValueAnimator

<animator xmlns:android="http://schemas.android.com/apk/res/android"
          android:duration="1000"
          android:repeatCount="1"
          android:repeatMode="reverse">
    <propertyValuesHolder>
        <keyframe android:fraction="0" android:value="1"/>
        <keyframe android:fraction=".2" android:value=".4"/>
        <keyframe android:fraction="1" android:value="0"/>
    </propertyValuesHolder>
</animator>
Keyframe

Keyframe 保存有值動畫的一個時間、值對,ValueAnimator 的值從一個 Keyframe 變化到另一個 Keyframe,每一個 Keyframe 也有一個 TimeInterpolate 對象。
Keyframe 有三個成員變量:

//時間
float mFraction; 
public float getFraction()
public void setFraction(float fraction)
//值類型
Class mValueType;
public Class getType()
//插值器
private TimeInterpolator mInterpolator = null;
public TimeInterpolator getInterpolator()
public void setInterpolator(TimeInterpolator interpolator)

Keyframe 是一個抽象類,相關的方法返回的是對應的子類對象。

public static Keyframe ofInt(float fraction, int value)
public static Keyframe ofInt(float fraction)
public static Keyframe ofFloat(float fraction, float value)
public static Keyframe ofFloat(float fraction)
public static Keyframe ofObject(float fraction, Object value)
public static Keyframe ofObject(float fraction)

Keyframe 內部定義了三個子類:ObjectKeyframe、IntKeyframe、FloatKeyframe。
看一下 ObjectKeyframe 類的實現:

ObjectKeyframe

子類內部又定義了一個成員變量 mValue,在 ObjectKeyframe 中是 Object 類型的,并且重寫了 Keyframe 類的 getValue 和 setValue 方法,在 Keyframe#ofObject 方法就是通過 Objectkeyframe 的構造方法創建了一個對象,在構造函數內部給成員變量 mFraction 和 mValue 賦值,這里的 Object 參數可以為任何類的對象,當 value 為 null 時,默認為 Object 類型。

PropertyValueHolder

PropertyValuesHolder 可以暫存動畫的屬性和值使一個動畫可以同時操作多個屬性,有時可以替代 AnimatorSet。
PropertyValuesHolder 類的幾個重要成員變量:

//屬性名稱
String mPropertyName;
public void setPropertyName(String propertyName)
//值類型
Class mValueType;
//屬性值通過一組 Keyframes 來存儲
Keyframes mKeyframes = null;
public void setKeyframes(Keyframe... values)
//以下三個方法內部通過 Keyframe#ofXXX 方法創建 Keyframe 對象并賦值給成員變量 mKeyframes
public void setIntValues(int... values)
public void setFloatValues(float... values)
public void setObjectValues(Object... values)

PropertyValuesHolder 的兩個構造方法都是 private 的

private PropertyValuesHolder(String propertyName)
private PropertyValuesHolder(Property property)

所以要通過內部的一系列 ofXXX 方法創建 PropertyValuesHolder 對象:

public static PropertyValuesHolder ofInt(String propertyName, int... values)
public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values)
public static PropertyValuesHolder ofFloat(String propertyName, float... values)
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values)
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)
public static PropertyValuesHolder ofObject(String propertyName,TypeConverter<PointF, ?> converter, Path path)
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) 
public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values)

ofXXX 方法創建相應的 PropertyValuesHolder 對象,并通過 PropertyValuesHolder 類的 setXXX 給 mKeyframes 賦值。

public 方法
public void start()
public void cancel()
public void end()
public void resume()
public void pause()
public void reverse()
public Object getAnimatedValue() 
public Object getAnimatedValue(String propertyName) 
public float getAnimatedFraction()

代碼創建對象

一般不使用 ValueAnimator 的構造方法而是通過 ofXXX 方法:

public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofFloat(float... values)
public static ValueAnimator ofArgb(int... values)
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
ofInt

ofXXX 方法內部的操作都是創建一個 ValueAnimtor 對象,然后通過 ValueAnimator#setXXXValues 方法把 values 封裝成 PropertyValuesHolder 數組


setIntValues

ValueAnimator 的值是存放在 PropertyValuesHolder 類型的數組成員變量 mValues 中的,數組中的每一個元素表示一個屬性,可以看到在 setIntValues 方法中,當 mValues 不為 null 時,把數組中的第一個 PropertyValuesHolder 元素取出來,然后調用 PropertyValuesHolder#setIntValues 方法,把值設置給該 PropertyValuesHolder 對象,前面已經說過 setXXXValues 方法內部調用 Keyframe#ofXXX 方法,當 mValues 為 null 時,最終是通過 PropertyValuesHolder#ofInt 方法生成 PropertyValuesHolder 對象然后調用了 setValues 方法


setValues

setValues 則是生成一個 PropertyValuesHolder 數組,在 ProertyValuesHolder#ofObject 方法中調用了該方法,所以 ValueAnimator 可以通過 ofPropertyValuesHolder 對多個屬性動畫。
監聽
AnimatorUpdateListener
public void addUpdateListener(AnimatorUpdateListener listener)
public void removeAllUpdateListeners()
public void removeUpdateListener(AnimatorUpdateListener listener)

ValueAnimator 內部定義了接口監聽動畫的更新,通過在回調方法中調用參數的 ValueAnimator#getAnimatedValue 方法獲取到值動畫的當前進度所對應的值。

4、ObjectAnimator

xml 文件中定義
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueTo="200"
    android:valueType="floatType"
    android:propertyName="y"
    android:repeatCount="1"
    android:repeatMode="reverse"/>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
                android:duration="1000"
                android:repeatCount="1"
                android:repeatMode="reverse">
    <propertyValuesHolder android:propertyName="x" android:valueTo="400"/>
    <propertyValuesHolder android:propertyName="y" android:valueTo="200"/>
</objectAnimator>
<propertyValuesHolder android:propertyName="x" >
    <keyframe android:fraction="0" android:value="800" />
    <keyframe android:fraction=".2"
              android:interpolator="@android:anim/accelerate_interpolator"
              android:value="1000" />
    <keyframe android:fraction="1"
              android:interpolator="@android:anim/accelerate_interpolator"
              android:value="400" />
</propertyValuesHolder>
<propertyValuesHolder android:propertyName="y" >
    <keyframe/>
    <keyframe android:fraction=".2"
              android:interpolator="@android:anim/accelerate_interpolator"
              android:value="300"/>
    <keyframe android:interpolator="@android:anim/accelerate_interpolator"
              android:value="1000" />
</propertyValuesHolder>

使用 objectAnimaor 標簽,ObjectAnimator 繼承自 ValueAnimator 類,屬性基本和 animaor 的定義差不多,只是多出了 android:propertyNameandroid:propertyXName=""android:propertyYName="" 等屬性,這些屬性的作用就是聲明屬性的名稱。
ObjectAnimator 對 ValueAnimator 進行了封裝,一方面在創建對象時綁定了屬性和目標對象,另一方面通過 Interpolator 返回當前的進度,再經過 Evaluator 根據進度計算出具體的值,最后根據屬性拼接 set 函數并反射調用,并將當前值作為參數傳入,實現動畫,不必在監聽器中監聽動畫進度。

代碼創建對象
public static ObjectAnimator ofInt(Object target, String propertyName, int... values)
public static ObjectAnimator ofInt(Object target, String xPropertyName, String yPropertyName,Path path)
public static ObjectAnimator ofArgb(Object target, String propertyName, int... values)
public static <T> ObjectAnimator ofArgb(T target, Property<T, Integer> property,int... values) 
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) 
public static ObjectAnimator ofFloat(Object target, String xPropertyName, String yPropertyName,Path path) 
public static ObjectAnimator ofObject(Object target, String propertyName,TypeEvaluator evaluator, Object... values)
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values) 

ofXXX 方法內部創建了 ObjectAnimator 對象,并調用了 setXXXValues 方法,類似于 ValueAnimator,最終都是調用了 setValues 方法,在方法中給成員變量 PropertyVaulesHolder[] mValues 賦值。
ofPropertyValuesHolder 可以同時操作多個屬性。

5、AnimatorSet

xml 文件定義
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially|together"
    >
</set>

通過 set 標簽定義,android:ordering 屬性表示動畫是按順序執行還是同時執行。

public 方法
public AnimatorSet()
public void setTarget(Object target)
public void setInterpolator(TimeInterpolator interpolator)
public void playTogether(Animator... items)
public void playTogether(Collection<Animator> items)
public void playSequentially(Animator... items)
public void playSequentially(List<Animator> items)
public Builder play(Animator anim)
public void cancel()
public void end()

AnimatorSet 使用了建造者模式,內部定義了一個 Builder 類

public class Builder {
        private Node mCurrentNode;
        Builder(Animator anim) {
            mDependencyDirty = true;
            mCurrentNode = getNodeForAnimation(anim);
        }

        public Builder with(Animator anim) {
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addSibling(node);
            return this;
        }
        public Builder before(Animator anim) {
            mReversible = false;
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addChild(node);
            return this;
        }

        public Builder after(Animator anim) {
            mReversible = false;
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addParent(node);
            return this;
        }

        public Builder after(long delay) {
            // setup dummy ValueAnimator just to run the clock
            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
            anim.setDuration(delay);
            after(anim);
            return this;
        }

    }

Builder 類定義了四個方法來設置動畫的執行順序,當屬性動畫順序執行或指定動畫執行順序時,直接或間接調用 play 方法返回 Builder 對象控制動畫的執行順序。

監聽器

AnimatorSet 內部也定義了監聽器 AnimatorSetListener,類似于 Animator.AnimatorListener 監聽動畫開始、結束、取消、重復。

6、包裝類

ObjectAnimtor 操作的屬性必須要有 setXXX 方法,如果動畫的時候沒有傳遞初始值,還要有 getXXX 方法
針對上述情況,官方文檔給出了三種解決方法:

  1. 給你的對象加上 get 和 set 方法,如果你有權限的話;
  2. 用一個類來包裝原始對象,間接為其提供 get 和 set 方法;
    這個時候目標對象就變成了包裝類的對象,而原始對象成為包裝類的一個成員變量,定義 set 和 get 方法設置或獲取原始對象的屬性值。
  3. 采用 ValueAnimator,監聽動畫過程,自己實現屬性改變;

7、插值器 Interpolator

TimeInterpolator 中文翻譯為時間插值器,它的作用是根據時間百分比來計算當前屬性值改變的百分比,在 android.view.animation 包下面定義了 TimeInterpolator 的子接口 Interpolator,并且已經定義了十幾個實現類:

Interpolator

在 Interpolator 的實現類里面都有一個 public float getInterpolation(float input) 方法,這個方法的參數代表動畫執行時間進度的百分比,取值范圍是0-1,0代表起點,1代表終點,隨著動畫的播放,input 從0到1逐漸變大;
返回值是當前時間點對應的屬性值改變的百分比,這個可以為負值,也可以大于1,為負值表示屬性值小于起始值,大于1表示屬性值超過終點值;

1.AccelerateInterpolator 加速插值器

該類有一個成員變量 mFractor 決定了加速的快慢

加速插值器 fractor = 1.0
加速插值器 fractor = 4
2. DecelerateInterpolator 減速插值器
減速插值器 fractor = 1
3. AccelerateDecelerateInterpolator 加速減速插值器
加速減速插值器
4. LinearInterpolator 線性插值器
5. BounceInterpolator 彈跳插值器
彈跳插值器
6.AnticipateInterpolator 回蕩秋千插值器

該類有一個成員變量 mTension 決定回蕩幅度的大小

回蕩秋千插值器 tension 為默認值2.0
7. AnticipateOvershootInterpolator
8. CycleInterpolator 正弦周期變化插值器
正弦周期變化插值器
9. OvershootInterpolator
tension 為默認值 2.0

通過上面的圖像可以看出,圖形的曲線表示的是屬性值的變化的百分比,0表示屬性起始值,1表示屬性結束值,屬性值主要在0~1之間變化,也可以超出該范圍,曲線的斜率可以表示變化的速率

8、估值器 TypeEvaluator

插值器返回的只是屬性值變化的百分比,還需要使用估值器映射出真正的屬性值。

TypeEvaluator

TypeEvaluator 中之定義了一個方法 evaluate ,三個參數分別為 Interpolator 返回的因子,屬性的起始值和結束值。
系統中已經定義了幾種實現類


IntEvaluator

看 IntEvaluator 類,evaluate 方法的返回值為**初始值 + 百分比 * (結束值 - 初始值)
各種 Evaluator 實現類的區別就在于屬性值的類型的不同,有時候需要自定義 TypeEvaluator

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

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,712評論 25 708
  • Animation Animation類是所有動畫(scale、alpha、translate、rotate)的基...
    四月一號閱讀 1,933評論 0 10
  • 1 背景 不能只分析源碼呀,分析的同時也要整理歸納基礎知識,剛好有人微博私信讓全面說說Android的動畫,所以今...
    未聞椛洺閱讀 2,735評論 0 10
  • 你玩過這款風靡全球的兒童編程游戲?嗎?這一次,編程貓和它的動物朋友們一起踏上了奇妙的編程冒險!趕緊來試試吧! 這是...
    e5489ee10db9閱讀 767評論 0 0
  • 這是今天在有道云筆記記錄的工作的日常: 快遞兩個跟蹤:宇信配件,宇豐證書;為啥不寄特快。 租金:宇信第9期租金 運...
    核攬大千閱讀 253評論 0 0