iOS文檔補完計劃--UITableView

目錄

  • UITableView
  • 復用原理
  • UITableViewDataSource&&UITableViewDelegate
  • 配置TableView
    • style
    • numberOfRowsInSection:
    • numberOfSections
    • rowHeight
    • separator
    • backgroundView
    • cellLayoutMarginsFollowReadableWidth
  • 創(chuàng)建Cell
    • registerCell
    • dequeueReusableCellWithIdentifier:forIndexPath:
    • dequeueReusableCellWithIdentifier:
  • 頁眉和頁腳
  • Cell&&IndexPath
    • cellForRowAtIndexPath:
    • indexPathForCell:
    • indexPathForRowAtPoint:
    • indexPathsForRowsInRect:
    • visibleCells
    • indexPathsForVisibleRows
  • 預估高度
  • 滾動tableView
    • scrollToRowAtIndexPath:atScrollPosition:animated:
    • scrollToNearestSelectedRowAtScrollPosition:animated:
  • 選擇控制
    • indexPathForSelectedRow
    • indexPathsForSelectedRows
    • selectRowAtIndexPath:animated:scrollPosition:
    • deselectRowAtIndexPath:animated:
    • 選擇權限
  • 插入&&刪除&&移動
    • performBatchUpdates:completion:
  • 編輯TableView
  • 重載
    • hasUncommittedUpdates
    • reloadData
    • reloadRowsAtIndexPaths:withRowAnimation:
    • reloadSections:withRowAnimation:
    • reloadSectionIndexTitles
  • 視圖區(qū)域
    • rectForSection:
    • rectForRowAtIndexPath:
  • 預加載
  • 索引配置
  • 通知
    • UITableViewSelectionDidChangeNotification

UITableView

  • SuperClass為UIScrollView

但只允許縱向滾動。

  • Section(節(jié))

可以為0節(jié)惑淳、每個Section都有自己的Row循未。
任何section都可以有選擇地在前面的一個header涩盾,并且可以選擇后跟一個footer

  • Row(行)

可以為0行塔沃、不過即使為0行該Sectionheader以及footer也會顯示。

  • Style

有兩種Style:UITableViewStylePlainUItableViewStyleGrouped。當你創(chuàng)建一個UITableView實例必須指定其的Style双絮、并且無法改變。

UITableViewStylePlain

1.plain類型有多段時得问,段頭停留(自帶效果)
2.plain類型默認section之間沒有中間的間距和頭部間距(想讓plain類型的section之間留有空白囤攀,需要在UITableView代理方法中return自定義的header和footer,并在自定義的UITableViewHeaderFooterView里面重寫setFrame方法)

  1. 可以有索引存在
UItableViewStyleGrouped

sectionHeaderView不會懸浮宫纬、存在默認高度焚挠。

剩下諸如背景色什么的區(qū)別看這篇吧、反正都是定制基本不用考慮《iOS UITableView 的 Plain和Grouped樣式的區(qū)別》


復用原理

可以參考一下:《UITableView的Cell復用原理和源碼分析》
寫的是mac_os的Chameleon漓骚、但原理應該都差不多蝌衔。

簡而言之:

  1. 用數組_cachedCells存儲當前屏幕能展示的cell
    通過CGRectIntersectsRect(cellRect,visibleBounds)確定
  2. 滑動時、獲取移出屏幕的cell
    _cachedCells進行copy蝌蹂、然后remove掉當前屏幕能展示的cell噩斟。剩下的cell就是消失的cell。
  3. 存入復用池
    將上一步獲取的cell存入集合_reusableCells(當然我認為用字典也行)孤个。
  4. 取出cell
    _reusableCells取出特定cell并且移出

至于是不是會在移出屏幕時從父視圖remove掉剃允、這個demo里是做了。但是真正的TableVIew似乎有一些不為人知的規(guī)則(大概率是總remove會造成性能損耗)、并不是一定會立刻remove斥废。


UITableViewDataSource&&UITableViewDelegate

《iOS文檔補完計劃--UITableViewDataSource&&UITableViewDelegate》


配置TableView

  • style

返回初始化時設置的style

@property(nonatomic, readonly) UITableViewStyle style;

如果初始化時沒有設置椒楣、默認為UITableViewStylePlain

  • - numberOfRowsInSection:

返回指定section中的row數

- (NSInteger)numberOfRowsInSection:(NSInteger)section;

在每次reload中牡肉、這個值會通過UITableViewDataSource獲取并被緩存捧灰。

  • - numberOfSections

返回總計的section數

@property(nonatomic, readonly) NSInteger numberOfSections;

在每次reload中、這個值會通過UITableViewDataSource獲取并被緩存统锤。

  • rowHeight

單元格的統(tǒng)一高度

@property(nonatomic) CGFloat rowHeight;

一旦主動實現tableView:heightForRowAtIndexPath:這個值將會失效凤壁。并且在每一次顯示cell時調用該方法、這樣對性能會有一定影響跪另。

默認值是UITableViewAutomaticDimension拧抖、也就是自適應。不過如果你使用ib生成控件免绿、需要顯示的設置rowHeight = UITableViewAutomaticDimension以自適應唧席。

  • separator

分割線的樣式、顏色嘲驾、效果

//分割線樣式 默認UITableViewCellSeparatorStyleSingleLine
@property(nonatomic) UITableViewCellSeparatorStyle separatorStyle;
//分割線顏色 默認`gray`
@property(nonatomic, strong) UIColor *separatorColor;
//分隔效果
@property(nonatomic, copy) UIVisualEffect *separatorEffect;

//分割線的位置
@property(nonatomic) UIEdgeInsets separatorInset;

//iOS11之后對separatorInset的擴展
@property(nonatomic) UITableViewSeparatorInsetReference separatorInsetReference;

不過通常我們都是自定義淌哟、所以直接
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;一勞永逸

  • backgroundView

TableView的背景View

@property(nonatomic, strong) UIView *backgroundView;

默認為nil。
你可以在一些情況下用到它辽故、比如將一個圖片作為backgroundView徒仓。
如果設置背景色直接使用backgroundView即可

  • cellLayoutMarginsFollowReadableWidth

pad開發(fā)時調整cell的margin用

@property(nonatomic) BOOL cellLayoutMarginsFollowReadableWidth;

在iPad開發(fā)時,使用iOS 9系統(tǒng)會出現tableviewCell的位置變化誊垢,在開發(fā)中默認與右側是15個像素掉弛,可是現在明顯大的多。需要將其置NO喂走。


創(chuàng)建Cell

  • registerCell
//注冊nib創(chuàng)建的cell
- (void)registerNib:(UINib *)nib 
forCellReuseIdentifier:(NSString *)identifier;

//注冊代碼創(chuàng)建的cell
- (void)registerClass:(Class)cellClass 
forCellReuseIdentifier:(NSString *)identifier;

你可以通過將Nib傳入nil來復位注冊表

  • - dequeueReusableCellWithIdentifier:forIndexPath:

返回已經注冊的指定cell殃饿、并添加到tableView的指定位置中

- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier 
                                                   forIndexPath:(NSIndexPath *)indexPath;

復用池中有該cell則直接返回該cell、并調用cell的prepareForReuse方法
如果復用池中沒有芋肠、則有兩種情況:

  1. tableView中已經注冊了cell
    直接新建cell乎芳、并調用cell的initWithStyle:reuseIdentifier:創(chuàng)建

  2. 沒有注冊cell
    直接崩潰這里要與dequeueReusableCellWithIdentifier:進行區(qū)分`。

  • - dequeueReusableCellWithIdentifier:

返回指定的id的cell

- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

和上一個方法基本相同帖池。

  • 二者的異同
相同點:
  1. 二者首先都會去從重用池(cellForRow返回的cell在移出屏幕時會被加入重用池)查找奈惑。
  2. 如果重用池中沒有、再嘗試從注冊表查找睡汹。
不同點:
  1. 如果沒有注冊肴甸、他會返回nil。而前者會崩潰
  2. 他只是取出cell帮孔、前者會附加一個添加到TableView的操作(因為必然返回cell吧?)雷滋。

頁眉和頁腳

頁眉頁腳的注冊、提取文兢、插入晤斩。

//注冊
- (void)registerNib:(nullable UINib *)nib forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
- (void)registerClass:(nullable Class)aClass forHeaderFooterViewReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);

//獲取
- (nullable __kindof UITableViewHeaderFooterView *)dequeueReusableHeaderFooterViewWithIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0); 

//頁眉同一高度
@property(nonatomic) CGFloat sectionHeaderHeight;

//頁腳同一高度
@property(nonatomic) CGFloat sectionFooterHeight;


//整個TableView的頁眉
@property(nonatomic, strong) UIView *tableHeaderView;

//整個TableView的頁腳
@property(nonatomic, strong) UIView *tableFooterView;

Cell&&IndexPath

  • - cellForRowAtIndexPath:

返回指定indexPath位置的cell

- (__kindof UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;

有兩種情況會返回nil

  1. 已經進入復用池
  2. 超出范圍的indexPath
  • - indexPathForCell:

返回指定cell的indexPath索引

- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell;

如果cell已經進入復用池、也會返回nil

  • - indexPathForRowAtPoint:

返回指定的點所在的IndexPath

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;

超出了TableVIew的bounds會返回nil

  • - indexPathsForRowsInRect:

返回rect所包含的IndexPath

- (NSArray<NSIndexPath *> *)indexPathsForRowsInRect:(CGRect)rect;
  • - visibleCells

返回當前可見的所有cell

@property(nonatomic, readonly) NSArray<__kindof UITableViewCell *> *visibleCells;
  • - indexPathsForVisibleRows

返回所有可見的IndexPath

@property(nonatomic, readonly) NSArray<NSIndexPath *> *indexPathsForVisibleRows;

預估高度

Cell姆坚、Header澳泵、Footer

@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); 
@property (nonatomic) CGFloat estimatedSectionHeaderHeight NS_AVAILABLE_IOS(7_0); 
@property (nonatomic) CGFloat estimatedSectionFooterHeight NS_AVAILABLE_IOS(7_0); 

默認UITableViewAutomaticDimension、設置成0則禁用兼呵。

這里有一些需要注意的地方:
  1. 禁用預估功能
    tableView會每次都讀取所有indexPathheightForRowAtIndexPath進行行高計算兔辅。

  2. 開啟預估功能
    rectForSection方法返回的rect也為預估值。只有當你劃過所有的cell击喂、才會得到真實的值维苔。


滾動tableView

  • - scrollToRowAtIndexPath:atScrollPosition:animated:

將TableView的某個IndexPath滾動到特定位置

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath 
              atScrollPosition:(UITableViewScrollPosition)scrollPosition 
                      animated:(BOOL)animated;

UITableViewScrollPosition為一個枚舉類型、表示滾動到屏幕的何處

typedef NS_ENUM(NSInteger, UITableViewScrollPosition) {
    UITableViewScrollPositionNone,//只保證能出現在屏幕上
    UITableViewScrollPositionTop,    //上
    UITableViewScrollPositionMiddle,   //中
    UITableViewScrollPositionBottom//下
}; 

文檔上說該方法不會引起scrollViewDidScroll:的調用懂昂、但我測試是會調用的介时。存疑吧

  • - scrollToNearestSelectedRowAtScrollPosition:animated:

讓選定的行滾動到屏幕指定位置

- (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition 
                                          animated:(BOOL)animated;

比如自己實現一個滾輪、點擊的cell滾動到中間凌彬。


選擇控制

  • indexPathForSelectedRow

返回所選行的IndexPath

@property(nonatomic, readonly) NSIndexPath *indexPathForSelectedRow;

如果有多個選擇沸柔、則返回第一個

  • indexPathsForSelectedRows

多選用

@property(nonatomic, readonly) NSArray<NSIndexPath *> *indexPathsForSelectedRows;
  • - selectRowAtIndexPath:animated:scrollPosition:

選擇指定行、可以有動畫

- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath 
                    animated:(BOOL)animated 
              scrollPosition:(UITableViewScrollPosition)scrollPosition;

這個方法不會引起tableView:willSelectRowAtIndexPath:铲敛、tableView:didSelectRowAtIndexPath:褐澎、UITableViewSelectionDidChangeNotification的調用。

如果傳遞UITableViewScrollPositionNone將會導不發(fā)生滾動伐蒋。如果想要這種效果工三、你需要自己實現滾動代碼scrollToRowAtIndexPath:atScrollPosition:animated:

  • - deselectRowAtIndexPath:animated:

取消選擇先鱼、可以有動畫

- (void)deselectRowAtIndexPath:(NSIndexPath *)indexPath 
                      animated:(BOOL)animated;

與上一個方法一樣徒蟆、它也不會導致一些相關方法被調用。(tableView:willDeselectRowAtIndexPath:型型、tableView:didDeselectRowAtIndexPath:段审、UITableViewSelectionDidChangeNotification)
并且不會產生任何滾動效果。

  • 選擇權限

普通選擇闹蒜、編輯選擇與多選

//正常模式下是否允許選擇寺枉。默認YES
@property(nonatomic) BOOL allowsSelection
//正常模式下的多行選擇。默認NO绷落±焉粒可以與indexPathsForSelectedRows配合使用
@property(nonatomic) BOOL allowsMultipleSelection;
//編輯模式下是否允許選擇。默認YES
@property(nonatomic) BOOL allowsSelectionDuringEditing;
//編輯模式下多選砌烁。默認NO
@property(nonatomic) BOOL allowsMultipleSelectionDuringEditing;

插入&&刪除&&移動

一下方法會導致TableView會立即調用相關代理方法筐喳、以獲取內容催式。

同時、我們可以批量操作

- (void)testTableViewUpdateCrash {
    NSIndexPath *insertIndexPath = [NSIndexPath indexPathForRow:10 inSection:0];
    NSIndexPath *deleteIndexPath = [NSIndexPath indexPathForRow:11 inSection:0];
    NSIndexPath *reloadIndexPath = [NSIndexPath indexPathForRow:12 inSection:0];
    NSIndexPath *moved1IndexPath = [NSIndexPath indexPathForRow:13 inSection:0];
    NSIndexPath *moved2IndexPath = [NSIndexPath indexPathForRow:14 inSection:0];
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:@[insertIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView deleteRowsAtIndexPaths:@[deleteIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView reloadRowsAtIndexPaths:@[reloadIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView moveRowAtIndexPath:moved1IndexPath toIndexPath:moved2IndexPath];
    [self.tableView endUpdates];
}

需要注意的是beginUpdatesenpdate是串行的避归。

所以荣月、我們最好先操作數據源然后再進行操作。

  • - insertRowsAtIndexPaths:withRowAnimation:

插入梳毙〔刚可以有動畫效果

//插入
- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;

//刪除
- (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;

//移動-不允許動畫、每次移動單行
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath 
               toIndexPath:(NSIndexPath *)newIndexPath;

//插入sections
- (void)insertSections:(NSIndexSet *)sections 
      withRowAnimation:(UITableViewRowAnimation)animation;

//刪除sections
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
//移動sections
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;
  • - performBatchUpdates:completion:

將多個操作放入動畫組進行账锹。iOS11之后

- (void)performBatchUpdates:(void (^)(void))updates 
                 completion:(void (^)(BOOL finished))completion;
  • - beginUpdates&&endUpdates

準備一系列插入萌业、刪除或選擇等操作

- (void)beginUpdates;
- (void)endUpdates;
  1. 盡量使用performBatchUpdates:completion:而不是這個方法

編輯TableView

修改TableView的編輯狀態(tài)

//屬性版
@property(nonatomic, getter=isEditing) BOOL editing;
//動畫版
- (void)setEditing:(BOOL)editing 
          animated:(BOOL)animated;

具體使用可以參閱《iOS文檔補完計劃--UITableViewDataSource&&UITableViewDelegate》中關于插入、刪除奸柬、拖動的實現生年。


重載

  • hasUncommittedUpdates

Drag & Drop相關。當返回YES時不建議進行reload

@property(nonatomic, readonly) BOOL hasUncommittedUpdates;
  • - reloadData

重載整個TableVIew

- (void)reloadData;

不應該在插入或刪除行的方法中調用廓奕,特別是在用beginUpdates和enpdate調用實現的動畫塊中晶框。

  • - reloadRowsAtIndexPaths:withRowAnimation:

允許使用動畫重載指定的indexPath

- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation;
  • - reloadSections:withRowAnimation:

重載指定的section

- (void)reloadSections:(NSIndexSet *)sections 
      withRowAnimation:(UITableViewRowAnimation)animation;
  1. 如果指定了可視的IndexPath。這個方法會立即向數據源請求新的單元格懂从。
  2. 新cell執(zhí)行插入動畫授段,舊cell執(zhí)行移出動畫
  • - reloadSectionIndexTitles

刷新右側索引

- (void)reloadSectionIndexTitles;

視圖區(qū)域

  • - rectForSection:

返回指定section所占的范圍

- (CGRect)rectForSection:(NSInteger)section;

需要注意這個方法的準確性、取決于預估行高如何去設置番甩。

  • - rectForRowAtIndexPath:

返回指定index所占的范圍

- (CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath;

如果該cell還沒有被展示過侵贵、系統(tǒng)會去獲取正確的高度。(也就是調用heightForRowAtIndexPath甚至cellForRowAtIndexPath)

indexPath違規(guī)則返回CGRectZero

還有兩個方法缘薛、懶得測試了...

- (CGRect)rectForFooterInSection:(NSInteger)section;
- (CGRect)rectForHeaderInSection:(NSInteger)section;

預加載

  • prefetchDataSourc

通過Pre-Fetching功能預知用戶行為

@property(nonatomic, weak) id<UITableViewDataSourcePrefetching> prefetchDataSource;

這個協(xié)議其實是用來通知我們窍育,當前滑動到某個區(qū)域后,根據這次滑動的方向接下去可能還會滑向哪些indexPaths宴胧。好讓我們做一些數據上的預備或者銷毀漱抓。

單個id的復用池為隊列reusable-cell queue.


索引配置

索引行數

@property (nonatomic) NSInteger sectionIndexMinimumDisplayRowCount;                                                      // 當行數達到某個數值,則顯示索引欄
@property (nonatomic, strong, nullable) UIColor *sectionIndexColor NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTOR;                   // 索引顏色
@property (nonatomic, strong, nullable) UIColor *sectionIndexBackgroundColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;         // 正常情況下的背景色
@property (nonatomic, strong, nullable) UIColor *sectionIndexTrackingBackgroundColor NS_AVAILABLE_IOS(6_0) UI_APPEARANCE_SELECTOR; // 觸摸時的背景色

通知

  • UITableViewSelectionDidChangeNotification

選擇項發(fā)生更改時發(fā)送通知

const NSNotificationName UITableViewSelectionDidChangeNotification;

參考資料

官方文檔--UITableView
iOS_10中UICollectionView和UITableView的變化

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末恕齐,一起剝皮案震驚了整個濱河市乞娄,隨后出現的幾起案子,更是在濱河造成了極大的恐慌显歧,老刑警劉巖仪或,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異士骤,居然都是意外死亡范删,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門拷肌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來到旦,“玉大人旨巷,你說我怎么就攤上這事√硗” “怎么了采呐?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昔汉。 經常有香客問我,道長拴清,這世上最難降的妖魔是什么靶病? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮口予,結果婚禮上娄周,老公的妹妹穿的比我還像新娘。我一直安慰自己沪停,他們只是感情好煤辨,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著木张,像睡著了一般众辨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舷礼,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天鹃彻,我揣著相機與錄音,去河邊找鬼妻献。 笑死蛛株,一個胖子當著我的面吹牛,可吹牛的內容都是我干的育拨。 我是一名探鬼主播谨履,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼熬丧!你這毒婦竟也來了笋粟?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤析蝴,失蹤者是張志新(化名)和其女友劉穎矗钟,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體嫌变,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡吨艇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了腾啥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片东涡。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡冯吓,死狀恐怖,靈堂內的尸體忽然破棺而出疮跑,到底是詐尸還是另有隱情组贺,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布祖娘,位于F島的核電站失尖,受9級特大地震影響,放射性物質發(fā)生泄漏渐苏。R本人自食惡果不足惜掀潮,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼富。 院中可真熱鬧仪吧,春花似錦、人聲如沸鞠眉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽械蹋。三九已至出皇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哗戈,已是汗流浹背恶迈。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谱醇,地道東北人暇仲。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像副渴,于是被迫代替她去往敵國和親奈附。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345