EasyRecyclerView擴(kuò)展的自定義RecyclerView控件

特別說明

  • 當(dāng)前博客平臺賬號已廢棄,如果有使用細(xì)節(jié)問題請前往我個人博客平臺 HuRuWo的技術(shù)小站進(jìn)行討論交流例驹。直接在其他平臺留言可能無法及時得到回復(fù)。
  • 文章首發(fā)于個人博客HuRuWo的技術(shù)小站,如果本文非vip用戶無法完全瀏覽或者圖片無法打開帕棉,可前往個人博客文章地址查看文章并留言討論夫凸。

  • 本篇文章個人博客文章地址EasyRecyclerView擴(kuò)展的自定義RecyclerView控件,點擊鏈接直接前往。

  • 更多技術(shù)文章訪問本人博客HuRuWo的技術(shù)小站蚕愤,包括 Electron從零開發(fā) Android 逆向 app 微信數(shù)據(jù)抓取 抖音數(shù)據(jù)抓取 閑魚數(shù)據(jù)抓取 小紅書數(shù)據(jù)抓取 其他軟件爬蟲 等技術(shù)文章

介紹:

recycler3.gif

將開發(fā)中常用的RecyclerView的各種需求封裝進(jìn)庫。提升開發(fā)效率饺蚊。
重點在Adapter與viewholder的封裝萍诱。他們之間徹底解耦。
adapter工作更少污呼,僅負(fù)責(zé)業(yè)務(wù)邏輯裕坊。所以如果你使用mvp架構(gòu)可以放進(jìn)presenter層。
viewholder負(fù)責(zé)View展示與Adapter沒有任何耦合燕酷,將可以到處復(fù)用籍凝。并不會影響運行效率。
并且adapter支持?jǐn)?shù)據(jù)管理苗缩,Header與Footer添加饵蒂,加載更多。沒有更多酱讶。加載錯誤
使用了部分Malinskiy/SuperRecyclerView的代碼退盯,將更多功能交給了adapter實現(xiàn)。

項目地址:

https://github.com/Jude95/EasyRecyclerView

引用

compile 'com.jude:easyrecyclerview:4.4.0'

當(dāng)然還要添加:

compile 'com.android.support:recyclerview-v7:24.2.0'

具體使用

布局引用:

<com.jude.easyrecyclerview.EasyRecyclerView
  android:id="@+id/recyclerView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layout_empty="@layout/view_empty"
  app:layout_progress="@layout/view_progress"
  app:layout_error="@layout/view_error"
  app:recyclerClipToPadding="true"
  app:recyclerPadding="8dp"
  app:recyclerPaddingTop="8dp"
  app:recyclerPaddingBottom="8dp"
  app:recyclerPaddingLeft="8dp"
  app:recyclerPaddingRight="8dp"
  app:scrollbarStyle="insideOverlay"http://insideOverlay or insideInset or outsideOverlay or outsideInset
  app:scrollbars="none"http://none or vertical or horizontal
  />

所有屬性都不是必須泻肯。 注意EasyRecyclerView本質(zhì)并不是一個RecyclerView

設(shè)置空白View&加載View&錯誤View

xml中

app:layout_empty="@layout/view_empty"
app:layout_progress="@layout/view_progress"
app:layout_error="@layout/view_error"

代碼中

void setEmptyView(View emptyView)
void setProgressView(View progressView)
void setErrorView(View errorView)

然后可以隨時顯示他們

void showEmpty()
void showProgress()  
void showError()  
void showRecycler()

RecyclerArrayAdapter

這個Adapter與本RecyclerView沒有任何耦合渊迁。你可以使用其他adapter。也可以把本adapter用于其他RecyclerView

整合了數(shù)據(jù)增刪的功能

void add(T object);
void addAll(Collection<? extends T> collection);
void addAll(T ... items);
void insert(T object, int index);
void remove(T object)
void clear()
void sort(Comparator<? super T> comparator)

整合的Header與Footer的實現(xiàn)

void addHeader(ItemView view)
void addFooter(ItemView view)

ItemView不是view而是view生成器
對應(yīng)Adapter的onCreate與onBind方法,所以onCreate后會多次onBind灶挟。
建議數(shù)據(jù)加載完畢后再add琉朽。onCreate里初始化UI。不使用onBind稚铣。

public interface ItemView {
     View onCreateView(ViewGroup parent);
     void onBindView(View itemView);
}

## Header與Footer完美適配

LinearLayoutManager,GridLayoutManager,StaggeredGridLayoutManager
在GridLayoutManager模式中需額外加一句
```java
//make adapter obtain a LookUp for LayoutManager箱叁,param is maxSpan。
gridLayoutManager.setSpanSizeLookup(adapter.obtainGridSpanSizeLookUp(2));

整合OnItemClickListener與OnItemLongClickListener

adapter.setOnItemClickListener(new RecyclerArrayAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(int position) {
        //position不包含Header
    }
});

adapter.setOnItemLongClickListener(new RecyclerArrayAdapter.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(int position) {
        return true;
    }
});

與在ViewHolder中給itemView設(shè)置OnClickListener等效榛泛。若重復(fù)設(shè)置ViewHolder中的設(shè)置會被替換蝌蹂。
如果在RecyclerView布局以后再設(shè)置。需要再使用'notifyDataSetChange()'曹锨。

下面的功能是在adapter最后添加一個footer孤个。來顯示各種狀態(tài)。

加載更多

void setMore(final int res,OnMoreListener listener);
void setMore(final View view,OnMoreListener listener);

注意一定當(dāng)添加0條數(shù)據(jù)或null時,會結(jié)束加載更多,顯示沒有更多沛简。
也可以在最后一頁手動調(diào)用adapter.stopMore();

加載錯誤

void setError(final int res,OnErrorListener listener)
void setError(final View view,OnErrorListener listener)
  1. adapter.pauseMore()暫停加載更多齐鲤,顯示錯誤View斥废。
  2. 暫停時如果再次添加數(shù)據(jù)。自動恢復(fù)加載更多给郊。
  3. 當(dāng)錯誤View再次被顯示時牡肉。會恢復(fù)成加載更多view。并回掉加載更多;
  4. adapter.resumeMore()繼續(xù)加載更多淆九,顯示加載更多View统锤,并立即回調(diào)加載更多。
  5. 比如你可以給錯誤View設(shè)置點擊重試炭庙。點擊調(diào)用resumeMore饲窿。

沒有更多
在adapter里設(shè)置,當(dāng)停止加載后就會顯示在最后一個焕蹄。

void setNoMore(final int res,OnNoMoreListener listener)
void setNoMore(final View view,OnNoMoreListener listener)

BaseViewHolder<M>

這個ViewHolder將每個item與adapter解耦逾雄。adapter只管實例化對應(yīng)ViewHolder.每個Item的view生成,findviewbyid,UI修改都由viewHolder自己管理。
列如:

public class PersonViewHolder extends BaseViewHolder<Person> {
    private TextView mTv_name;
    private SimpleDraweeView mImg_face;
    private TextView mTv_sign;


    public PersonViewHolder(ViewGroup parent) {
        super(parent,R.layout.item_person);
        mTv_name = $(R.id.person_name);
        mTv_sign = $(R.id.person_sign);
        mImg_face = $(R.id.person_face);
    }

    @Override
    public void setData(final Person person){
        mTv_name.setText(person.getName());
        mTv_sign.setText(person.getSign());
        mImg_face.setImageURI(Uri.parse(person.getFace()));
    }
}

-----------------------------------------------------------------------

public class PersonAdapter extends RecyclerArrayAdapter<Person> {
    public PersonAdapter(Context context) {
        super(context);
    }

    @Override
    public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
        return new PersonViewHolder(parent);
    }
}

Decoration

這里提供了2種常用Decoration供大家使用腻脏。
DividerDecoration
通常用在LinearLayoutManager的情況下鸦泳。在item之間添加分割線。

DividerDecoration itemDecoration = new DividerDecoration(Color.GRAY, Util.dip2px(this,0.5f), Util.dip2px(this,72),0);//顏色 & 高度 & 左邊距 & 右邊距
itemDecoration.setDrawLastItem(true);//有時候你不想讓最后一個item有分割線,默認(rèn)true.
itemDecoration.setDrawHeaderFooter(false);//是否對Header于Footer有效,默認(rèn)false.
recyclerView.addItemDecoration(itemDecoration);

這是效果:


SpaceDecoration
通常用于GridLayoutManager和StaggeredGridLayoutManager永品。在View之間添加間距做鹰。

SpaceDecoration itemDecoration = new SpaceDecoration((int) Utils.convertDpToPixel(8,this));//參數(shù)是距離寬度
itemDecoration.setPaddingEdgeSide(true);//是否為左右2邊添加padding.默認(rèn)true.
itemDecoration.setPaddingStart(true);//是否在給第一行的item添加上padding(不包含header).默認(rèn)true.
itemDecoration.setPaddingHeaderFooter(false);//是否對Header于Footer有效,默認(rèn)false.
recyclerView.addItemDecoration(itemDecoration);

這是效果:

另外:

雖然與我的庫沒什么關(guān)系,但很多人在問就寫一下吧腐碱。item的水波紋效果
在你item的View加上這一條屬性:

android:foreground="?android:attr/selectableItemBackground"

就好了...

實戰(zhàn):

布局文件:

main_activity.xml

<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'DejaVu Sans Mono';font-size:13.5pt;"><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.administrator.easyrecyviewtest.MainActivity">

 <com.jude.easyrecyclerview.EasyRecyclerView  android:id="@+id/recyclerView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:recyclerClipToPadding="true"
  app:recyclerPadding="8dp"
  app:recyclerPaddingBottom="8dp"
  app:recyclerPaddingLeft="8dp"
  app:recyclerPaddingRight="8dp"
  app:recyclerPaddingTop="8dp"
  app:scrollbarStyle="insideOverlay"
  app:scrollbars="none" />
</RelativeLayout></pre>

view_more.xml

<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'DejaVu Sans Mono';font-size:13.5pt;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="48dp"
  android:gravity="center">
 <ProgressBar  android:layout_width="28dp"
  android:layout_height="28dp"
  android:indeterminate="false"/>
 <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="更多加載中……"/>

</LinearLayout></pre>

view_nomore.xml

<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'DejaVu Sans Mono';font-size:13.5pt;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="48dp">
 <TextView  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:gravity="center"
  android:text="(* ̄ω ̄) 沒有更多了"/>
</LinearLayout></pre>

具體步驟:

mainactivity-->setadapter-->viewholder-->picture

mainactivity

public class MainActivity extends AppCompatActivity {
    private EasyRecyclerView recyclerView;
    private ImageAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (EasyRecyclerView) findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
        recyclerView.setAdapter(adapter = new ImageAdapter(this));

        //添加headrd
//        adapter.addHeader(new RecyclerArrayAdapter.ItemView() {
//            @Override
//            public View onCreateView(ViewGroup parent) {
//                RollPagerView header = new RollPagerView(MainActivity.this);
//                header.setHintView(new ColorPointHintView(MainActivity.this, Color.YELLOW,Color.GRAY));
//                header.setHintPadding(0, 0, 0, (int) convertDpToPixel(8, MainActivity.this));
//                header.setPlayDelay(2000);
//                header.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) Utils.convertDpToPixel(200, StaggeredGridActivity.this)));
//                header.setAdapter(new BannerAdapter(MainActivity.this));
//                return header;
//            }
//
//            @Override
//            public void onBindView(View headerView) {
//
//            }
//        });

        //添加邊框
        SpaceDecoration itemDecoration = new SpaceDecoration((int) convertDpToPixel(8,this));
        itemDecoration.setPaddingEdgeSide(true);
        itemDecoration.setPaddingStart(true);
        itemDecoration.setPaddingHeaderFooter(false);
        recyclerView.addItemDecoration(itemDecoration);




        //更多加載
        adapter.setMore(R.layout.view_more, new RecyclerArrayAdapter.OnMoreListener() {
            @Override
            public void onMoreShow() {
                addData();
            }

            @Override
            public void onMoreClick() {

            }
        });
        //移除加載更多頁腳
        //adapter.stopMore();
        //沒有更多
        adapter.setNoMore(R.layout.view_nomore);

        //寫刷新事件
        recyclerView.setRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                recyclerView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //adapter.clear();
                       // adapter.addAll(DataProvider.getPictures(0));
                    }
                },1000);
            }
        });

        //點擊事件
        adapter.setOnItemClickListener(new RecyclerArrayAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(int position) {
                //position不包含Header
                Toast.makeText(getApplicationContext(),
                     position+"", Toast.LENGTH_LONG).show();
            }
        });

        adapter.setOnItemLongClickListener(new RecyclerArrayAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(int position) {
                Toast.makeText(getApplicationContext(),
                        position+"", Toast.LENGTH_LONG).show();
                return true;
            }
        });
        addData();
    }

    private void addData(){
        recyclerView.postDelayed(new Runnable() {
            @Override
            public void run() {
                adapter.addAll(DataProvider.getPictures(0));
            }
        },1000);
    }

    public static float convertDpToPixel(float dp, Context context){
        Resources resources = context.getResources();
        DisplayMetrics metrics = resources.getDisplayMetrics();
        float px = dp * (metrics.densityDpi / 160f);
        return px;
    }
}

ImageAdapter

public class ImageAdapter extends RecyclerArrayAdapter<Picture> {
    public ImageAdapter(Context context) {
        super(context);
    }

    @Override
    public BaseViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) {
        return new ImageViewHolder(parent);
    }
}

ImageViewHolder

public class ImageViewHolder extends BaseViewHolder<Picture> {
    ImageView imgPicture;

    public ImageViewHolder(ViewGroup parent) {
        super(new ImageView(parent.getContext()));
        imgPicture = (ImageView) itemView;
        imgPicture.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        imgPicture.setScaleType(ImageView.ScaleType.CENTER_CROP);
    }

    @Override
    public void setData(Picture data) {
        ViewGroup.LayoutParams params = imgPicture.getLayoutParams();

        DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
        int width = dm.widthPixels/2;//寬度為屏幕寬度一半
        int height = data.getHeight()*width/data.getWidth();//計算View的高度

        params.height = height;
        imgPicture.setLayoutParams(params);
        //imgPicture.setImageResource(R.mipmap.ic_launcher);
        Glide.with(getContext())
                .load(data.getSrc()+"?imageView2/0/w/"+ width)
                .into(imgPicture);
    }
}

Picture

public class Picture {
    int width;
    int height;
    String src;

    public Picture(int width, int height, String src) {
        this.width = width;
        this.height = height;
        this.src = src;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getSrc() {
        return src;
    }

    public void setSrc(String src) {
        this.src = src;
    }
}

DataProvider

public class DataProvider {


    static final Picture[] VIRTUAL_PICTURE = {
            new Picture(566,800,"http://o84n5syhk.bkt.clouddn.com/57154327_p0.png"),
            new Picture(2126,1181,"http://o84n5syhk.bkt.clouddn.com/57180221_p0.jpg"),
            new Picture(1142,800,"http://o84n5syhk.bkt.clouddn.com/57174070_p0.jpg"),
            new Picture(550,778,"http://o84n5syhk.bkt.clouddn.com/57166531_p0.jpg"),
            new Picture(1085,755,"http://o84n5syhk.bkt.clouddn.com/57151022_p0.jpg"),
            new Picture(656,550,"http://o84n5syhk.bkt.clouddn.com/57172236_p0.jpg"),
            new Picture(1920,938,"http://o84n5syhk.bkt.clouddn.com/57174564_p0.jpg"),
            new Picture(1024,683,"http://o84n5syhk.bkt.clouddn.com/57156832_p0.jpg"),
            new Picture(723,1000,"http://o84n5syhk.bkt.clouddn.com/57151474_p0.png"),
            new Picture(2000,1667,"http://o84n5syhk.bkt.clouddn.com/57156623_p0.png"),
    };
    public static ArrayList<Picture> getPictures(int page){
        ArrayList<Picture> arrayList = new ArrayList<>();
        for (int i = 0; i < VIRTUAL_PICTURE.length; i++) {
            arrayList.add(VIRTUAL_PICTURE[i]);
        }
        return arrayList;
    }
}

測試:

my.gif

使用注意事項:

由于ViewHolder使用的是ViewGroup作為parent
所以布局文件需要在最外面放置一個相對布局作為父容器誊垢。
類似:

<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'DejaVu Sans Mono';font-size:13.5pt;"><?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="72dp"
  android:gravity="center_vertical"
  android:foreground="?android:attr/selectableItemBackground"
  android:background="@android:color/white">
 <ImageView  android:id="@+id/person_face"
  android:layout_width="48dp"
  android:layout_height="48dp"
  android:layout_marginLeft="16dp"
  android:layout_centerVertical="true"
  />
 <LinearLayout  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_toRightOf="@+id/person_face"
  android:gravity="center_vertical"
  android:layout_marginLeft="16dp"
  android:orientation="vertical">
 <TextView  android:id="@+id/person_name"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:textSize="16sp"
  android:gravity="center_vertical"
  />
 <TextView  android:id="@+id/person_sign"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:singleLine="true"
  android:textColor="@android:color/darker_gray"
  />

 </LinearLayout></RelativeLayout></pre>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掉弛,一起剝皮案震驚了整個濱河市症见,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌殃饿,老刑警劉巖谋作,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乎芳,居然都是意外死亡遵蚜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門奈惑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吭净,“玉大人,你說我怎么就攤上這事肴甸〖叛常” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵原在,是天一觀的道長友扰。 經(jīng)常有香客問我彤叉,道長,這世上最難降的妖魔是什么村怪? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任秽浇,我火速辦了婚禮,結(jié)果婚禮上甚负,老公的妹妹穿的比我還像新娘柬焕。我一直安慰自己,他們只是感情好梭域,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布击喂。 她就那樣靜靜地躺著,像睡著了一般碰辅。 火紅的嫁衣襯著肌膚如雪懂昂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天没宾,我揣著相機(jī)與錄音凌彬,去河邊找鬼。 笑死循衰,一個胖子當(dāng)著我的面吹牛铲敛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播会钝,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼伐蒋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了迁酸?” 一聲冷哼從身側(cè)響起先鱼,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奸鬓,沒想到半個月后焙畔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡串远,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年宏多,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澡罚。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡伸但,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出留搔,到底是詐尸還是另有隱情更胖,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站函喉,受9級特大地震影響避归,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜管呵,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一梳毙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捐下,春花似錦账锹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至婴程,卻和暖如春廓奕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背档叔。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工桌粉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人衙四。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓铃肯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親传蹈。 傳聞我的和親對象是個殘疾皇子押逼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

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