【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阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • Animation Animation类是所有动画(scale、alpha、translate、rotate)的基...
    四月一号阅读 1,868评论 0 10
  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,579评论 0 9
  • 你玩过这款风靡全球的儿童编程游戏�吗?这一次,编程猫和它的动物朋友们一起踏上了奇妙的编程冒险!赶紧来试试吧! 这是...
    e5489ee10db9阅读 704评论 0 0
  • 这是今天在有道云笔记记录的工作的日常: 快递两个跟踪:宇信配件,宇丰证书;为啥不寄特快。 租金:宇信第9期租金 运...
    核揽大千阅读 220评论 0 0