Android事件分發(fā)機制的探索與發(fā)現(xiàn)之View篇

版權(quán)聲明:本文來自門心叼龍的博客苗踪,屬于原創(chuàng)內(nèi)容畜普,轉(zhuǎn)載請注明出處:https://blog.csdn.net/geduo_83/article/details/90145083

github源碼下載地址:https://github.com/geduo83/android-touch-event
Android事件分發(fā)機制的探索與發(fā)現(xiàn)之View篇
Android事件分發(fā)機制的探索與發(fā)現(xiàn)之ViewGroup篇
Android事件分發(fā)機制的探索與發(fā)現(xiàn)之Activity篇
Android事件分發(fā)機制的探索與發(fā)現(xiàn)之總結(jié)篇
Android事件分發(fā)機制在實戰(zhàn)開發(fā)中的應(yīng)用之一
Android事件分發(fā)機制在實戰(zhàn)開發(fā)中的應(yīng)用之二

關(guān)于Android事件傳遞機制的文章在前面也零零散散的寫過兩篇砸脊,當(dāng)時也是時間有限涡匀,也沒有過多的去完善匆匆就發(fā)出去了拴事。

因為Android事件分發(fā)機制是整個Android系統(tǒng)的難點也是重點,說它是難點是因為觸摸事件的流轉(zhuǎn)流程錯綜復(fù)雜弓摘,前一陣子在有個技術(shù)群里面很多人都說焚鹊,事件分發(fā)這塊自己也是學(xué)習(xí)了好多次,但是都是過一陣子韧献,對事件的流轉(zhuǎn)流程又忘了末患,記不住,學(xué)了又忘锤窑,忘了又學(xué)璧针,出現(xiàn)這種情況就是對事件流轉(zhuǎn)流程理解不深刻,對書上的流程圖死記硬背導(dǎo)致的渊啰,有些書上甚至出現(xiàn)流程錯誤的問題探橱,真是誤人子弟。


這是有些書上的事件分發(fā)流程圖

這種圖流程圖誰能記得住绘证,而且還有一張View的我就不貼圖了隧膏,正是有些作者的不負(fù)責(zé)任,讓很多人走了不少的彎路嚷那,這就是研究問題的方法有問題胞枕,就好比有的老師可能半個小時就把這個問題將清楚,而有的老師可能花好幾個小時把這個問題還講不明白魏宽,就是因為他們沒有透過現(xiàn)象看到問題的本質(zhì)所在腐泻,本來問題就比較復(fù)雜决乎,再復(fù)雜的問題也是有規(guī)律可循的。

說它是重點贫悄,我們知道在功能機時代瑞驱,我們與手機交互主要是依靠機械鍵盤來進(jìn)行輸入,而在智能機時代窄坦,觸摸屏技術(shù)的革命,人與手機的交互都變得那么的簡單凳寺,輕輕的點擊手指就能完成各種各種的復(fù)雜操作鸭津,從簡單的點擊一個按鈕,界面切換的左滑右滑操作肠缨,再到瀏覽新聞看更多內(nèi)容的上滑下滑操作逆趋,這樣的操作可以說在現(xiàn)在的智能手機上無處不在,這一切的操作的背后晒奕,就是整個Android操作系統(tǒng)的事件分發(fā)機制闻书。

所以,也不是一兩篇文章就能講清楚的脑慧,所以今天我申請了一個關(guān)于事件分發(fā)的專題魄眉,準(zhǔn)備通過一系列的文章來講解View的事件分發(fā)機制。網(wǎng)上關(guān)于事件分發(fā)的文章可以說都是鋪天蓋地闷袒,我看大部分都是講源碼分析坑律,有的有理論沒實戰(zhàn),有的只講結(jié)果不講分析囊骤,有的是講了View晃择、ViewGroup,而沒有不講Activity也物。

說到事件分發(fā)宫屠,我們就是要搞清楚事件分發(fā)的流程。事件分發(fā)滑蚯,可以拆開為兩部分浪蹂,一個是事件,一個是分發(fā)膘魄。何為事件乌逐?當(dāng)你用的手指在屏幕上點擊了一下,滑動了一下创葡,有幾個事件浙踢?都是什么事件?

觸摸事件類型

觸摸事件對應(yīng)的是MotionEvent,事件主要有如下三種

  • ACTION_DOWN:用戶手指按下的操作灿渴,標(biāo)志一次觸摸事件的開始
  • ACITON_MOVE:用戶在手指按下屏幕之后洛波,在松開之前胰舆,如果移動的距離超過一定的閾值,就會被認(rèn)定為ACTION_MOVE操作
  • ACTION_UP:用戶手指抬起的操作蹬挤,標(biāo)志一次觸摸事件的結(jié)束

觸摸事件傳遞

講完了事件缚窿,接下來我們說分發(fā),事件的分發(fā)焰扳,實質(zhì)就是講事件的傳遞倦零,事件的傳遞分為三個階段:

  • 分發(fā):dispatchTouchEvent(MotionEvent event),在Android系統(tǒng)中吨悍,所有的觸摸事件都是通過這個方法來分發(fā)的
  • 攔截:onInterceptTouchEvent扫茅,這個方法只有ViewGroup中存在
  • 消費:onTouchEvent

觸摸事件的相關(guān)類

在android系統(tǒng)中,擁有事件傳遞處理能力的類有三個

  • Activity:擁有dispatchTouchEvent和onTouchEvent方法
  • View:和Activity一樣同時擁有dispatchTouchEvent和onTouchEvent方法
  • ViewGourp:擁有dispatchTouchEvent和onTouchEvent方法育瓜,在加上一個攔截方法onInterceptTouchEvent

View和ViewGourp之間的關(guān)系

View是ViewGourp的父類葫隙,一個ViewGroup中可以擁有多個View和ViewGourp,下面谷歌android API 文檔的一個截圖躏仇,可以清楚的看到他們之間的一個繼承關(guān)系
View和ViewGroup關(guān)系

前面我在講事件傳遞的時候恋脚,主要講了三個方法,事件分發(fā)dispathTouchEvent方法焰手,事件攔截的onInterecptTouchEvent方法和事件消費的onTouch的onTouchEvent方法糟描。


dispathTouchEvent方法
onTouch方法
onInterceptTouchEvent方法

以上就是三個關(guān)于觸摸事件的處理方法,我們通過谷歌官方api文檔的截圖我們不難發(fā)現(xiàn)册倒,他們都是返回的是一個boolean類型的常量蚓挤,無外乎要么返回true,要么返回false驻子,還有一種可能就是調(diào)用父類的同名方法灿意,通過接口文檔我們得知dispathTouchEvent返回true表示該事件被View處理了,反之返回false就是不處理崇呵,不處理那么事件最后交給誰了缤剧?onTouchEvent方法返回true這是表示被消費掉了,反之亦然域慷,那么調(diào)用它父類的同名方法結(jié)果又會怎么樣荒辕?關(guān)于攔截方法如果返回true表示被攔截掉了,那么這個事件是交給了自己的onTouchEvent方法了嗎犹褒?如果onTouchEvent返回了false不消費掉這給事件又會交給誰去處理抵窒?等等一系列的疑問。

但是不管怎么樣我們通過官方文檔我們可以得到一個結(jié)論就是:不同的返回值會導(dǎo)致事件的傳遞流程發(fā)生很大的變化叠骑,我們想了李皇,我們通過不斷的修改這些方法的返回值,并查看日志記錄宙枷,我們就可以清楚的看到每一種情況觸摸事件的處理流程掉房。
為此我準(zhǔn)備了兩個自定義控件MyLayout和MyButton茧跋,并復(fù)寫他們的dispathchTouchEvent方法和onTouchEvent方法,以及onInterceptTouEvent方法卓囚,不斷的修改他們的返回值瘾杭,來跟蹤每個事件的處理流程。

準(zhǔn)備工作:

  • 自定義ViewGroup MyLayout.java
package com.zjx.vcar.test.view;
public class MyLayout extends LinearLayout {
    public static final String TAG = "MYTAG";
    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyLayout dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyLayout onInterceptTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MyLayout onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return super.onTouchEvent(event);
    }
}
  • 自定義View MyButton.java
@SuppressLint("AppCompatCustomView")
public class MyButton extends Button {
    public static final String TAG = "MYTAG";
    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyButton dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MyButton onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return super.onTouchEvent(event);
    }
}
  • 創(chuàng)建MainActivty.java的布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<com.android.touchevent.view.MyLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:background="#FF00FF"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <com.android.touchevent.view.MyButton
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:text="點擊測試"
        android:background="#00FF00"
        />
</com.android.touchevent.view.MyLayout>
  • 創(chuàng)建MainActivity.java
public class MainActivity extends AppCompatActivity {
    public static String TAG = "MYTAG";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MainActivity dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MainActivity onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return super.onTouchEvent(event);
    }
}

好了哪亿,截止目前測試的準(zhǔn)備工作就做好了粥烁,我們看下頁面效果,MyLayout設(shè)置了紫色背景锣夹,MyButon設(shè)置了綠色背景


33.png

本文我們只分析MyButton的處理流程页徐,MyLayout和Activity的流程我們放在后面的章節(jié)進(jìn)行介紹,這樣是為了避免文章過長银萍,反而不利于大家的學(xué)習(xí)。

MyButton的onTouchEvent方法

  • 情況1:我們onTouchEvent調(diào)用父類的同名方法
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MyButton onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return super.onTouchEvent(event);
    }
  • 點擊測試按鈕測試
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton onTouchEvent start:ACTION_DOWN
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_MOVE
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_MOVE
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_MOVE
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_MOVE
V/MYTAG: MyButton onTouchEvent start:ACTION_MOVE
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_UP
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyButton onTouchEvent start:ACTION_UP

MyButton 的onTouchEvent方法依次接受到了三個事件:ACTION_DOWN,ACTION_MOVE,ACTION_MOVE

  • 情況2:我們onTouchEvent返回true
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MyButton onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return true;
    }
  • 點擊測試按鈕測試
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton onTouchEvent start:ACTION_DOWN
-----------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_UP
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyButton onTouchEvent start:ACTION_UP

通過測試打印的log我們不難發(fā)現(xiàn)恤左,調(diào)用父類的同名方法和返回true其結(jié)果是一樣的

  • 情況3:返回false
 @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v(TAG,"MyButton onTouchEvent start:"+MotionEventUtil.getMotionEventName(event));
        return false;
    }

點擊測試結(jié)果:

V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton onTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onTouchEvent start:ACTION_DOWN
V/MYTAG: MainActivity onTouchEvent start:ACTION_DOWN
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_MOVE
V/MYTAG: MainActivity onTouchEvent start:ACTION_MOVE
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_UP
V/MYTAG: MainActivity onTouchEvent start:ACTION_UP

我們驚奇的發(fā)現(xiàn)如果返回false贴唇,MyButton的onTouchEvent方法將事件傳遞給MyLayout的onTourchEvent方法了,也就是事件回傳了飞袋,如果MyLayout不消費的話戳气,將繼續(xù)回傳,直到MainActivity的onTouchEvent方法巧鸭,后續(xù)的ACTION_MOVE瓶您,ACTION_UP,就不在分發(fā)了纲仍,MainActivity的onTouchEvent就直接消費掉了呀袱。

MyButton的dispatchTouchEvent方法

  • 情況1:dispatchTouchEvent調(diào)用父類的同名方法
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyButton dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return super.dispatchTouchEvent(ev);
    }

點擊測試結(jié)果我們不用測試就能猜得到了,因為我們測試它的onTouchEvent方法的時候郑叠,dispatchTouchEvent方法默認(rèn)就調(diào)用的是父類的同名方法super.dispatchTouchEvent(ev)夜赵,我們通過觀察打印日志不難發(fā)現(xiàn),MyButton的dispatchTouchEvent方法執(zhí)行完畢乡革,就把點擊事件傳遞給自己的onTouchEvent方法了寇僧,也就是說MyButton沒有子view了,就把事件分發(fā)給自己onTouchEvent方法了

  • 情況2:返回true
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyButton dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return true;
    }

點擊測試按鈕

V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_DOWN
------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_UP
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_UP
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_UP

返回true沸版,點擊事件被MyButton的dispatchTouchEvent方法自行消費掉了

  • 情況3:返回false
@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.v(TAG,"MyButton dispatchTouchEvent start:"+MotionEventUtil.getMotionEventName(ev));
        return false;
    }

點擊測試

V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onInterceptTouchEvent start:ACTION_DOWN
V/MYTAG: MyButton dispatchTouchEvent start:ACTION_DOWN
V/MYTAG: MyLayout onTouchEvent start:ACTION_DOWN
V/MYTAG: MainActivity onTouchEvent start:ACTION_DOWN
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_MOVE
V/MYTAG: MainActivity onTouchEvent start:ACTION_MOVE
---------------------------------------------------------
V/MYTAG: MainActivity dispatchTouchEvent start:ACTION_UP
V/MYTAG: MainActivity onTouchEvent start:ACTION_UP

當(dāng)MyButton的dispatchTouchEvent方法返回false的時候嘁傀,點擊事件是一路回傳,直到到達(dá)MainActivity onTouchEvent的方法才算結(jié)束

好了视粮,直到現(xiàn)在我們對MyButton的dispatchTouchEvent方法和onTouchEvent方法就徹底分析完了细办,我們不難得出結(jié)論:觸摸事件是按照View樹的嵌套層次由內(nèi)到外依次進(jìn)行傳遞,直到到達(dá)最內(nèi)層的子View的onTouchEvent方法馒铃,如果onTouchEvent方法返回true或者調(diào)用了父類的同名方法蟹腾,表示該事件被消費掉了痕惋,如果返回了false則該觸摸事件會回傳回去,直到到達(dá)最外層的MainActivity的onTouchEvent方法娃殖,對于dispatchTouchEvent方法如果調(diào)用的是父類的同名方法則觸摸事件會分發(fā)給自己的onTouchEvent方法值戳,如果返回了true則表示該方法被自行消費掉了,如果返回了false表示該觸摸事件會一層一層的回傳給自己父View的onTouchEvent方法炉爆,直到到達(dá)MainActivity的onTouchEvent方法才算結(jié)束堕虹,此后的其他事件如ACTION_MOVE和ACTION_DOWN事件直接就被MainActivity的onTouchEvent方法消費掉了,而不會傳遞給MyLayout了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芬首,一起剝皮案震驚了整個濱河市赴捞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郁稍,老刑警劉巖赦政,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耀怜,居然都是意外死亡恢着,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門财破,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掰派,“玉大人,你說我怎么就攤上這事左痢∶蚁郏” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵俊性,是天一觀的道長略步。 經(jīng)常有香客問我,道長磅废,這世上最難降的妖魔是什么纳像? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮拯勉,結(jié)果婚禮上竟趾,老公的妹妹穿的比我還像新娘。我一直安慰自己宫峦,他們只是感情好岔帽,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著导绷,像睡著了一般犀勒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天贾费,我揣著相機與錄音钦购,去河邊找鬼。 笑死褂萧,一個胖子當(dāng)著我的面吹牛押桃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播导犹,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼唱凯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谎痢?” 一聲冷哼從身側(cè)響起磕昼,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎节猿,沒想到半個月后票从,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡滨嘱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年纫骑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片九孩。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖发框,靈堂內(nèi)的尸體忽然破棺而出躺彬,到底是詐尸還是另有隱情,我是刑警寧澤梅惯,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布宪拥,位于F島的核電站,受9級特大地震影響铣减,放射性物質(zhì)發(fā)生泄漏她君。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一葫哗、第九天 我趴在偏房一處隱蔽的房頂上張望缔刹。 院中可真熱鬧,春花似錦劣针、人聲如沸校镐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸟廓。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間引谜,已是汗流浹背牍陌。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留员咽,地道東北人毒涧。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像骏融,于是被迫代替她去往敵國和親链嘀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

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