下拉刷新和上拉加載之MJRefresh篇(一)

版本歷史

版本號 修改時間
V1.0 2017.05.01

前言

在我們的app中加載數(shù)據(jù),很多時候都需要進(jìn)行上拉加載和下拉刷新,特別是像今日頭條這樣的門戶網(wǎng)站,每個頁面給用戶提供20條左右的數(shù)據(jù),根據(jù)用戶的喜歡選擇是否刷新愿伴,才請求服務(wù)器給出分頁的數(shù)據(jù)。這里我們可以自定義上拉加載和下拉刷新电湘,但是也可以采用第三方框架隔节,我們這篇主要就是說的是應(yīng)用較為廣泛的第三方框架MJRefresh,此篇為基礎(chǔ)入門篇寂呛,專門為那些剛?cè)腴T同學(xué)的進(jìn)行引導(dǎo)怎诫,下面主要的內(nèi)容就是對MJRefresh進(jìn)行概覽并給出一個最簡單的例子。下面就開始吧贷痪。開始之前先給出MJRefreh的github地址幻妓。
MJRefrsh-github地址

MJRefresh概覽

適用范圍

MJRefresh適用哪些控件的刷新呢?github官網(wǎng)上給出了四個劫拢,其實(shí)不難猜到就是主要的那幾個可以滾動的控件(UITextView除外)肉津,主要就是四個:UIScrollViewUITableView舱沧、UICollectionView妹沙、UIWebView

API集成

主要的集成方式有兩種:

  1. 自動集成:通過cocoapods集成熟吏。
  2. 手動集成:通過github下載距糖,手動拖動到項(xiàng)目中。

API結(jié)構(gòu)

我們先看一下有哪些源文件分俯。

API結(jié)構(gòu)-1
API結(jié)構(gòu)-2

這個家族的文件就目前的更新情況而言肾筐,已經(jīng)全部在這里了哆料。我們在看一下下面這個圖表缸剪。

API圖表

下面對這個圖標(biāo)進(jìn)行說明:

  • 紅色的部分,可直接使用
  • 下拉刷新 1)Normal: MJRefreshNormalHeader 2) Gif:MJRefreshGifHeader
  • 上拉刷新:1)自動刷新 Normal:MJRefreshAutoNormalFooter 和 Gif:MJRefreshAutoGifFooter 2)自動回彈 Normal:MJRefreshBackNormalFooter 和 Gif:MJRefreshBackGifFooter东亦。
  • 其他顏色的部分不可以直接使用杏节。

除了我們直接用唬渗,我們還可以DIY刷新,使用下面的奋渔。

DIY刷新

API中幾個重要的類

1. MJRefreshComponent.h
/** The Base Class of refresh control */

@interface MJRefreshComponent : UIView

#pragma mark -  Control the state of Refresh 

/** BeginRefreshing */
- (void)beginRefreshing;

/** EndRefreshing */
- (void)endRefreshing; 

/** IsRefreshing */
- (BOOL)isRefreshing;

#pragma mark - Other

* According to the drag ratio to change alpha automatically 

@property (assign, nonatomic, getter=isAutomaticallyChangeAlpha) BOOL automaticallyChangeAlpha;

@end

2. MJRefreshHeader.h

@interface MJRefreshHeader : MJRefreshComponent

/** Creat header */
+ (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;

/** Creat header */
+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;

/** This key is used to storage the time that the last time of drown-down successfully */
@property (copy, nonatomic) NSString *lastUpdatedTimeKey;

/** The last time of drown-down successfully */
@property (strong, nonatomic, readonly) NSDate *lastUpdatedTime;

/** Ignored scrollView contentInset top */
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetTop;

@end

3. MJRefreshFooter.h

 @interface MJRefreshFooter : MJRefreshComponent

/** Creat footer */
+ (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;

/** Creat footer */
+ (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;

/** NoticeNoMoreData */
- (void)noticeNoMoreData;

/** ResetNoMoreData(Clear the status of NoMoreData ) */
- (void)resetNoMoreData;

/** Ignored scrollView contentInset bottom */
@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;

/** Automaticlly show or hidden by the count of data(Show-have data镊逝,Hidden- no data) */
@property (assign, nonatomic) BOOL automaticallyHidden;@end


4. MJRefreshAutoFooter.h

@interface MJRefreshAutoFooter : MJRefreshFooter

/** Is Automatically Refresh(Default is Yes) */
@property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh;

/** When there is much at the bottom of the control is automatically refresh(Default is 1.0,Is at the bottom of the control appears in full, will refresh automatically) */
@property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent;

@end

幾種使用方式

下面簡單的介紹幾種使用方式嫉鲸,內(nèi)容來源于github。謝謝每一個作者的分享,謝謝大家骨稿。

下拉刷新

1. Default模式刷新

self.tableView.header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
   //Call this Block When enter the refresh status automatically 
}];

或

// Set the callback(Once you enter the refresh status仪媒,then call the action of target,that is call [self loadNewData])
self.tableView.header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];

// Enter the refresh status immediately
[self.tableView.header beginRefreshing];

看下面的gif圖藤树。

default模式

2. 帶有動畫圖片的刷新

// Set the callback(一Once you enter the refresh status浴滴,then call the action of target,that is call [self loadNewData])
MJRefreshGifHeader *header = [MJRefreshGifHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];

// Set the ordinary state of animated images
[header setImages:idleImages forState:MJRefreshStateIdle];

// Set the pulling state of animated images(Enter the status of refreshing as soon as loosen)
[header setImages:pullingImages forState:MJRefreshStatePulling];

// Set the refreshing state of animated images
[header setImages:refreshingImages forState:MJRefreshStateRefreshing];

// Set header
self.tableView.mj_header = header;

我們看一下下面的gif圖岁钓。

animate-image

3. 隱藏時間的刷新

// Hide the time
header.lastUpdatedTimeLabel.hidden = YES;

我們看下面的gif圖升略。

hide-time-fresh

4. 隱藏狀態(tài)和時間的刷新

// Hide the time
header.lastUpdatedTimeLabel.hidden = YES;

// Hide the status
header.stateLabel.hidden = YES;


看下下面的gif圖。

hide_time_status_fresh

5. DIY文案刷新

// Set title
[header setTitle:@"Pull down to refresh" forState:MJRefreshStateIdle];
[header setTitle:@"Release to refresh" forState:MJRefreshStatePulling];
[header setTitle:@"Loading ..." forState:MJRefreshStateRefreshing];

// Set font
header.stateLabel.font = [UIFont systemFontOfSize:15];
header.lastUpdatedTimeLabel.font = [UIFont systemFontOfSize:14];

// Set textColor
header.stateLabel.textColor = [UIColor redColor];
header.lastUpdatedTimeLabel.textColor = [UIColor blueColor];

看一下gif圖屡限。

DIY_fresh

6. 自定義控件的刷新

self.tableView.mj_header = [MJDIYHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
// Implementation reference to MJDIYHeader.h和MJDIYHeader.m

看下面的gif圖品嚣。

control_fresh

上拉刷新

1. Default模式刷新

self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
    //Call this Block When enter the refresh status automatically
}];
或
// Set the callback(Once you enter the refresh status,then call the action of target钧大,that is call [self loadMoreData])
self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];

看下面的gif圖腰根。

default_fresh

2. 動畫刷新

// Set the callback(Once you enter the refresh status,then call the action of target拓型,that is call [self loadMoreData])
MJRefreshAutoGifFooter *footer = [MJRefreshAutoGifFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];

// Set the refresh image
[footer setImages:refreshingImages forState:MJRefreshStateRefreshing];

// Set footer
self.tableView.mj_footer = footer;

看下面的gif圖额嘿。

animate_image_fresh

3. 隱藏狀態(tài)的刷新

// Hide the title of refresh status
footer.refreshingTitleHidden = YES;

// If does have not above method,then use 
footer.stateLabel.hidden = YES;

看下面的gif圖劣挫。

hide_status_fresh

4. 全部加載完畢的刷新

//Become the status of NoMoreData
[footer noticeNoMoreData];

我們看下面的gif圖册养。

all_load_fresh

5. DIY文字的刷新

// Set title
[footer setTitle:@"Click or drag up to refresh" forState:MJRefreshStateIdle];
[footer setTitle:@"Loading more ..." forState:MJRefreshStateRefreshing];
[footer setTitle:@"No more data" forState:MJRefreshStateNoMoreData];

// Set font
footer.stateLabel.font = [UIFont systemFontOfSize:17];

// Set textColor
footer.stateLabel.textColor = [UIColor blueColor];

我們看下面的gif圖。

DIY_title_fresh

6. 隱藏footer的刷新

//Hidden current control of the pull to refresh
self.tableView.mj_footer.hidden = YES;

我們看gif圖压固。

hide_after_loadall

7. 自動回彈的刷新

self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];

我們看一下gif圖球拦。

autoback_fresh

8. 圖片自動回彈的刷新

MJRefreshBackGifFooter *footer = [MJRefreshBackGifFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];

// Set the normal state of the animated image
[footer setImages:idleImages forState:MJRefreshStateIdle];

//  Set the pulling state of animated images(Enter the status of refreshing as soon as loosen)
[footer setImages:pullingImages forState:MJRefreshStatePulling];

// Set the refreshing state of animated images
[footer setImages:refreshingImages forState:MJRefreshStateRefreshing];

// Set footer
self.tableView.mj_footer = footer;

我們看下下面gif圖。

autoback_image_fresh

9.自定義控件的自動刷新

self.tableView.mj_footer = [MJDIYAutoFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
// Implementation reference to MJDIYAutoFooter.h和MJDIYAutoFooter.m

下面我們看gif圖帐我。

autofresh_control_fresh

10.自定義控件的自動回彈刷新

 self.tableView.mj_footer = [MJDIYBackFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
// Implementation reference to MJDIYBackFooter.h和MJDIYBackFooter.m

我們看下gif圖坎炼。

autoback_control_fresh

11.上下拉刷新

// The drop-down refresh
self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
   //Call this Block When enter the refresh status automatically 
}];

// The pull to refresh
self.collectionView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
   //Call this Block When enter the refresh status automatically
}];

我們看一下下邊的gif圖。

up_down_fresh

12.webview下拉刷新

//Add the control of The drop-down refresh

self.webView.scrollView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
   //Call this Block When enter the refresh status automatically
}];

我們看一下下面的gif圖拦键。

webview_fresh

我的一個非常簡單的應(yīng)用舉例

我利用MJRefresh非常簡單的實(shí)現(xiàn)了上拉和下拉刷新谣光,這只是給大家看看的例子,在例子中我利用延時模擬網(wǎng)絡(luò)加載芬为。希望對入門級的同學(xué)會有幫助萄金。

先看代碼結(jié)構(gòu)蟀悦。

代碼結(jié)構(gòu)

然后我們看代碼。

1. AppDelegate.m

#import "AppDelegate.h"
#import "JJMainVC.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    JJMainVC *mainVC = [[JJMainVC alloc] init];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:mainVC];
    self.window.rootViewController = nav;
    [self.window makeKeyAndVisible];
        
    return YES;
}

@end

2. JJMainVC.h

#import <UIKit/UIKit.h>

@interface JJMainVC : UIViewController

@end

3. JJMainVC.m

#import "JJMainVC.h"
#import "Masonry.h"
#import "JJTableViewCell.h"
#import "MJRefresh.h"

@interface JJMainVC () <UITableViewDelegate, UITableViewDataSource>

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, assign) NSInteger currentPage;

@end

@implementation JJMainVC

static NSString * const kJJMainVCReuseIdentify = @"kJJMainVCReuseIdentify";

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = @"MJRefresh Demo";
    
    [self setupUI];
    
}

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    
    //tableview
    [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.bottom.equalTo(self.view);
    }];

}

#pragma mark - Object Private Function

- (void)setupUI
{
    //tableview加載
    UITableView *tableView = [[UITableView alloc] init];
    tableView.rowHeight = 80.0;
    tableView.delegate = self;
    tableView.dataSource = self;
    [tableView registerClass:[JJTableViewCell class] forCellReuseIdentifier:kJJMainVCReuseIdentify];
    tableView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:tableView];
    self.tableView = tableView;
    
    //頭部刷新控件
    tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(downFreshloadData)];
    [tableView.mj_header beginRefreshing];
    //尾部刷新控件
    tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(upFreshLoadMoreData)];
    [tableView.mj_footer beginRefreshing];
}

//下拉刷新
- (void)downFreshloadData
{
    //這里加入的是網(wǎng)絡(luò)請求氧敢,帶上相關(guān)參數(shù)日戈,利用網(wǎng)絡(luò)工具進(jìn)行請求。我這里沒有網(wǎng)絡(luò)就模擬一下數(shù)據(jù)吧孙乖。
    //網(wǎng)絡(luò)不管請求成功還是失敗都要結(jié)束更新浙炼。
    NSLog(@"我在下拉刷新");
    
    //利用延時函數(shù)模擬網(wǎng)絡(luò)加載
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
    dispatch_after(time, dispatch_get_main_queue(), ^{
        [self.tableView.mj_header endRefreshing];
    });
}

//上拉加載更多
- (void)upFreshLoadMoreData
{
    //在這里上拉加載更多,將加載的數(shù)據(jù)拼接在數(shù)據(jù)源后面就可以了唯袄。
    //利用延時函數(shù)模擬網(wǎng)絡(luò)加載
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
    dispatch_after(time, dispatch_get_main_queue(), ^{
        [self.tableView.mj_footer endRefreshing];
    });

}

#pragma mark - UITableViewDelegate, UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 10;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kJJMainVCReuseIdentify forIndexPath:indexPath];
    
    return cell;
}

@end

4.  JJTableViewCell.h

#import <UIKit/UIKit.h>

@interface JJTableViewCell : UITableViewCell

@end

5. JJTableViewCell.m

#import "JJTableViewCell.h"
#import "Masonry.h"

@interface JJTableViewCell ()

@property (nonatomic, strong) UIImageView *avatarImageView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UILabel *descLabel;

@end

@implementation JJTableViewCell

#pragma mark - Override Base Function

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        [self setupUI];
    }

    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    //頭像
    [self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self);
        make.left.equalTo(self).offset(20.0);
        make.width.height.equalTo(@50);
    }];
    
    //姓名
    [self.nameLabel sizeToFit];
    [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.avatarImageView.mas_right).offset(20.0);
        make.top.equalTo(self.avatarImageView);
    }];
    
    //介紹
    [self.descLabel sizeToFit];
    [self.descLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.nameLabel);
        make.bottom.equalTo(self.avatarImageView);
    }];

}

#pragma mark - Object Private Function

- (void)setupUI
{
    //頭像
    UIImageView *avatarImageView = [[UIImageView alloc] init];
    avatarImageView.image = [UIImage imageNamed:@"Snip20170430_5.png"];
    [self.contentView addSubview:avatarImageView];
    self.avatarImageView = avatarImageView;

    //姓名
    UILabel *nameLabel = [[UILabel alloc] init];
    nameLabel.text = @"香格里拉";
    nameLabel.textColor = [UIColor blueColor];
    nameLabel.font = [UIFont systemFontOfSize:14.0];
    [self.contentView addSubview:nameLabel];
    self.nameLabel = nameLabel;

    //介紹
    UILabel *descLabel = [[UILabel alloc] init];
    descLabel.text = @"這是一個迷人的地方鼓拧,可以去看看~~~";
    descLabel.textColor = [UIColor redColor];
    descLabel.font = [UIFont systemFontOfSize:14.0];
    [self.contentView addSubview:descLabel];
    self.descLabel = descLabel;

}

@end

然后我們看下邊的gif圖。

simple_refresh_demo

??這個實(shí)現(xiàn)很簡單越妈,給初學(xué)者一個入門的看看效果季俩,后續(xù)我有時間會加大難度,希望對大家有幫助梅掠,謝謝大家酌住,下面給出github地址

后記

今天就寫這么多了阎抒,午飯都沒吃酪我,該去吃飯了,謝謝大家且叁,未完都哭,待續(xù)~~~。

大海
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逞带,一起剝皮案震驚了整個濱河市欺矫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌展氓,老刑警劉巖穆趴,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遇汞,居然都是意外死亡未妹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門空入,熙熙樓的掌柜王于貴愁眉苦臉地迎上來络它,“玉大人,你說我怎么就攤上這事歪赢』粒” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵轨淌,是天一觀的道長迂烁。 經(jīng)常有香客問我,道長递鹉,這世上最難降的妖魔是什么盟步? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮躏结,結(jié)果婚禮上却盘,老公的妹妹穿的比我還像新娘。我一直安慰自己媳拴,他們只是感情好黄橘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屈溉,像睡著了一般塞关。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上子巾,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天帆赢,我揣著相機(jī)與錄音,去河邊找鬼线梗。 笑死椰于,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仪搔。 我是一名探鬼主播瘾婿,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烤咧!你這毒婦竟也來了偏陪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤煮嫌,失蹤者是張志新(化名)和其女友劉穎竹挡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立膛,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揪罕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宝泵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片好啰。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖儿奶,靈堂內(nèi)的尸體忽然破棺而出框往,到底是詐尸還是另有隱情,我是刑警寧澤闯捎,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布椰弊,位于F島的核電站许溅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秉版。R本人自食惡果不足惜贤重,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望清焕。 院中可真熱鬧并蝗,春花似錦、人聲如沸秸妥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粥惧。三九已至键畴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間突雪,已是汗流浹背镰吵。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挂签,地道東北人疤祭。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像饵婆,于是被迫代替她去往敵國和親勺馆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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