Android :Activity中切換不同狀態(tài)頁:加載中妇蛀,加載失敗,數(shù)據(jù)頁笤成,空頁面……

在Android應(yīng)用中评架,基本每個應(yīng)用都會有網(wǎng)絡(luò)加載數(shù)據(jù)的實現(xiàn),也基本上需要實現(xiàn)在網(wǎng)絡(luò)加載數(shù)據(jù)后出現(xiàn)的不同頁面炕泳,一般有4種纵诞,分別是加載中頁面 加載失敗顯示的頁面,加載成功數(shù)據(jù)的頁面 以及 加載沒有數(shù)據(jù)的空頁面培遵。如果采用對每一個頁面加載數(shù)據(jù)進(jìn)行處理的方法浙芙,就會很麻煩,接下來就介紹兩種方式來解決這個問題籽腕,第一種嗡呼,半徹底式,第二種皇耗,徹底式南窗。
先來看第一種方式

1.EmptyLayout(自定義ViewGroup):

先來看看4種效果:分別是 加載錯誤 空頁面 加載有數(shù)據(jù) 以及加載錯誤點擊重新加載 (設(shè)置出來為加載中)

GIF.gif

上面簡單模擬了下幾種狀態(tài),就是一個自定義ViewGroup郎楼,里面有一個ProgressBar ImageVIew 和一個TextView矾瘾,先看一下布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal">

        <ImageView
            android:id="@+id/img_error_layout"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:contentDescription="@null"
            android:visibility="gone" />

        <ProgressBar
            android:id="@+id/animProgress"
            android:layout_width="30dip"
            android:layout_height="30dip" />
    </RelativeLayout>

    <TextView
        android:id="@+id/tv_error_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10.0dip"
        android:gravity="center"
        android:lines="2"
        android:textColor="@android:color/darker_gray"
        android:textSize="17sp" />
</LinearLayout>

布局很簡單,接下來看一下EmptyLayout的代碼:

public class EmptyView extends LinearLayout implements View.OnClickListener {
    public static final int NETWORK_LOADING = 1; // 加載中
    public static final int NODATA = 2; // 沒有數(shù)據(jù)
    public static final int NETWORK_ERROR = 3; // 網(wǎng)絡(luò)錯誤
    public static final int HIDE_LAYOUT = 4; // 隱藏

    private int mErrorState = NETWORK_LOADING;//初始化為加載狀態(tài)

    private ProgressBar animProgress;
    private ImageView img;
    private TextView tv;

    private String strNoDataContent;
    private String strErrorContent;
    private int imgNoDataImage = -1;
    private int imgErrorImage = -1;

    private OnClickListener listener;

    public EmptyView(Context context) {
        this(context, null);
    }

    public EmptyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        View view = LayoutInflater.from(getContext()).inflate(R.layout.view_empty, null);
        animProgress = (ProgressBar) view.findViewById(R.id.animProgress);
        img = (ImageView) view.findViewById(R.id.img_error_layout);
        tv = (TextView) view.findViewById(R.id.tv_error_layout);
        
        //初始化設(shè)置
        if (getVisibility() == View.GONE) {
            setErrorType(HIDE_LAYOUT);
        } else {
            setErrorType(NETWORK_LOADING);
        }
        setOnClickListener(this);
        //圖片去觸發(fā)點擊事件
        img.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (listener != null) {
                    listener.onClick(view);
                }
            }
        });
        addView(view);
    }

    //自定義點擊監(jiān)聽(圖片會攔截 EmptyVIew的點擊事件箭启,所以也需要對圖片進(jìn)行設(shè)置點擊事件)
    public void setOnLayoutClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    //整個EmptyVIew去觸發(fā)點擊事件
    @Override
    public void onClick(View view) {
        if (listener != null) {
            listener.onClick(view);
        }
    }

    //判斷3種狀態(tài)
    public boolean isLoadError() {
        return mErrorState == NETWORK_ERROR;
    }
    public boolean isLoading() {
        return mErrorState == NETWORK_LOADING;
    }
    public boolean isLoadingNoData() {
        return mErrorState == NODATA;
    }

    //傳入不同狀態(tài)的圖片 文字
    public void setErrorImag(int imgResource) {
        imgErrorImage = imgResource;
    }
    public void setNoDataImag(int imgResource) {
        imgNoDataImage = imgResource;
    }
    public void setErrorContent(String msg) {
        strErrorContent = msg;
    }
    public void setNoDataContent(String noDataContent) {
        strNoDataContent = noDataContent;
    }
    public void setErrorType(int type) {
        setVisibility(View.VISIBLE);
        mErrorState = type;
        switch (type) {
            case NETWORK_LOADING:
                animProgress.setVisibility(View.VISIBLE);
                img.setVisibility(View.GONE);
                tv.setVisibility(View.VISIBLE);
                tv.setText("正在加載...");
                setVisibility(View.VISIBLE);
                break;
            case NODATA:
                animProgress.setVisibility(View.GONE);
                img.setImageResource(imgNoDataImage == -1 ? R.mipmap.empty : imgNoDataImage);
                img.setVisibility(View.VISIBLE);
                tv.setText(strNoDataContent == null ? "點擊屏幕壕翩,重新加載" : strNoDataContent);
                tv.setVisibility(View.VISIBLE);
                setVisibility(View.VISIBLE);
                break;
            case NETWORK_ERROR:
                animProgress.setVisibility(View.GONE);
                img.setImageResource(imgErrorImage == -1 ? R.mipmap.error_no_wifi : imgErrorImage);
                img.setVisibility(View.VISIBLE);
                tv.setText(strErrorContent == null ? "點擊屏幕,重新加載" : strErrorContent);
                tv.setVisibility(View.VISIBLE);
                setVisibility(View.VISIBLE);
                break;
            case HIDE_LAYOUT:
                setVisibility(View.GONE);
                break;
            default:
                break;
        }
    }

    @Override
    public void setVisibility(int visibility) {
        if (visibility == View.GONE) {
            mErrorState = HIDE_LAYOUT;
        }
        super.setVisibility(visibility);
    }
}

也很簡單傅寡,主要是注意一下邏輯清晰放妈,實現(xiàn)還是蠻容易的,注釋都有荐操,就不多做解釋了芜抒,接下來來看一下對EmptyLayout空間的使用
xml布局中:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/bill_navi_layout"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#EFEFF4"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="10dp">
      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="我是有內(nèi)容的"/>
    </LinearLayout>

    <com.example.base.view.EmptyView
        android:id="@+id/empty"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </com.example.base.view.EmptyView>
</RelativeLayout>

上面的線性布局簡單代表了一個有內(nèi)容的頁面,將EmptyLayout放置在整個布局的中間托启,操作VIew的Visiable和Gone來顯示不同的頁面

使用示例:

public class EmptyActivity extends TitleActivity {

    @BindView(R.id.empty)
    EmptyView empty;
    @BindView(R.id.bill_navi_layout)
    LinearLayout billNaviLayout;

    @Override
    public void onInitView(Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);
        setContentView(R.layout.activity_empty);
        ButterKnife.bind(this);
        billNaviLayout.setVisibility(View.GONE);//初始化內(nèi)容頁面為不顯示

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);//模擬加載過程
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //NETWORK_ERROR     NODATA    HIDE_LAYOUT  NETWORK_LOADING
                              empty.setErrorType(EmptyView.NETWORK_ERROR);//錯誤頁面

//                            empty.setErrorType(EmptyView.NODATA);//空頁面

//                            empty.setErrorType(EmptyView.HIDE_LAYOUT);//有內(nèi)容頁面
//                            billNaviLayout.setVisibility(View.Visiable);//設(shè)置為顯示
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //點擊事件
        empty.setOnLayoutClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                empty.setErrorType(EmptyView.NETWORK_LOADING);
            }
        });
    }
}

2.StateViewHelper(基類實現(xiàn)宅倒,一勞永逸)

第二種實現(xiàn)方式邏輯比較第一種較為復(fù)雜一點,但是在后續(xù)的使用上卻比第一種更加靈活以及簡便屯耸,且更符合Android封裝的特點拐迁,實現(xiàn)始難后易蹭劈。
看一下很挫的動畫吧,功能實現(xiàn)妥妥的线召,媽的铺韧,就是不會寫博客啊。缓淹。哈打。

GIF.gif

上面一樣是每一個狀態(tài)延遲2s后實現(xiàn),和網(wǎng)絡(luò)加載后顯示不同的VIew一一對應(yīng)讯壶,和EmptyView一樣

public class EmptyActivity extends TitleActivity {

    @BindView(R.id.empty)
    EmptyView empty;
    @BindView(R.id.bill_navi_layout)
    LinearLayout billNaviLayout;

    @Override
    public void onInitView(Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);
        setContentView(R.layout.activity_empty);
        ButterKnife.bind(this);
        billNaviLayout.setVisibility(View.VISIBLE);//初始化內(nèi)容頁面為不顯示
        empty.setVisibility(View.GONE);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);//模擬加載過程
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
//                            setMode(StateViewHelper.MODE_LOADING);
//                            setMode(StateViewHelper.MODE_ERROR);
                            setMode(StateViewHelper.MODE_EMPTY);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

都是先展示自己的ContentView料仗,然后各自設(shè)置不同網(wǎng)絡(luò)加載后的狀態(tài)VIew,接下來看具體的封裝伏蚊。

首先上自定義的這個StateViewHelper類

public abstract class StateViewHelper {
    public static final int MODE_LOADING = 0;
    public static final int MODE_CONTENT = 1;
    public static final int MODE_EMPTY = 2;
    public static final int MODE_ERROR = 3;

    private int mMode = MODE_CONTENT;
    private View[] mModeViews = new View[4];
    private ViewGroup.LayoutParams[] mModeParams = new ViewGroup.LayoutParams[4];

    private Context mContext;
    private ViewGroup mContent ;
    public StateViewHelper(Context context){
            super();
            this.mContext = context;
    }
    //將父View添加進(jìn)來
    public void setContentRoot(ViewGroup contentView) {
        this.mContent = contentView;
    }

    //根據(jù)Id設(shè)置View到父View里面
    public void setContentView(int layoutResID) {
        View view = LayoutInflater.from(mContext).inflate(layoutResID, mContent, false);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );
        setContentView(view, params);
    }
    //設(shè)置View到父View里面
    public void setContentView(View view) {
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        setContentView(view, params);
    }
    //根據(jù)布局參數(shù)添加到父View里面
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        setModeView(view, params, MODE_CONTENT);
    }

    //添加四種布局 的View 和 Mode
    public void setModeView(View view, int mode) {
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );
        setModeView(view, params, mode);
    }
    public void setModeView(int view, int mode) {
        View subView = LayoutInflater.from(mContext).inflate(view, mContent, false);
        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        );
        setModeView(subView, params, mode);
    }
    public void setModeView(View view, ViewGroup.LayoutParams params, int mode) {
        checkMode(mode);//檢查罢维,只允許4種View中的mode存在
        mModeViews[mode] = view;//添加mode 和 Params到數(shù)組中
        mModeParams[mode] = params;

        if(mMode == mode&&mContent!=null){//如果是ContentVIew的話 就添加到父VIew中
            clearContentView();
            mContent.addView(view,params);
        }
    }


    //通過父View去查找子VIew
    public View findViewById(int id){
        if(mContent!=null){
            View view = mContent.findViewById(id);
            return view;
        }
        return null;
    }

    //清楚父VIew中的子VIew
    private void clearContentView() {
      if( mContent!=null){
          for (int i = 0, size = mContent.getChildCount(); i < size; i++) {
              View subView = mContent.getChildAt(i);
              if (onViewClear(subView)) {
                  mContent.removeView(subView);
              }
          }
      }
    }

    //子類實現(xiàn),如果子View不等于null 并且 不等于Toolbar丙挽,因為子VIew里面也會包含Toolbar肺孵,所以需要去掉
    public abstract boolean onViewClear(View subView);

    //根據(jù)邏輯設(shè)置不同的mode,然后去改變子VIew
    public void setMode(int mode){
        if(mode == mMode) return;
        checkMode(mode);
        mMode = mode;

        clearContentView();
        View mModeView = mModeViews[mode];
        if (mModeView == null) return;

        ViewGroup.LayoutParams mModeParam = mModeParams[mode];
        if (mModeParam == null) {
            mModeParam = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT
            );
        }
        if (mContent == null) return;
        mContent.addView(mModeView,mModeParam);

        //如果是加載的View颜阐,就添加動畫
        if(mode==MODE_LOADING){
            final ImageView mAnimationView = (ImageView) findViewById(R.id.h_x_loading);
            Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(
                    mContext, R.anim.loading_animation);
            mAnimationView.startAnimation(hyperspaceJumpAnimation);
        }
    }

    private void checkMode(int mode) {
        if (mode != MODE_LOADING && mode != MODE_ERROR
                && mode != MODE_EMPTY && mode != MODE_CONTENT) {
            throw new IllegalStateException("illegal mode for content, please check StateViewHelper");
        }
    }

    public int getMode() {
        return mMode;
    }
}

代碼注釋每一個都寫好了平窘,不講解了,懶凳怨。瑰艘。。

再來看下第2 基類肤舞,之所以說是第2基類紫新,就是任何項目都可以去基礎(chǔ)的類叫基類,第2基類是說在某一個項目中需要使用到這個功能李剖,就可以定義在第2基類中芒率。

public class TitleActivity extends BaseActivity {
    private  StateViewHelper stateViewHelper;
    private Toolbar mToolbar;
    private ActionBar mActionBar;
    @Override
    public void onInitView(Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);
        super.setContentView(R.layout.common_title_bar);

        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);
        mActionBar = getSupportActionBar();
        if (mActionBar != null) {
            mActionBar.setDisplayHomeAsUpEnabled(true);
        }
        //初始化 為ContentView
        stateViewHelper = new BaseStateViewWrapper(this);
        setMode(StateViewHelper.MODE_CONTENT);
        stateViewHelper.setContentRoot((ViewGroup) findViewById(R.id.container));
        //添加三種mode的View進(jìn)去
        stateViewHelper.setModeView(R.layout.view_activity_loading, StateViewHelper.MODE_LOADING);
        stateViewHelper.setModeView(R.layout.view_activity_error, StateViewHelper.MODE_ERROR);
        stateViewHelper.setModeView(R.layout.view_activity_empty, StateViewHelper.MODE_EMPTY);
    }
    //先去找父View一個級別的view,如果為null篙顺,則去找子VIew里面的view
    public View findViewById(int id){
        View view = super.findViewById(id);
        if(view!=null){
            return view;
        } else {
            return stateViewHelper.findViewById(id);
        }
    }

    public Toolbar getToolbar() {
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        return mToolbar;
    }
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mToolbar.setTitle(title);
    }
    @Override
    public void setTitle(int titleId) {
        super.setTitle(titleId);
        mToolbar.setTitle(titleId);
    }
    public void hideTitleBar() {
        if (mActionBar != null) {
            mActionBar.hide();
        }
    }
    //設(shè)置ContentVIew偶芍,子類調(diào)用
    public void setContentView(int layoutResID) {
        stateViewHelper.setContentView(layoutResID);
    }
    public void setContentView(View view) {
        stateViewHelper.setContentView(view);
    }
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        stateViewHelper.setContentView(view, params);
    }
    public void setModeView(View view, int mode) {
        stateViewHelper.setModeView(view, mode);
    }
    public void setModeView(int view, int mode) {
        stateViewHelper.setModeView(view, mode);
    }
    public void setMode(int mode) {
        stateViewHelper.setMode(mode);
    }
    public int getMode() {
        return stateViewHelper.getMode();
    }

    private class BaseStateViewWrapper extends StateViewHelper {

        public BaseStateViewWrapper(Context context) {
            super(context);
        }
        @Override
        public boolean onViewClear(View subView) {
            return subView != null && subView != mToolbar;
        }
    }
}

第2基類的xml布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="?attr/colorPrimary"
    android:fitsSystemWindows="true"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <include layout="@layout/toolbar_default" />

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        android:background="@color/theme_color"/>

</LinearLayout>

就是一個Toolbar和一個FrameLayout,F(xiàn)rameLayout用來填充子VIew的德玫。經(jīng)過這樣封裝之后匪蟀,需要改變View,直接使用SetMode(mode),就可以來實現(xiàn)宰僧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末材彪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌段化,老刑警劉巖嘁捷,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異穗泵,居然都是意外死亡普气,警方通過查閱死者的電腦和手機谜疤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門佃延,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夷磕,你說我怎么就攤上這事履肃。” “怎么了坐桩?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵尺棋,是天一觀的道長。 經(jīng)常有香客問我绵跷,道長膘螟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任碾局,我火速辦了婚禮荆残,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘净当。我一直安慰自己内斯,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布像啼。 她就那樣靜靜地躺著俘闯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪忽冻。 梳的紋絲不亂的頭發(fā)上真朗,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音僧诚,去河邊找鬼蜜猾。 笑死,一個胖子當(dāng)著我的面吹牛振诬,可吹牛的內(nèi)容都是我干的蹭睡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赶么,長吁一口氣:“原來是場噩夢啊……” “哼肩豁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤清钥,失蹤者是張志新(化名)和其女友劉穎琼锋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祟昭,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡缕坎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了篡悟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谜叹。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖搬葬,靈堂內(nèi)的尸體忽然破棺而出荷腊,到底是詐尸還是另有隱情,我是刑警寧澤急凰,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布女仰,位于F島的核電站,受9級特大地震影響抡锈,放射性物質(zhì)發(fā)生泄漏疾忍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一床三、第九天 我趴在偏房一處隱蔽的房頂上張望一罩。 院中可真熱鬧,春花似錦勿璃、人聲如沸擒抛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歧沪。三九已至,卻和暖如春莲组,著一層夾襖步出監(jiān)牢的瞬間诊胞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工锹杈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撵孤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓竭望,卻偏偏與公主長得像邪码,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咬清,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫闭专、插件奴潘、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評論 4 62
  • 《誰何》—穿石—自古多情總被無情惱幾間皺冷泛葉凋零心雨陣陣與誰何 江楓霜露自知冷暖羌管斷瑟話凄涼好個白是秋! —2...
    東方詩空閱讀 189評論 0 1
  • Our Economics and Management college's new campus, dinghu...
    單字一個罅閱讀 334評論 0 0
  • 《其實水苑偶得》 夜寒室暖一壺茶影钉, 半醒半夢俗亦雅画髓。 輕舉香茗酬兄弟, 水苑小憩如歸家平委。
    _東哥閱讀 294評論 0 0