是Android的自定義View-進階知識-自定義View的創(chuàng)建(構造函數(shù))

前言

對于Android程序員來說,自定義View是繞不過的話題,作為Android終端,除了一些后臺應用涝婉,大部分的應用最直接面對用戶的還是我們的界面,界面的美觀和流暢性某種程度上決定了用戶的留存糯景。

同時嘁圈,自定義View也符合封裝的思想,將通用的功能控件進行自定義彌補官方控件的使用不便蟀淮,這將提升我們的開發(fā)效率最住。

除了便利性外,當然追求各類復雜View的自定義怠惶,也是我們作為Android程序員的綜合素質的體現(xiàn)(才不是炫技呢)涨缚。

自定義View的分類

Android 官方將自定義View分為三類:

  • 繼承已有控件
  • 組合控件
  • 完全自定義控件

繼承已有控件

如果需要實現(xiàn)的自定義View的功能與已有的控件功能類似,可以直接通過拓展已有控件的方式進行控件的自定義。

實現(xiàn)這類自定義View需要對需要繼承的已有控件的相關屬性和Api有所了解脓魏,當然兰吟,可以通過完全自定義View的方式來實現(xiàn)自定義,但是從那些已封裝的控件開始會大大提高開發(fā)的效率茂翔。

組合控件

當有一些較復雜的自定義View需要實現(xiàn)的時候混蔼,組合控件是一個較好的選擇,不會過于復雜又較為簡單珊燎,一般是繼承某一種布局來組合已有的控件惭嚣。

這種實現(xiàn)自定義View的方式最為常用,在日常的開發(fā)過程中悔政,經(jīng)常會出現(xiàn)需要封裝一些組件的需求晚吞,這時候組合控件就一個很好的選擇。

完全自定義控件

當要進行一些不規(guī)則谋国,極度復雜的控件封裝時槽地,就需要通過完全自定義的方式來實現(xiàn)View,通過實現(xiàn)提供的各種方法來實現(xiàn)芦瘾。

一般的完全自定義控件會出現(xiàn)在現(xiàn)有控件無法實現(xiàn)的情況下捌蚊,常見的是一些有著復雜形狀的UI或是需要重新定義的布局模式,才會用到完全自定義控件旅急。

自定義View的基本步驟(本文介紹前兩個步驟)

不同方式實現(xiàn)的自定義View它們的基本實現(xiàn)套路大同小異的逢勾,一般會經(jīng)過以下幾個步驟:

  • 繼承已有的View或是ViewGroup,實現(xiàn)構造方法
  • 自定義屬性
  • 測量
  • 繪制
  • 處理交互事件
  • 其它一些功能上的邏輯處理

本文會優(yōu)先介紹前兩個步驟藐吮,它們可以被稱為自定義View的創(chuàng)建

繼承已有的View或是ViewGroup,實現(xiàn)構造方法

構造方法是每一個類的入口逃贝,View也不例外谣辞,為了更加直觀地展現(xiàn)View的構造函數(shù),這里給出繼承自FrameLayout的構造方法(本文所用自定義View實例基于FrameLayout):

class CustomCreateView : FrameLayout {

    // 第一個構造函數(shù)
    constructor(context: Context) : super(context) {

    }

    // 第二個構造函數(shù)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {

    }

    // 第三個構造函數(shù)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {

    }

    // 第四個構造函數(shù)
    // 在 API 21 以上才能使用
    constructor(
        context: Context,
        attrs: AttributeSet,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes) {

    }
}

一般地沐扳,通過代碼實例化一個View對象會調用第一個構造函數(shù)泥从,通過xml定義一個View會調用第二個構造函數(shù),系統(tǒng)是不會直接調用第三和第四個構造函數(shù)的沪摄,那它們有什么用呢躯嫉?

在展開構造函數(shù)之前,我們先要來了解一下自定義屬性相關的概念杨拐,也就是第三和第四個構造函數(shù)所多出來的那幾個參數(shù)內容有什么含義祈餐?

自定義屬性

View的屬性幫助我們可以快速實現(xiàn)我們所需要的功能,除了使用系統(tǒng)所提供給我們的那些View的屬性哄陶,我們還可以自定義相關的屬性帆阳,來實現(xiàn)原本所無法實現(xiàn)的功能。

實現(xiàn)步驟

定義自定義屬性

在res/values創(chuàng)建attrs.xml文件屋吨,在<declare-styleable>標簽下新建自定義屬性蜒谤,如下:

<resources>
   <declare-styleable name="CustomCreateView">
       <attr name="showText" format="boolean" />
       <attr name="labelPosition" format="enum">
           <enum name="left" value="0"/>
           <enum name="right" value="1"/>
       </attr>
   </declare-styleable>
</resources>

在代碼中山宾,每一個 <attr> 屬性都代表了一個自定義屬性,可以看到每個 <attr> 中都包含了兩個屬性:

  • name —— 在xml引用控件設置屬性的名字
  • format —— 屬性值的類型
關于format的屬性類型的設置

android在format中預設了很多屬性的類型滿足日常開發(fā)的屬性類型的需求鳍徽,下面來詳細了解一下具體有哪些屬性類型

屬性類型 屬性類型說明
color 顏色值资锰,一般為顏色的16進制值,例如:#000000
dimension 尺寸值阶祭,用于設置控件大小或是字體大小绷杜,例如:16dp、18sp
integer 整形數(shù)值
string 字符串類型
boolean 布爾值胖翰,當屬性需要做true或false判斷的時候使用
enum 枚舉類型接剩,屬性值只能選擇一個值,子項的value要設置為整形數(shù)萨咳,具體設置方法見上面的代碼
flags 位或運算懊缺,屬性值可以選擇多個值,子項的value要設置為整形數(shù)培他,一般設置為2的倍數(shù)來進行區(qū)分(具體原因會在獲取屬性值的部分給出)鹃两,具體設置方法同enum,將內層標簽改為<flag>
float 浮點型數(shù)值
fraction 百分數(shù)
reference 資源ID

在這些屬性值中舀凛,enum和flags較為容易搞混俊扳,這里拿出來強調一下:

  • enum —— 屬性值只能選擇一個值,例如LinearLayout的orientation屬性
  • flags —— 屬性值可以選擇多個值猛遍,例如gravity屬性

另外需要注意的是format可以同時設置多個屬性值馋记,來指定多個屬性類型,常見應用就是引用資源ID和其它的屬性類型進行混合使用懊烤,多屬性類型通過“|”連接梯醒。

在 XML 布局中指定屬性值

當我們設置完自定義屬性后,就可以在對應的xml文件下的對應控件下進行使用:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.redrain.viewdemo.custom_create.CustomCreateView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        custom:showText="true"
        custom:labelPosition="left"/>

</FrameLayout>

當然這樣還不能實現(xiàn)屬性的功能腌紧,因為我們還沒有設置具體的屬性作用邏輯茸习,那么接下來就來講講如何接收設置好的自定義屬性并進行功能設置。

接收自定義屬性

還記得自定義View的構造函數(shù)嗎壁肋?其中有一個參數(shù)AttributeSet就是表示所設定的屬性号胚,也就是通過它來獲取到具體設置的值,但是直接從AttributeSet中獲取參數(shù)會導致一些問題浸遗,所以需要通過obtainStyledAttributes()方法來獲取屬性值猫胁。

constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
    // 通過obtainStyledAttributes方法獲取到TypedArray對象
    val a = context.theme.obtainStyledAttributes(
        attrs,
        R.styleable.CustomCreateView,
        0, 0
    )

    try {
        // 獲取相應的屬性值
        isShowText = a.getBoolean(R.styleable.CustomCreateView_showText, false)
        textPos = a.getInteger(R.styleable.CustomCreateView_labelPosition, 0)
    } finally {
        // TypedArray是共享資源必須在使用后進行回收
        a.recycle()
    }
}

接受到屬性值之后就可以進行根據(jù)需求來相關的邏輯操作了。

關于各類屬性值如何獲取

每一種屬性類型都有著對應的獲取屬性值的方法:

// color的獲取
// 參數(shù)說明:index表示對應的styleable ID乙帮;defValue表示默認的顏色
int getColor(int index, int defValue)       

// dimension的獲取
// 關于 dimension 的獲取杜漠,獲取到的值為px值,需要進行相應的轉化
// 參數(shù)說明:index表示對應的styleable ID;defValue表示默認的大小
float getDimension(int index, float defValue)           // 獲取到像素值
int getDimensionPixelOffset(int index, int defValue)    // 獲取到像素值驾茴,并轉化為整形數(shù)(取整)
int getDimensionPixelSize(int index, int defValue)      // 獲取到像素值盼樟,并轉化為整形數(shù)(四舍五入的方式轉化)

// integer的獲取
// 參數(shù)說明:index表示對應的styleable ID;defValue表示默認值
// 注意:getInt方法在獲取到屬性值時锈至,如果不是整形數(shù)那么會嘗試強制轉化為int類型晨缴,而getInteger則會拋出exception
int getInt(int index, int defValue)
int getInteger(int index, int defValue)

// string的獲取
// 參數(shù)說明:index表示對應的styleable ID
String getString(int index)

// boolean的獲取
// 參數(shù)說明:index表示對應的styleable ID;defValue表示默認值
boolean getBoolean(int index, boolean defValue)

// enum的獲取
// 枚舉類型的屬性值獲取峡捡,通過getInt或是getInteger來獲取對應的屬性值击碗,獲取到的相應的值來得到枚舉的具體值
int getInt(int index, int defValue)
int getInteger(int index, int defValue)

// flags的獲取
// 通過getInt或是getInteger來獲取對應的屬性值
// 注意:由于flags類型的屬性可以設置多個屬性值,獲取到的值為所設置屬性值對應的value值之和们拙,來進一步判斷選擇了哪些屬性值
int getInt(int index, int defValue)
int getInteger(int index, int defValue)

// float的獲取
// 參數(shù)說明:index表示對應的styleable ID稍途;defValue表示默認值
float getFloat(int index, float defValue)

// fraction的獲取
// 參數(shù)說明:index表示對應的styleable ID;base表示屬性值需要乘的值砚婆;pbase表示屬性值需要除的值械拍;defValue表示默認值
float getFraction(int index, int base, int pbase, float defValue)

// reference的獲取
// 參數(shù)說明:index表示對應的styleable ID;defValue表示默認值
int getResourceId(int index, int defValue)

這里可能會有一個一個疑問了装盯,我們知道有些屬性可以通過多種方式來設置坷虑,比如text屬性可以直接通過字符串或是通過字符串引用id來設置,這種情況只需要直接通過getString方法來設置即可埂奈,Android內部已經(jīng)做了相應的邏輯處理迄损,其它類型的屬性值同理。

添加動態(tài)屬性

上述介紹的都是關于控件的靜態(tài)屬性設置账磺,有時候需要動態(tài)的對屬性進行調整芹敌,所以對需要對每一個屬性值提供一個setter&getter的方法來實現(xiàn)動態(tài)設置屬性:

var isShowText: Boolean = false
    set(value) {
        field = value
        tvText.visibility = if (value) VISIBLE else INVISIBLE
    }

當然動態(tài)屬性的設置方法不局限于上面這種,在定義動態(tài)屬性的時候需要根據(jù)需求去靈活地調整實現(xiàn)方式垮抗。

構造函數(shù)參數(shù)的含義

了解自定義屬性的相關概念党窜,那么回到我們之前講到的構造函數(shù),不同的構造函數(shù)所包含的參數(shù)都分別代表著什么呢借宵?

class CustomCreateView : View {

    // 第一個構造函數(shù)
    constructor(context: Context?) : super(context) {

    }

    // 第二個構造函數(shù)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {

    }

    // 第三個構造函數(shù)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {

    }

    // 第四個構造函數(shù)
    // 在 API 21 以上才能使用
    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes) {

    }
}

  • context 上下文就不展開了,都知道這是個什么東西
  • attrs 表示屬性值的集合矾削,上文中已經(jīng)講解了
  • defStyleAttr
  • defStyleRes

重點來講解一下后面兩個參數(shù)壤玫,有做過代碼實驗的同學可定會發(fā)現(xiàn)獲取屬性的方法中包含有兩個之前傳0的參數(shù):

val a = context.theme.obtainStyledAttributes(
    attrs,
    R.styleable.CustomCreateView,
    0, 0
)

最后兩個參數(shù)分別代表了defStyleAttrdefStyleRes

defStyleAttr

相當于為View設置一個主題風格的屬性配置哼凯,如果沒有在xml中沒有定義相關的屬性欲间,但又在主題中定義了相關屬性,那么會從defStyleAttr所指向的style中查找對應的屬性断部。

可以這么理解它猎贴,它依賴于主題,不同主題中定義不同的defStyleAttr,實現(xiàn)的效果也不同她渴。

defStyleRes

指向Style的資源ID达址,但是僅在defStyleAttr為0或者defStyleAttr不為0但Theme中沒有為defStyleAttr屬性賦值時起作用。

簡單來說就是這種方式和主題無關趁耗,它就是兜底的默認屬性風格沉唠。

具體傳參使用方式

defStyleAttr

首先,要在values/attrs中定義特定的屬性名:

<attr name="CustomCreateViewDefStyleAttr" format="reference"/>

然后在values/styles中定義所要設置的屬性風格:

<style name="CustomCreateViewLeftStyleAttr">
    <item name="showText">true</item>
    <item name="labelPosition">left</item>
</style>

下一步苛败,在所需要定義的style中定義對應的屬性(本文這里就偷懶直接放在AppTheme上了):

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="CustomCreateViewDefStyleAttr">@style/CustomCreateViewLeftStyleAttr</item>
</style>

最后在構造函數(shù)中定義默認的屬性風格:

constructor(context: Context, attrs: AttributeSet) : this(context, attrs, R.attr.CustomCreateViewDefStyleAttr) {
    Log.d("customCreate", "第二個構造方法")

}

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
    context,
    attrs,
    defStyleAttr
) {
    Log.d("customCreate", "第三個構造方法")

    val view = LayoutInflater.from(context).inflate(R.layout.view_custom_create, this)
    tvText = view.findViewById(R.id.tv_text)
    tvText.text = "CustomCreateView"

    // 通過obtainStyledAttributes方法獲取到TypedArray對象
    val a = context.obtainStyledAttributes(
        attrs,
        R.styleable.CustomCreateView,
        defStyleAttr, 0
    )

    try {
        // 獲取相應的屬性值
        isShowText = a.getBoolean(R.styleable.CustomCreateView_showText, false)
        labelPosition = a.getInteger(R.styleable.CustomCreateView_labelPosition, 0)
    } finally {
        // TypedArray是共享資源必須在使用后進行回收
        a.recycle()
    }

    tvText.visibility = if (isShowText) VISIBLE else INVISIBLE
    tvText.gravity = if (labelPosition == 0) Gravity.LEFT else Gravity.RIGHT
}

注意這種方式的屬性定義和一般的屬性定義的區(qū)別在于:

  • 通過二參構造函數(shù)實現(xiàn)三參構造函數(shù)满葛,第三個參數(shù)定義為我們定義好的資源id
  • obtainStyledAttributes方法中的第三個參數(shù)傳入defStyleAttr

這樣就實現(xiàn)了defStyleAttr方式的屬性定義,這種方式實際上會到theme中去尋找定義好的特定屬性名罢屈,如果有嘀韧,則會在優(yōu)先級允許的情況下,使用特定屬性名下的定義屬性缠捌,如果沒有則不會去獲取屬性锄贷。

defStyleRes

defStyleRes實現(xiàn)只需要在defStyleAttr實現(xiàn)上稍微做一點小改動。

去掉theme中的定義:

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

讓三參構造函數(shù)實現(xiàn)四參構造函數(shù):

constructor(context: Context, attrs: AttributeSet) : this(context, attrs, R.attr.CustomCreateViewDefStyleAttr) {
    Log.d("customCreate", "第二個構造方法")

}

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : this(
    context,
    attrs,
    defStyleAttr,
    R.style.CustomCreateViewLeftStyleAttr
) {
    Log.d("customCreate", "第三個構造方法")
}

constructor(
    context: Context,
    attrs: AttributeSet,
    defStyleAttr: Int,
    defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {
    Log.d("customCreate", "第四個構造方法")

    val view = LayoutInflater.from(context).inflate(R.layout.view_custom_create, this)
    tvText = view.findViewById(R.id.tv_text)
    tvText.text = "CustomCreateView"

    // 通過obtainStyledAttributes方法獲取到TypedArray對象
    val a = context.obtainStyledAttributes(
        attrs,
        R.styleable.CustomCreateView,
        defStyleAttr, defStyleRes
    )

    try {
        // 獲取相應的屬性值
        isShowText = a.getBoolean(R.styleable.CustomCreateView_showText, false)
        labelPosition = a.getInteger(R.styleable.CustomCreateView_labelPosition, 0)
    } finally {
        // TypedArray是共享資源必須在使用后進行回收
        a.recycle()
    }

    tvText.visibility = if (isShowText) VISIBLE else INVISIBLE
    tvText.gravity = if (labelPosition == 0) Gravity.LEFT else Gravity.RIGHT
}

注意這種方式的屬性定義和一般的屬性定義的區(qū)別在于:

  • 通過三參構造函數(shù)實現(xiàn)四參構造函數(shù)鄙币,第四個參數(shù)定義為我們定義好的資源id
  • obtainStyledAttributes方法中的第四個參數(shù)傳入defStyleRes

由于在主題中肃叶,已經(jīng)去掉了defStyleAttr方式定義的屬性資源,那么最終會調用defStyleRes所定義的屬性資源十嘿,也就是:

<style name="CustomCreateViewLeftStyleAttr">
    <item name="showText">true</item>
    <item name="labelPosition">right</item>
</style>

屬性設置區(qū)別

上文中已經(jīng)將各類的屬性賦值一一講解因惭,那么它們區(qū)別以及應用場景是什么呢?

屬性設置:

  1. 在布局xml中直接定義
  2. 在布局xml中通過style定義
  3. 自定義View所在的Activity的Theme中指定style引用
  4. 構造函數(shù)中defStyleRes指定的默認值

屬性設置的方式有以上幾種绩衷,優(yōu)先級從高到低(如果高優(yōu)先級的定義了蹦魔,那么低優(yōu)先級的就不會采用),下文中使用數(shù)字來表示:

  1. 很好理解咳燕,xml的屬性定義是程序員的第一設置項勿决,反映了程序員的期望。
  2. style定義可以理解為某一種設計的規(guī)范招盲,增強了復用性低缩,但其可以被1所定義的屬性替換,在規(guī)范的同時曹货,提升定制的可能咆繁。
  3. 更像一種主題性質的定義,統(tǒng)一的主題定義顶籽,方便了程序員來定制整體樣式玩般。
  4. 提供了最基礎的默認值,保證了整體風格的統(tǒng)一礼饱。

Android將屬性定義通過不同顆粒度的定義方式進行了區(qū)分坏为,最主要的還是幫助開發(fā)者提高開發(fā)的效率究驴。

總結

本文主要講解自定義View的創(chuàng)建過程,從構造函數(shù)這個入口作為切入點匀伏,講解自定義屬性的定義過程和不同方式下對View的屬性風格的把握洒忧,本文沒有給出完整的源碼,但是所使用的代碼是連貫的帘撰,建議想嘗試的同學可以自己寫一寫代碼做一下嘗試跑慕,尤其是defStyleAttrdefStyleRes的概念一定要好好地理解一下,實際開發(fā)中會極大地提高我們的開發(fā)效率摧找。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末核行,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蹬耘,更是在濱河造成了極大的恐慌芝雪,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件综苔,死亡現(xiàn)場離奇詭異惩系,居然都是意外死亡,警方通過查閱死者的電腦和手機如筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門堡牡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杨刨,你說我怎么就攤上這事晤柄。” “怎么了妖胀?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵芥颈,是天一觀的道長。 經(jīng)常有香客問我赚抡,道長爬坑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任涂臣,我火速辦了婚禮盾计,結果婚禮上,老公的妹妹穿的比我還像新娘赁遗。我一直安慰自己闯估,他們只是感情好,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布吼和。 她就那樣靜靜地躺著,像睡著了一般骑素。 火紅的嫁衣襯著肌膚如雪炫乓。 梳的紋絲不亂的頭發(fā)上刚夺,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音末捣,去河邊找鬼侠姑。 笑死,一個胖子當著我的面吹牛箩做,可吹牛的內容都是我干的莽红。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼邦邦,長吁一口氣:“原來是場噩夢啊……” “哼安吁!你這毒婦竟也來了?” 一聲冷哼從身側響起燃辖,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤鬼店,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后黔龟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妇智,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年氏身,在試婚紗的時候發(fā)現(xiàn)自己被綠了巍棱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛋欣,死狀恐怖航徙,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情豁状,我是刑警寧澤捉偏,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站泻红,受9級特大地震影響夭禽,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谊路,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一讹躯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缠劝,春花似錦潮梯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脱羡,卻和暖如春萝究,著一層夾襖步出監(jiān)牢的瞬間免都,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工帆竹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留绕娘,地道東北人。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓栽连,卻偏偏與公主長得像险领,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子秒紧,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內容