自定義 RecyclerView 實現(xiàn)刷新與加載更多

“哎呀,最近新接手一個項目里要用 RecyclerView 的地方好多着裹,而且基本上都需要上拉刷新和下拉加載领猾,我才寫了兩個頁面,手都快斷了骇扇,有沒有什么比較好的方法摔竿?”

“什么!你還在自己一點點地寫少孝?那你得寫到啥時候去继低?”

“那怎么辦?”

“你是不是傻稍走,Github 上那么多優(yōu)秀的開源庫袁翁,用一個啊⌒隽常或者是自己寫一個簡單的粱胜,別寫那么復雜的,能滿足自己需求的就行狐树”貉梗”

“有道理,我去看看”

......

“Github 上的優(yōu)秀的好多啊褪迟,我都看花了眼冗恨,不知道該選哪一個?”

“實在不行味赃,你就自己寫一個唄掀抹,如果只是實現(xiàn)你的需求應該不難,來說說看心俗,你的需求是什么傲武?”

“也不是很復雜,就簡單的一個城榛,能上拉加載更多揪利,下拉刷新的就行,簡單不狠持?”

“你出去別說你是程序員疟位,會被懟死的……”

“咋了,這不行嗎喘垂?”

“不是不行甜刻,你這需求提了跟沒提一個樣绍撞,有沒有點實質(zhì)性的東西?”

“嗯……得院,那我重說

  1. 在布局文件中只使用一個控件傻铣,不做任何的嵌套;
  2. 在 RecyclerView 沒有數(shù)據(jù)的時候祥绞,頁面上顯示提示信息非洲,‘暫無數(shù)據(jù)’ 就行;
  3. 支持下拉刷新蜕径,刷新顯示的 Header 就用官方的那個小圓圈就行了两踏;
  4. 支持上拉加載,如果有下一頁數(shù)據(jù)丧荐, Footer 顯示一個 Loading 配上‘加載中……’缆瓣,如果沒有數(shù)據(jù),就顯示‘你已經(jīng)扯到底了’虹统。

嗯弓坞,就這么多〕道螅”

“還行渡冻,也不算難,有什么想法嗎忧便?”

“暫時沒了族吻,后面想到再加吧≈樵觯”

“…………”

“那行超歌,那我們先來看看具體怎么實現(xiàn)吧〉俳蹋”

“1. 同一個控件內(nèi)既能刷新又要可以上拉加載巍举,官方的控件應該是沒有的,那就自定義一個吧凝垛,自定義一個 ViweGroup 懊悯,然后把 SwipeRefreshLayout 和 RecyclerView 包裹起來,然后再給 RecyclerView 添加一個滑動監(jiān)聽事件梦皮;

  1. 在沒有數(shù)據(jù)的情況下顯示提示信息炭分,這個可以放一個 TextView 或者是 ImageView ,然后在獲取數(shù)據(jù)之后剑肯,判斷是否為空捧毛,如果數(shù)據(jù)不為空就顯示 RecyclerView,如果數(shù)據(jù)為空,就顯示 TextView岖妄;
  2. 需要動態(tài)的修改 Footer 顯示的內(nèi)容型将,那就在 RecyclerView 的 Adapter 中動態(tài)更改唄。

“等等荐虐,那個 Footer 的動態(tài)更改能不能不讓我做啊,每次都要寫動態(tài)改變代碼丸凭,實在不想寫福扬。”

“沒讓你寫啊惜犀,我是說放在我們內(nèi)部的 Adapter 里面铛碑。是這樣的,我打算自己實現(xiàn)一個 Adapter 虽界,在這個 Adapter 里面去動態(tài)的更新 Footer汽烦。”

“你實現(xiàn)了 Adapter莉御,那我外面還能用嗎撇吞?

“可以啊,咋不行礁叔,我自定義的 Adapter 把你外層需要用到的 Adapter 包裹起來牍颈,你還是你,不過琅关,你外面還有一層煮岁。玩過俄羅斯套娃嗎?”

“沒有……”

“想想手機和手機殼的關(guān)系涣易,這個跟那個類似画机。”

“好像懂了……”

“那我們來實現(xiàn)吧新症〔绞希”

“從哪下手啊账劲?我怎么感覺一臉懵逼戳护。”

“先從布局文件開始瀑焦,先來寫顯示出來的列表布局腌且,在里面寫上你要的那幾個控件。然后再給 Footer 來一個布局榛瓮∑潭”

me_recyclerview.xml

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

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/list_tip_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="沒有數(shù)據(jù)"
        android:textSize="16sp" />

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/list_swipe_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone" />

    </android.support.v4.widget.SwipeRefreshLayout>

</FrameLayout>

“嗯,這就是列表布局了,內(nèi)容很簡單就是你現(xiàn)在寫的樣子……精续,好了坝锰,再來寫個 Footer 布局≈馗叮”

“等等顷级,這個簡單,我來确垫」保”

“行行行,你來删掀∠杓剑”

me_foot.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="48dp">

    <ProgressBar
        android:id="@+id/item_footer_progress"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.4"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/item_footer_message"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_marginStart="8dp"
        android:gravity="center"
        android:text="加載中"
        app:layout_constraintLeft_toRightOf="@+id/item_footer_progress" />

</android.support.constraint.ConstraintLayout>

“還行,那我們繼續(xù)披泪?”

“好嘞纤子。”

“剛才說了款票,需要使用一個 Adapter 來包裹外層調(diào)用方的 Adapter 控硼,那么還需要自定義一個 Adapter ,就叫 MeRefreshListAdapter 吧徽职。來繼續(xù)”

MeRefreshListAdapter.java

    private static final int TYPE_FOOTER = -1;
    private RecyclerView.Adapter adapter;
    private LayoutInflater inflater;
    private boolean isShowFooter;
    private boolean isNoData;

    public MeRefreshListAdapter(RecyclerView.Adapter adapter, Context context, boolean isShowFooter, boolean isNoData) {
        this.adapter = adapter;
        this.isShowFooter = isShowFooter;
        this.isNoData = isNoData;
        inflater = LayoutInflater.from(context);
    }

“你這里那個 RecyclerView.Adapter 干啥使得象颖?”

“那個就是外面你傳進來的 Adapter 啊,你外面的 Adapter 肯定得繼承自 RecyclerView.Adapter 吧姆钉,那我得保證说订,你加的什么泛型我這邊都能用啊。比如你有一個是繼承自 RecyclerView.Adapter<Person.ViewHolder>,還有一個是繼承自 RecyclerView.Adapter<City.ViewHolder>”。

“哦~”

“還有裸准,這個 MeRefreshListAdapter 需要控制 Footer 和外層 Adapter 的 Item 的創(chuàng)建與綁定塔插,總的來說屋摇,他們是兩類,我不管你外層的 Item 的類型有幾個,我都要加上 1 ,這個 1 就是 Footer沾谜。并且,我內(nèi)部只對 Footer 這一個類型的 Item 進行控制胀莹,其余的還是交給你外層去做基跑。不過這時候就需要進行判斷了,到底哪一個是 Footer 類型的描焰,哪一個是普通類型(外層的 Item 類型)媳否。”

“這個我知道,簡單篱竭,F(xiàn)ooter 肯定是在最后一個的力图,那就直接把最后一個歸為 Footer 就行了,不對掺逼,當不顯示 Footer 的時候吃媒,最后一個 Item 也是普通類型,那就是在顯示 Footer 的情況下的最后一個 Item 是 Footer吕喘∠郏”

“嗯,是的兽泄,這樣一來,我們自定義的 Adapter 也就出來了漾月〔∩遥”

MeRefreshListAdapter.java

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder viewHolder;
        switch (viewType) {
            case TYPE_FOOTER:
                View footer = inflater.inflate(R.layout.me_list_footer, parent, false);
                viewHolder = new FooterHolder(footer);
                break;
            default:
                viewHolder = adapter.onCreateViewHolder(parent, viewType);
                break;
        }
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof FooterHolder) {
            FooterHolder footerHolder = (FooterHolder) holder;
            footerHolder.progressBar.setVisibility(isNoData ? View.GONE : View.VISIBLE);
            footerHolder.message.setText(isNoData ? "--- 扯到底了 ---" : "加載中……");
        }else{
            adapter.onBindViewHolder(holder,position);
        }
    }

    @Override
    public int getItemCount() {
        return isShowFooter ? adapter.getItemCount() + 1 : adapter.getItemCount();
    }

    @Override
    public int getItemViewType(int position) {
        if (isShowFooter && position + 1 == getItemCount()) {
            return TYPE_FOOTER;
        } else {
            return adapter.getItemViewType(position);
        }
    }
    
    static class FooterHolder extends RecyclerView.ViewHolder {
        ProgressBar progressBar;
        TextView message;

        FooterHolder(View itemView) {
            super(itemView);
            progressBar = itemView.findViewById(R.id.item_footer_progress);
            message = itemView.findViewById(R.id.item_footer_message);
        }
    }

    public void setShowFooter(boolean flag) {
        this.isShowFooter = flag;
        this.notifyDataSetChanged();
    }

    public void setNoData(boolean flag) {
        this.isNoData = flag;
        this.notifyDataSetChanged();
    }

“當然了,還需要對外開放更新 Adapter 的方法梁肿,這樣才能實時控制嘛蜓陌。”

“我們接下來干啥吩蔑?”

“寫接口钮热,我們需要自定義兩個接口方法,用來在外層調(diào)用烛芬。很簡單隧期,就下面這樣的∽嘎Γ”

RefreshLoadListener.java

public interface RefreshLoadListener {
    /**
     * 上拉加載更多
     */
    void upLoad();

    /**
     * 下拉刷新
     */
    void downRefresh();
}

“接口也寫完了仆潮,現(xiàn)在開始進入正題了。自定義 ViewGroup 繼承自 LinearLayout遣臼,然后重寫其中的構(gòu)造方法性置。四個構(gòu)造方法都要重寫啊,不寫的話可能會運行報錯揍堰∨羟常”

MeRecyclerView.java

public class MeRecyclerView extends LinearLayout implements SwipeRefreshLayout.OnRefreshListener {

    private SwipeRefreshLayout refreshLayout;
    private RecyclerView refreshList;
    private AppCompatTextView listTip;
    private RefreshLoadListener loadListener;
    private MeRefreshListAdapter meRefreshListAdapter;
    private Context mContext;
    private RecyclerView.LayoutManager layoutManager;
    private boolean isShowFooter;
    private boolean isNoData;
    private int lastVisibleItem;

    public MeRecyclerView(Context context) {
        super(context);
        init(context);
    }

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

    public MeRecyclerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }
    
    private void init(Context context) {
        this.mContext = context;
        LayoutInflater.from(context).inflate(R.layout.me_recyclerview, this, true);
        refreshLayout = findViewById(R.id.list_swipe_refresh);
        listTip = findViewById(R.id.list_tip_message);
        refreshList = findViewById(R.id.list_list);

        refreshLayout.setOnRefreshListener(this);
    }
}

“你看,剛才在初始化操作的時候屏歹,我們就設置了 SwipeRefreshLayout 的刷新接口隐砸,現(xiàn)在就到了我們需要實現(xiàn)他的時候了,可能跟你平時寫的不太一樣西采,因為雖然我們實現(xiàn)了這個接口凰萨,但我們還是得把這個具體實現(xiàn)的機會交給外層,讓外層進行實際的數(shù)據(jù)獲取。當然了胖眷,我們?nèi)绻斍绊撁嫣幱谒⑿聽顟B(tài)武通,那 Footer 肯定是不能顯示出來的,這個時候就需要操作一下剛才我們寫的 MeRefreshListAdapter ”

MeRecyclerView.java

    @Override
    public void onRefresh() {
        if (null != loadListener) {
            isNoData = false;
            isShowFooter = false;
            meRefreshListAdapter.setNoData(isNoData);
            meRefreshListAdapter.setShowFooter(isShowFooter);
            loadListener.downRefresh();
        }
    }

“好了珊搀,下拉刷新結(jié)束了冶忱,是不是很簡單?”

“這就結(jié)束了境析,這也太快了囚枪。”

“下面來看上拉加載更多劳淆×凑樱”

“刷新的容易,加載更多的沛鸵,要控制下面 Footer 顯示還要改變顯示的文字括勺,想想頭就大∏”

“你想啥呢疾捍,那些都做完了啊,剛在在 MeRefreshListAdapter 不是就做過了……”

“完全沒意識到……”

“上拉加載其實跟刷新一樣的栏妖,都挺好實現(xiàn)的乱豆,無非就是給 RecyclerView 添加一個滑動監(jiān)聽,然后再根據(jù)當前位置去判斷是否加載新數(shù)據(jù)吊趾。你看”

MeRecyclerView.java

        refreshList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                int totalCount = layoutManager.getItemCount() - 1;
                if (totalCount > 18 && newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem == totalCount && !isNoData && !isShowFooter) {
                    if (null != loadListener) {
                        setFooter();
                        loadListener.upLoad();
                    }
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (layoutManager instanceof LinearLayoutManager) {
                    lastVisibleItem = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
                }
            }
        });
        
    private void setFooter() {
        isShowFooter = true;
        meRefreshListAdapter.setShowFooter(true);
    }

"好了宛裕,上拉加載更多也解決了,不過這里我偷了個懶趾徽。在獲取當前列表的最后一項的 position 時续滋,我判斷了 LinearLayoutManager ,其他的沒進行判斷孵奶,不過也簡單疲酌,GridLayoutManager 是繼承自 LinearLayoutManager ,而 StaggeredGridLayoutManager 獲取最后一個 item 的 position 返回的是一個數(shù)組了袁,取出其中最大的即可朗恳。"

“好吧,那這樣是不是就算完成了爸嘟搿?”

“想多了崭庸,看起來怀浆,我們是做完這么多的谊囚,但是,并沒有做完执赡,比如镰踏,我們還需要進行停止刷新,要不然那個無論是上拉加載還是刷新都會有那個 loading 在那不停地動沙合〉煳保”

MeRecyclerView.java

    public void stopRefresh(int pageCount, boolean isNoData) {
        this.isNoData = isNoData;
        meRefreshListAdapter.setNoData(isNoData);
        showData(meRefreshListAdapter.getItemCount() > 0);
        if (pageCount == 1) {
            refreshLayout.setRefreshing(false);
        } else {
            if (!isNoData) {
                isShowFooter = false;
                meRefreshListAdapter.setShowFooter(isShowFooter);
            }
        }
    }
    
    private void showData(boolean b) {
        refreshList.setVisibility(b ? VISIBLE : VISIBLE);
        listTip.setVisibility(b ? GONE : VISIBLE);
    }

"再比如,我們還需要與外部的 LayoutManager 以及 Adapter 建立聯(lián)系以及在外部數(shù)據(jù)變動的時候首懈,通知我們進行刷新"

MeRecyclerView.java

    public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
        this.layoutManager = layoutManager;
        refreshList.setLayoutManager(layoutManager);
    }

    public void setAdapter(RecyclerView.Adapter adapter) {
        meRefreshListAdapter = new MeRefreshListAdapter(adapter, mContext, isShowFooter, isNoData);
        refreshList.setAdapter(meRefreshListAdapter);
    }
    
    public void notifyDataSetChanged() {
        meRefreshListAdapter.notifyDataSetChanged();
    }

"這還不算完……"

“還沒完绊率?”

“肯定的啊,你想啊究履,頁面剛打開的時候滤否,你是不是得立即去刷新一下,做事總得主動點嘛最仑,所以我們還需要一個可以開始刷新的顽聂。”

“我知道盯仪,是讓頁面進來的時候去刷新一下,開始獲取數(shù)據(jù)對吧蜜葱,我們可以直接調(diào)用下拉刷新的方法啊全景,那樣最省事。就像這樣牵囤“只疲”

    public void startRefresh() {
        refreshLayout.setRefreshing(true);
        onRefresh();
    }

“是的,這么樣就行了揭鳞。不過還有一個最最最重要的就是得讓外部把接口實現(xiàn)了炕贵,所以還要這么一個方法∫俺纾”

    public void setLoadListener(RefreshLoadListener loadListener) {
        this.loadListener = loadListener;
    }

"這個称开,我肯定不會晚啊,不過如果忘記了乓梨,肯定都不能用啊鳖轰。我先拿去試試看好不好用啊。"

“……”

“真爽扶镀,用起來特簡單蕴侣。在布局文件里面只用一個控件,就是剛才我們自定義的那個臭觉,然后昆雀,像往常一樣設置 LayoutManager 和 Adapter 不過需要在服務器返回數(shù)據(jù)之后自己手動停止刷新辱志。還是挺簡單的。哦狞膘,對揩懒,還有一個要自己啟動刷新】透裕”

RefreshActivity.java

    @BindView(R.id.refresh_demo_list)
    MeRecyclerView refreshDemoList;
    int page = 1;
    int size = 20;
    List<Map<String, Object>> dataList;
    ListAdapter listAdapter;
    LinearLayoutManager layoutManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_refresh);
        ButterKnife.bind(this);

        dataList = new ArrayList<>();
        listAdapter = new ListAdapter(this, R.layout.item_simgle_check, dataList);
        layoutManager = new LinearLayoutManager(this);
        
        refreshDemoList.setLoadListener(this);
        refreshDemoList.setLayoutManager(layoutManager);
        refreshDemoList.setAdapter(listAdapter);
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        refreshDemoList.startRefresh();
    }
    
    @Override
    public void downRefresh() {
        page = 1;
        getData();
    }

    @Override
    public void upLoad() {
        page += 1;
        getData();
    }
    
    private void update(List<Map<String, Object>> maps) {
        if (page > 5) {
            maps.clear();
        }
        if (maps.size() > 0) {
            if (page == 1) {
                dataList.clear();
                dataList.addAll(maps);
            } else {
                dataList.addAll(maps);
            }
            refreshDemoList.notifyDataSetChanged();
            refreshDemoList.stopRefresh(page, false);
        } else {
            refreshDemoList.stopRefresh(page, true);
        }
    }

沒有數(shù)據(jù)
加載更多
沒有更多

"好了旭从,跟你學完了,我還去繼續(xù)寫代碼了场仲,還有什么問題和悦,下次再來問你。希望有一天渠缕,我能不問你也能把問題解決了鸽素。??"

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市亦鳞,隨后出現(xiàn)的幾起案子馍忽,更是在濱河造成了極大的恐慌,老刑警劉巖燕差,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遭笋,死亡現(xiàn)場離奇詭異,居然都是意外死亡徒探,警方通過查閱死者的電腦和手機瓦呼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來测暗,“玉大人央串,你說我怎么就攤上這事⊥胱模” “怎么了质和?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稚字。 經(jīng)常有香客問我饲宿,道長,這世上最難降的妖魔是什么胆描? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任褒傅,我火速辦了婚禮,結(jié)果婚禮上袄友,老公的妹妹穿的比我還像新娘殿托。我一直安慰自己,他們只是感情好剧蚣,可當我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布支竹。 她就那樣靜靜地躺著旋廷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪礼搁。 梳的紋絲不亂的頭發(fā)上饶碘,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機與錄音馒吴,去河邊找鬼扎运。 笑死,一個胖子當著我的面吹牛饮戳,可吹牛的內(nèi)容都是我干的豪治。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扯罐,長吁一口氣:“原來是場噩夢啊……” “哼负拟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起歹河,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤掩浙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秸歧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厨姚,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年键菱,在試婚紗的時候發(fā)現(xiàn)自己被綠了遣蚀。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡纱耻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出险耀,到底是詐尸還是另有隱情弄喘,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布甩牺,位于F島的核電站蘑志,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贬派。R本人自食惡果不足惜急但,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望搞乏。 院中可真熱鬧波桩,春花似錦、人聲如沸请敦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至萤皂,卻和暖如春撒穷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背裆熙。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工端礼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人入录。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓蛤奥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纷跛。 傳聞我的和親對象是個殘疾皇子喻括,可洞房花燭夜當晚...
    茶點故事閱讀 44,665評論 2 354

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