Android進(jìn)階之光——View體系(View事件分發(fā)機(jī)制)

View與ViewGroup

View是Android所有控件的基類(lèi)
ViewGroup是View的組合丘损,ViewGroup可以包含很多View以及ViewGroup笑撞,而包含的ViewGroup又可以包含View和ViewGroup


View樹(shù)

坐標(biāo)系

Android系統(tǒng)中有兩種坐標(biāo)系:Android坐標(biāo)系和View坐標(biāo)系黄伊。

Android坐標(biāo)系

在Android中泪酱,將屏幕左上角的頂點(diǎn)作為Android坐標(biāo)系的原點(diǎn),這個(gè)原點(diǎn)向右是X軸正方向,向下是Y軸正方向


Android坐標(biāo)系

View坐標(biāo)系

View坐標(biāo)系與Android坐標(biāo)系并不沖突墓阀,兩者是共同存在的


View坐標(biāo)系

View獲取自身的寬高

width=getRight()-getLeft();
height=getBottom()-getTop();

這樣做比較麻煩毡惜,因?yàn)橄到y(tǒng)已經(jīng)向我們提供了獲取View寬高的方法:getHeight()、getWidth()

View自身的坐標(biāo)

  • getTop():獲取View自身頂邊到其父布局頂邊的距離
  • getLeft():獲取View自身左邊到其父布局左邊的距離
  • getRight():獲取View自身右邊到其父布局左邊的距離
  • getBottom():獲取View自身底邊到其父布局頂邊的距離

MotionEvent

  • getX() 獲取點(diǎn)擊事件距離控件左邊的距離斯撮,即視圖坐標(biāo)
  • getY() 獲取點(diǎn)擊事件距離控件頂邊的距離经伙,視圖坐標(biāo)
  • getRawX() 獲取點(diǎn)擊事件距離整個(gè)屏幕左邊的距離 絕對(duì)坐標(biāo)
  • getRawY() 獲取點(diǎn)擊事件距離整個(gè)屏幕頂邊的距離 絕對(duì)坐標(biāo)

View的滑動(dòng)

在處理View的滑動(dòng)時(shí),基本思路都是類(lèi)似的:當(dāng)點(diǎn)擊事件傳到View時(shí)勿锅,系統(tǒng)記下觸摸點(diǎn)的坐標(biāo)帕膜,手指移動(dòng)時(shí)記下移動(dòng)后觸摸的坐標(biāo)并計(jì)算偏移量,并通過(guò)偏移量來(lái)修改View的坐標(biāo)

layout()方法

View進(jìn)行繪制的時(shí)候會(huì)調(diào)用onLayout()來(lái)設(shè)置顯示的位置溢十。
我們自定義一個(gè)view

  • java代碼 CustomView.java
package com.probuing.androidlight.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

public class CustomView extends View {
    private int lastX;
    private int lastY;

    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //獲取手指觸摸點(diǎn)的橫坐標(biāo)和縱坐標(biāo)
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計(jì)算移動(dòng)距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //調(diào)用layout方法重新繪制位置
                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                break;
        }
        return true;
    }
}
  • 隨后在布局文件中引用自定義View
<?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"
    tools:context=".activity.ViewLSNActivity">

    <com.probuing.androidlight.view.CustomView
        android:id="@+id/customview"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_margin="50dp"
        android:background="@android:color/holo_red_light"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

offsetLeftAndRight()和offsetTopAndBottom()

其實(shí)也可以用這兩種方法來(lái)替換layout()方法

  • java代碼
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        //獲取手指觸摸點(diǎn)的橫坐標(biāo)和縱坐標(biāo)
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計(jì)算移動(dòng)距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                //調(diào)用layout方法重新繪制位置
//                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                break;
        }
        return true;
    }

LayoutParams(改變布局參數(shù))

LayoutParams主要保存了一個(gè)View的布局參數(shù)垮刹,因此我們可以通過(guò)LayoutParams來(lái)改變View的布局參數(shù)從而達(dá)到改變View位置的效果
因?yàn)槲覀冏远x的View的父控件是LinearLayout,所以我們使用了LinearLayout.LayoutParams张弛。

  • java代碼
  @Override
    public boolean onTouchEvent(MotionEvent event) {
        //獲取手指觸摸點(diǎn)的橫坐標(biāo)和縱坐標(biāo)
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //計(jì)算移動(dòng)距離
                int offsetX = x - lastX;
                int offsetY = y - lastY;
/*                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);*/
                //調(diào)用layout方法重新繪制位置
//                layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft()+offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                break;
        }
        return true;
    }

動(dòng)畫(huà)

我們也可以采用View動(dòng)畫(huà)來(lái)移動(dòng)

  • res目錄創(chuàng)建anim目錄 并創(chuàng)建translate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="1000"
        android:fromXDelta="0"
        android:toXDelta="300" />
</set>

View動(dòng)畫(huà)不能改變View的位置參數(shù)荒典。但是屬性動(dòng)畫(huà)可以解決位置問(wèn)題

   @Override
    protected void onStart() {
        super.onStart();
        ObjectAnimator.ofFloat(customview,"translationX",0,300).setDuration(1000)
                .start();
    }

scrollTo與scrollBy

scrollTo(x,y)表示移動(dòng)到一個(gè)具體的坐標(biāo)點(diǎn)。而scrollBy(dx,dy)則表示移動(dòng)的增量為dx吞鸭、dy寺董。

屬性動(dòng)畫(huà)

隨著Android3.0屬性動(dòng)畫(huà)的提出,View之前的動(dòng)畫(huà)帶來(lái)的問(wèn)題刻剥,例如響應(yīng)事件位置依然在動(dòng)畫(huà)發(fā)生前的地方遮咖,不具備交互性等也隨之解決。

ObjectAnimator

ObjectAnimator是屬性動(dòng)畫(huà)最重要的類(lèi)透敌,創(chuàng)建一個(gè)ObjectAnimator只需要通過(guò)其靜態(tài)工廠類(lèi)直接返還一個(gè)ObjectAnimator對(duì)象盯滚。參數(shù)包括一個(gè)對(duì)象和對(duì)象的屬性名字,這個(gè)屬性必須有g(shù)et和set方法

ObjectAnimator.ofFloat(customview,"translationX",0,300)
        .setDuration(1000)
        .start();

下面就是一些常用的可以直接使用的屬性動(dòng)畫(huà)的屬性值

  • translationX和translationY:用來(lái)沿著X軸或Y軸進(jìn)行平移
  • rotation、rotationX酗电、rotationY:用來(lái)圍繞View的支點(diǎn)進(jìn)行旋轉(zhuǎn)
  • PrivotX和PrivotY:控制View對(duì)象的支點(diǎn)位置魄藕,圍繞這個(gè)支點(diǎn)進(jìn)行旋轉(zhuǎn)和縮放變換處理。
  • alpha:透明度撵术,默認(rèn)是1,0是代表完全透明
  • x和y:描述View對(duì)象在其容器中的最終位置

ValueAnimator

ValueAnimator不提供任何動(dòng)畫(huà)效果背率,它是一個(gè)數(shù)值發(fā)生器,用來(lái)產(chǎn)生一定的有規(guī)律的數(shù)字嫩与。

動(dòng)畫(huà)的監(jiān)聽(tīng)

完整的動(dòng)畫(huà)具有start寝姿、repeat、end划滋、cancel這4個(gè)過(guò)程

 @Override
    protected void onStart() {
        super.onStart();
        ObjectAnimator translationX = ObjectAnimator.ofFloat(customview, "translationX", 0, 300).setDuration(1000);
        translationX.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                
            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        translationX.start();
    }

一般情況下 我們比較常用的是onAnimationEnd事件饵筑,Android也提供了AnimatorListenterAdapter來(lái)讓我們選擇必要的事件進(jìn)行監(jiān)聽(tīng)

 @Override
    protected void onStart() {
        super.onStart();
        ObjectAnimator translationX = ObjectAnimator.ofFloat(customview, "translationX", 0, 300).setDuration(1000);
        translationX.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                Toast.makeText(ViewLSNActivity.this, "end", Toast.LENGTH_SHORT).show();
            }
        });
        translationX.start();
    }

組合動(dòng)畫(huà)——AnimatorSet

AnimatorSet類(lèi)提供了一個(gè)play()方法,如果我們向這個(gè)方法中傳入一個(gè)Animator對(duì)象处坪,將會(huì)返回一個(gè)AnimatorSet.Builder的實(shí)例根资,每次調(diào)用方法時(shí)都會(huì)返回Builder自身用于構(gòu)建

  • after(Animator anim)將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)后執(zhí)行
  • after(long delay)將現(xiàn)有動(dòng)畫(huà)延遲指定毫秒后執(zhí)行
  • before(Animator anim)將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)之前執(zhí)行
  • with(Animator anim)將現(xiàn)有動(dòng)畫(huà)和傳入的動(dòng)畫(huà)同時(shí)執(zhí)行
    private void animBuilder() {
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(customview, "translationX", 0.0f, 200.0f, 0f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(customview, "scaleX", 1.0f, 2.0f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(customview, "rotationX", 0.0f, 90.0f, 0.0f);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(3000);
        animatorSet.play(animator1).with(animator2).after(animator3);
        animatorSet.start();
    }

組合動(dòng)畫(huà)——PropertyValuesHolder

除了使用AnimatorSet類(lèi)之外架专,還可以使用PropertyValuesHolder類(lèi)來(lái)實(shí)現(xiàn)組合動(dòng)畫(huà)。使用PropertyValuesHolder類(lèi)只能是多個(gè)動(dòng)畫(huà)一起執(zhí)行玄帕。使用PropertyValuesHolder只能是多個(gè)動(dòng)畫(huà)一起執(zhí)行部脚。得結(jié)合ObjectAnimator.ofPropertyValuesHolder()

   private void propertyValuesHolder() {
        PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
        PropertyValuesHolder valueHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0f);
        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(customview, valuesHolder1, valueHolder2);
        objectAnimator.setDuration(2000).start();
    }

在XML中使用屬性動(dòng)畫(huà)

在res中新建animator目錄(屬性動(dòng)畫(huà)必須放在animator目錄下),新建scale.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType"
    >
</objectAnimator>

在程序中引用XML定義得屬性動(dòng)畫(huà)

  private void startXMLAnimator() {
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scale);
        animator.setTarget(customview);
        animator.start();
    }

View的事件分發(fā)機(jī)制

先來(lái)看看Activity組成

Activity的構(gòu)成

一個(gè)Activity包含一個(gè)Window對(duì)象裤纹,這個(gè)對(duì)象是由PhoneWindow實(shí)現(xiàn)的委刘。PhoneWindow將DecorView作為整個(gè)應(yīng)用窗口的根View。而這個(gè)DecorView又將屏幕劃分為兩個(gè)區(qū)域:一個(gè)是TitleView另一個(gè)是ContentView鹰椒。我們平常做應(yīng)用所寫(xiě)的布局就是展示在ContentView中的

解析View的事件分發(fā)機(jī)制

當(dāng)我們點(diǎn)擊屏幕時(shí)锡移,就產(chǎn)生了點(diǎn)擊事件,這個(gè)事件被封裝成了一個(gè)類(lèi):MotionEvent吹零,而當(dāng)這個(gè)MotionEvent產(chǎn)生后罩抗,那么系統(tǒng)就會(huì)將這個(gè)MotionEvent傳遞給View的層級(jí)。MotionEvent在View中的層級(jí)傳遞過(guò)程就是點(diǎn)擊事件的分發(fā)
點(diǎn)擊事件有3個(gè)重要的方法

  • dispatchTouchEvent(MotionEvent ev):用于事件的分發(fā)
  • onInterceptTouchEvent(MotionEvent ev):用于事件的攔截灿椅,在dispatchTouchEvent中調(diào)用
  • onTouchEvent(MotionEvent ev):用來(lái)處理點(diǎn)擊事件套蒂,在dispatchTouchEvent()方法中進(jìn)行調(diào)用

View的事件分發(fā)機(jī)制

當(dāng)點(diǎn)擊事件產(chǎn)生后,事件首先會(huì)傳遞給當(dāng)前的Activity茫蛹,這會(huì)調(diào)用Activity的dispatchTouchEvent()方法(也就是交由Activity中的PhoneWindow來(lái)完成操刀,然后PhoneWindow再把事件處理工作交給DecorView,然后再由DecorView將事件處理工作交給根ViewGroup)

注意:一個(gè)完整的事件的序列是以DOWN開(kāi)始以UP結(jié)束

  • 如果ViewGroup要攔截事件的時(shí)候婴洼,那么后續(xù)的事件序列都會(huì)交給它處理骨坑,而不用再調(diào)用onInterceptTouchEvent()方法了。

點(diǎn)擊事件分發(fā)的傳遞規(guī)則

偽代碼表示

public boolean dispatchTouchEvent(MotionEvent ev){
boolean result = false;
if(onInterceptTouchEvent(ev)){
           result=super.onTouchEvent(ev)
  }else{
          result=child.dispatchTouchEvent(ev)
}
return result;
}

事件自上而下傳遞過(guò)程

當(dāng)點(diǎn)擊事件產(chǎn)生后會(huì)由Activity來(lái)處理柬采,傳遞給PhoneWindow欢唾,再傳遞給DecorView,最后傳遞給頂層的ViewGroup粉捻。
對(duì)于根ViewGroup礁遣,點(diǎn)擊事件首先傳遞給它的dispatchTouchEvent(),該ViewGroup的onInterceptTouchEvent()

  • 如果返回true肩刃,則表示要攔截這個(gè)事件祟霍,這個(gè)事件就會(huì)交給它的onTouchEvent()方法處理
  • 如果返回false,則表示不攔截這個(gè)事件盈包,這個(gè)事件會(huì)交給子元素的dispatchTouchEvent()處理
    如此反復(fù)下去沸呐,如果傳遞給底層的View,View是沒(méi)有子View的呢燥,就會(huì)調(diào)用這個(gè)View的dispathTouchEvent()方法崭添,一般最終會(huì)調(diào)用View的onTouchEvent()

事件自下而上傳遞過(guò)程

當(dāng)點(diǎn)擊事件傳遞給底層的View時(shí),如果底層的View的onTouchEvent()方法返回true叛氨,則表示事件由底層的View消耗并處理呼渣。
如果返回false則表示該View不做處理根暑,事件會(huì)傳遞給父View的onTouchEvent()處理,如果父View的onTouchEvent()返回false表示父View也不處理徙邻,則繼續(xù)傳遞給該父View的父View處理,如此反復(fù)


事件分發(fā)機(jī)制
  • Activity
    • 沒(méi)有onInterceptTouchEvent方法
    • 只有dispatchTouchEvent畸裳、onTouchEvent方法
  • ViewGroup
    • 有 onInterceptTouchEvent缰犁、dispatchTouchEvent、onTouchEvent方法
  • View
    • 沒(méi)有 onInterceptTouchEvent方法

事件分發(fā)流程

Activity

dispatchTouchEvent:

  • 返回值true/false:事件由自己消費(fèi)
  • 返回值super:交由子ViewGroup的dispatchTouchEvent處理

ViewGroup

dispatchTouchEvent:
  • 返回值true:事件由自己消費(fèi)
  • 返回值false:交由父View的onTouchEvent()處理
  • 返回值super:傳遞給自己的onInterceptTouchEvent()進(jìn)行分發(fā)
onInterceptTouchEvent:
  • 返回值true:表示攔截事件怖糊,交由自己的onTouchEvent處理
  • 返回值false/super:表示不攔截事件帅容,交由子View的dispatchTouchEvent()處理
onTouchEvent:
  • 返回值true:表示事件自己處理
  • 返回值false/super:將事件交由父onTouchEvent處理

View

dispatchTouchEvent:
  • 返回值為true:事件由自己消費(fèi)
  • 返回值為false:事件交由父View的onTouchEvent處理
  • 返回值為super:交由自己的onTouchEvent處理
onTouchEvent
  • 返回值true:事件自己消費(fèi)
  • 返回值false、super:事件交由父view的onTouchEvent處理伍伤,直至傳遞到Activity的onTouchEvent()

OnTouchListener和onClickListener執(zhí)行順序

當(dāng)一個(gè)View需要處理事件時(shí)并徘,如果設(shè)置了OnTouchListener,那么OnTouchListener中的OnTouch會(huì)被回調(diào)扰魂。

  • 如果onTouch返回false麦乞,則當(dāng)前View的onTouchEvent方法會(huì)被調(diào)用
  • 如果onTouch返回true,那么onTouchEvent方法將不會(huì)調(diào)用
    由此可看出onTouchListener要比onTouchEvent優(yōu)先級(jí)高
    在onTouchEvent方法中劝评,如果當(dāng)前設(shè)置的有onClickListener那么onClick就會(huì)被調(diào)用姐直,由此可以看出onClick的優(yōu)先級(jí)最低,處于事件傳遞的尾端

onTouch->onTouchListener->onTouchEvent->onClick->onClickListener

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蒋畜,一起剝皮案震驚了整個(gè)濱河市声畏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姻成,老刑警劉巖插龄,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異科展,居然都是意外死亡均牢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)辛润,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)膨处,“玉大人,你說(shuō)我怎么就攤上這事砂竖≌娲唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵乎澄,是天一觀的道長(zhǎng)突硝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)置济,這世上最難降的妖魔是什么解恰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任锋八,我火速辦了婚禮,結(jié)果婚禮上护盈,老公的妹妹穿的比我還像新娘挟纱。我一直安慰自己,他們只是感情好腐宋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布紊服。 她就那樣靜靜地躺著,像睡著了一般胸竞。 火紅的嫁衣襯著肌膚如雪欺嗤。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天卫枝,我揣著相機(jī)與錄音煎饼,去河邊找鬼。 笑死校赤,一個(gè)胖子當(dāng)著我的面吹牛吆玖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播马篮,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼衰伯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了积蔚?” 一聲冷哼從身側(cè)響起意鲸,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尽爆,沒(méi)想到半個(gè)月后怎顾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡漱贱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年槐雾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幅狮。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡募强,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出崇摄,到底是詐尸還是另有隱情擎值,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布逐抑,位于F島的核電站鸠儿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜进每,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一汹粤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧田晚,春花似錦嘱兼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至泞莉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間船殉,已是汗流浹背鲫趁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留利虫,地道東北人挨厚。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像糠惫,于是被迫代替她去往敵國(guó)和親疫剃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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