安卓開發-高仿ios時間選擇控件timepicker

在開發中如果有地址或者日期選擇等就會涉及到時間或者條件選擇器,大家都會想到仿iOS的三級聯動的效果,用wheelview實現,其實安卓原生自帶了時間和日期選擇器可能是效果來說太粗獷了,所以很多產品效果圖都是清一色的ios那種效果,ok,廢話說完了上圖

Demo地址:

1,安卓原生的時間和日期選擇器

代碼:download.csdn.net/download/qq_32487869/10111865

DatePickerDialog dialog = new

DatePickerDialog(MainActivity.this, new DatePickerDialog.OnDateSetListener() {

@Override

public void onDateSet(DatePicker view, int year, int monthOfYear, int

dayOfMonth) {

if(monthOfYear<=9){

mouth1="0"+(monthOfYear+1);

}else{

mouth1=String.valueOf(monthOfYear+1);

}

if(dayOfMonth<=9){

day1= "0"+dayOfMonth;

}else{

day1=String.valueOf(dayOfMonth);

}

dateStr = String.valueOf(year)+"-"+mouth1+"-"+day1;

button1.setText(dateStr);

}

}, calender.get(Calendar.YEAR), calender.get(Calendar.MONTH),

calender.get(Calendar.DAY_OF_MONTH));

dialog.show();

使用非常簡單,自己寫個時間過濾方法就行

TimePickerDialog dialog = new TimePickerDialog(MainActivity.this,

new TimePickerDialog.OnTimeSetListener() {

@Override

public void onTimeSet(TimePicker view, int hourOfDay, int minute) {

button2.setText(String.valueOf(hourOfDay+":"+minute));

}

},calender2.get(Calendar.HOUR),calender2.get(Calendar.MINUTE),false);

dialog.show();

DatePickerDialog和TimePickerDialog都是原生帶的,在5.0之前還是和ios那種效果差不多,來回上下滑選擇日期的,但是5.0后就成日歷了,雖然好看,不過占比屏太大,設計并不會考慮這種效果,哎,現在很多安卓的控件原生其實效果不錯的,不過還是得為了遵循產品和設計的意思做成仿ios效果(小小的抱怨一下)

2.開源日期選擇器Timepickview和條件選擇器Optionspickview

代碼:timepick:

TimePickerView pvTime = new TimePickerView.Builder(MainActivity.this, new TimePickerView.OnTimeSelectListener() {

@Override

public void onTimeSelect(Date date2, View v) {//選中事件回調

String time = getTime(date2);

button3.setText(time);

}

})

.setType(TimePickerView.Type.YEAR_MONTH_DAY)//默認全部顯示

.setCancelText("取消")//取消按鈕文字

.setSubmitText("確定")//確認按鈕文字

.setContentSize(20)//滾輪文字大小

.setTitleSize(20)//標題文字大小

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleText("請選擇時間")//標題文字

.setOutSideCancelable(true)//點擊屏幕,點在控件外部范圍時,是否取消顯示

.isCyclic(true)//是否循環滾動

.setTextColorCenter(Color.BLACK)//設置選中項的顏色

.setTitleColor(Color.BLACK)//標題文字顏色

.setSubmitColor(Color.BLUE)//確定按鈕文字顏色

.setCancelColor(Color.BLUE)//取消按鈕文字顏色

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleBgColor(0xFF666666)//標題背景顏色 Night mode

//? ? ? ? ? ? ? ? ? ? ? ? .setBgColor(0xFF333333)//滾輪背景顏色 Night mode

//? ? ? ? ? ? ? ? ? ? ? ? .setRange(calendar.get(Calendar.YEAR) - 20, calendar.get(Calendar.YEAR) + 20)//默認是1900-2100年

//? ? ? ? ? ? ? ? ? ? ? ? .setDate(selectedDate)// 如果不設置的話,默認是系統時間*/

//? ? ? ? ? ? ? ? ? ? ? ? .setRangDate(startDate,endDate)//起始終止年月日設定

//? ? ? ? ? ? ? ? ? ? ? ? .setLabel("年","月","日","時","分","秒")

.isCenterLabel(false) //是否只顯示中間選中項的label文字,false則每項item全部都帶有label。

//? ? ? ? ? ? ? ? ? ? ? ? .isDialog(true)//是否顯示為對話框樣式

.build();

pvTime.setDate(Calendar.getInstance());//注:根據需求來決定是否使用該方法(一般是精確到秒的情況),此項可以在彈出選擇器的時候重新設置當前時間,避免在初始化之后由于時間已經設定,導致選中時間與當前時間不匹配的問題。

pvTime.show();

注釋已經寫的很詳細了,各種選項干嘛用的

Optionspickview:代碼:

options1Items.clear();

options1Items.add("托兒索");

options1Items.add("兒童劫");

options1Items.add("小學生之手");

options1Items.add("德瑪西亞大保健");

options1Items.add("面對疾風吧");

options1Items.add("天王蓋地虎");

options1Items.add("我發一米五");

options1Items.add("爆劉繼芬");

OptionsPickerView pvOptions = new? OptionsPickerView.Builder(MainActivity.this, new OptionsPickerView.OnOptionsSelectListener() {

@Override

public void onOptionsSelect(int options1, int option2, int options3 ,View v) {

//返回的分別是三個級別的選中位置

String s =? options1Items.get(options1);

button4.setText(s);

}

})

//? ? ? ? ? ? ? ? ? ? ? ? .setSubmitText("確定")//確定按鈕文字

//? ? ? ? ? ? ? ? ? ? ? ? .setCancelText("取消")//取消按鈕文字

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleText("城市選擇")//標題

.setSubCalSize(20)//確定和取消文字大小

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleSize(20)//標題文字大小

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleColor(Color.BLACK)//標題文字顏色

.setSubmitColor(Color.BLUE)//確定按鈕文字顏色

.setCancelColor(Color.BLUE)//取消按鈕文字顏色

//? ? ? ? ? ? ? ? ? ? ? ? .setTitleBgColor(0xFF333333)//標題背景顏色 Night mode

//? ? ? ? ? ? ? ? ? ? ? ? .setBgColor(0xFF000000)//滾輪背景顏色 Night mode

//? ? ? ? ? ? ? ? ? ? ? ? .setContentTextSize(18)//滾輪文字大小

//? ? ? ? ? ? ? ? ? ? ? ? .setTextColorCenter(Color.BLUE)//設置選中項的顏色

.setTextColorCenter(Color.BLACK)//設置選中項的顏色

//? ? ? ? ? ? ? ? ? ? ? ? .setLineSpacingMultiplier(1.6f)//設置兩橫線之間的間隔倍數

//? ? ? ? ? ? ? ? ? ? ? ? .setLinkage(false)//設置是否聯動,默認true

//? ? ? ? ? ? ? ? ? ? ? ? .setLabels("省", "市", "區")//設置選擇的三級單位

//? ? ? ? ? ? ? ? ? ? ? ? .isCenterLabel(false) //是否只顯示中間選中項的label文字,false則每項item全部都帶有label。

//? ? ? ? ? ? ? ? ? ? ? ? .setCyclic(false, false, false)//循環與否

//? ? ? ? ? ? ? ? ? ? ? ? .setSelectOptions(1, 1, 1)? //設置默認選中項

//? ? ? ? ? ? ? ? ? ? ? ? .setOutSideCancelable(false)//點擊外部dismiss default true

//? ? ? ? ? ? ? ? ? ? ? ? .isDialog(true)//是否顯示為對話框樣式

.build();

pvOptions.setPicker(options1Items);

pvOptions.show();

條件自己定義,可以傳簡單集合,也可以傳別的,比如省市縣...

轉自:www.lxweimin.com/p/ba0faf749e73

3.結合wheelview和原生timepick自定義時間選擇器

用法:

final String[] str = new String[10];

ChangeDatePopwindow mChangeBirthDialog = new ChangeDatePopwindow(MainActivity.this);

mChangeBirthDialog.setDate("2017", "6", "20");

mChangeBirthDialog.showAtLocation(main, Gravity.BOTTOM, 0, 0);

mChangeBirthDialog.setBirthdayListener(new ChangeDatePopwindow.OnBirthListener() {

@Override

public void onClick(String year, String month, String day) {

// TODO Auto-generated method stub

Toast.makeText(MainActivity.this,year + "-" + month + "-" + day,Toast.LENGTH_LONG).show();

StringBuilder sb = new StringBuilder();

sb.append(year.substring(0, year.length() - 1)).append("-").append(month.substring(0, day.length() - 1)).append("-").append(day);

str[0] = year + "-" + month + "-" + day;

str[1] = sb.toString();

button5.setText(str[0]);

}

});

大致思路:

年-月-日,其實是三個wheelview,然后手動設置時間的范圍,繼承原有的adapter

一個例子

* Abstract wheel adapter provides common functionality for adapters.

*/

public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {

/** Text view resource. Used as a default view for adapter. */

public static final int TEXT_VIEW_ITEM_RESOURCE = -1;

/** No resource constant. */

protected static final int NO_RESOURCE = 0;

/** Default text color */

public static final int DEFAULT_TEXT_COLOR = 0xFF585858;

/** Default text color */

public static final int LABEL_COLOR = 0xFF700070;

/** Default text size */

public static final int DEFAULT_TEXT_SIZE = 18;

// Text settings

private int textColor = DEFAULT_TEXT_COLOR;

private int textSize = DEFAULT_TEXT_SIZE;

// Current context

protected Context context;

// Layout inflater

protected LayoutInflater inflater;

// Items resources

protected int itemResourceId;

protected int itemTextResourceId;

// Empty items resources

protected int emptyItemResourceId;

/**

* Constructor

* @param context the current context

*/

protected AbstractWheelTextAdapter(Context context) {

this(context, TEXT_VIEW_ITEM_RESOURCE);

}

/**

* Constructor

* @param context the current context

* @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views

*/

protected AbstractWheelTextAdapter(Context context, int itemResource) {

this(context, itemResource, NO_RESOURCE);

}

/**

* Constructor

* @param context the current context

* @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views

* @param itemTextResource the resource ID for a text view in the item layout

*/

protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {

this.context = context;

itemResourceId = itemResource;

itemTextResourceId = itemTextResource;

inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

}

/**

* Gets text color

* @return the text color

*/

public int getTextColor() {

return textColor;

}

/**

* Sets text color

* @param textColor the text color to set

*/

public void setTextColor(int textColor) {

this.textColor = textColor;

}

/**

* Gets text size

* @return the text size

*/

public int getTextSize() {

return textSize;

}

/**

* Sets text size

* @param textSize the text size to set

*/

public void setTextSize(int textSize) {

this.textSize = textSize;

}

/**

* Gets resource Id for items views

* @return the item resource Id

*/

public int getItemResource() {

return itemResourceId;

}

/**

* Sets resource Id for items views

* @param itemResourceId the resource Id to set

*/

public void setItemResource(int itemResourceId) {

this.itemResourceId = itemResourceId;

}

/**

* Gets resource Id for text view in item layout

* @return the item text resource Id

*/

public int getItemTextResource() {

return itemTextResourceId;

}

/**

* Sets resource Id for text view in item layout

* @param itemTextResourceId the item text resource Id to set

*/

public void setItemTextResource(int itemTextResourceId) {

this.itemTextResourceId = itemTextResourceId;

}

/**

* Gets resource Id for empty items views

* @return the empty item resource Id

*/

public int getEmptyItemResource() {

return emptyItemResourceId;

}

/**

* Sets resource Id for empty items views

* @param emptyItemResourceId the empty item resource Id to set

*/

public void setEmptyItemResource(int emptyItemResourceId) {

this.emptyItemResourceId = emptyItemResourceId;

}

/**

* Returns text for specified item

* @param index the item index

* @return the text of specified items

*/

protected abstract CharSequence getItemText(int index);

@Override

public View getItem(int index, View convertView, ViewGroup parent) {

if (index >= 0 && index < getItemsCount()) {

if (convertView == null) {

convertView = getView(itemResourceId, parent);

}

TextView textView = getTextView(convertView, itemTextResourceId);

if (textView != null) {

CharSequence text = getItemText(index);

if (text == null) {

text = "";

}

textView.setText(text);

if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {

configureTextView(textView);

}

}

return convertView;

}

return null;

}

@Override

public View getEmptyItem(View convertView, ViewGroup parent) {

if (convertView == null) {

convertView = getView(emptyItemResourceId, parent);

}

if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {

configureTextView((TextView)convertView);

}

return convertView;

}

/**

* Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.

* @param view the text view to be configured

*/

protected void configureTextView(TextView view) {

view.setTextColor(textColor);

view.setGravity(Gravity.CENTER);

view.setTextSize(textSize);

view.setEllipsize(TextUtils.TruncateAt.END);

view.setLines(1);

//? ? ? ? view.setCompoundDrawablePadding(20);

//? ? ? ? view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);

}

/**

* Loads a text view from view

* @param view the text view or layout containing it

* @param textResource the text resource Id in layout

* @return the loaded text view

*/

public TextView getTextView(View view, int textResource) {

TextView text = null;

try {

if (textResource == NO_RESOURCE && view instanceof TextView) {

text = (TextView) view;

} else if (textResource != NO_RESOURCE) {

text = (TextView) view.findViewById(textResource);

}

} catch (ClassCastException e) {

Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView");

throw new IllegalStateException(

"AbstractWheelAdapter requires the resource ID to be a TextView", e);

}

return text;

}

/**

* Loads view from resources

* @param resource the resource Id

* @return the loaded view or null if resource is not set

*/

public View getView(int resource, ViewGroup parent) {

switch (resource) {

case NO_RESOURCE:

return null;

case TEXT_VIEW_ITEM_RESOURCE:

return new TextView(context);

default:

return inflater.inflate(resource, parent, false);

}

}

還有設置滑動監聽,改變日期

wvYear.addChangingListener(new OnWheelChangedListener() {

@Override

public void onChanged(WheelView wheel, int oldValue, int newValue) {

// TODO Auto-generated method stub

String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem());

selectYear = currentText;

setTextviewSize(currentText, mYearAdapter);

currentYear = currentText.substring(0, currentText.length()-1).toString();

Log.d("currentYear==",currentYear);

setYear(currentYear);

initMonths(Integer.parseInt(month));

mMonthAdapter = new CalendarTextAdapter(context, arry_months, 0, maxTextSize, minTextSize);

wvMonth.setVisibleItems(5);

wvMonth.setViewAdapter(mMonthAdapter);

wvMonth.setCurrentItem(0);

calDays(currentYear, month);

}

});

wvYear.addScrollingListener(new OnWheelScrollListener() {

@Override

public void onScrollingStarted(WheelView wheel) {

// TODO Auto-generated method stub

}

@Override

public void onScrollingFinished(WheelView wheel) {

// TODO Auto-generated method stub

String currentText = (String) mYearAdapter.getItemText(wheel.getCurrentItem());

setTextviewSize(currentText, mYearAdapter);

}

});

wvMonth.addChangingListener(new OnWheelChangedListener() {

@Override

public void onChanged(WheelView wheel, int oldValue, int newValue) {

// TODO Auto-generated method stub

String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem());

selectMonth = currentText;

setTextviewSize(currentText, mMonthAdapter);

setMonth(currentText.substring(0, 1));

initDays(Integer.parseInt(day));

mDaydapter = new CalendarTextAdapter(context, arry_days, 0, maxTextSize, minTextSize);

wvDay.setVisibleItems(5);

wvDay.setViewAdapter(mDaydapter);

wvDay.setCurrentItem(0);

calDays(currentYear, month);

}

});

wvMonth.addScrollingListener(new OnWheelScrollListener() {

@Override

public void onScrollingStarted(WheelView wheel) {

// TODO Auto-generated method stub

}

@Override

public void onScrollingFinished(WheelView wheel) {

// TODO Auto-generated method stub

String currentText = (String) mMonthAdapter.getItemText(wheel.getCurrentItem());

setTextviewSize(currentText, mMonthAdapter);

}

});

wvDay.addChangingListener(new OnWheelChangedListener() {

@Override

public void onChanged(WheelView wheel, int oldValue, int newValue) {

// TODO Auto-generated method stub

String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem());

setTextviewSize(currentText, mDaydapter);

selectDay = currentText;

}

});

wvDay.addScrollingListener(new OnWheelScrollListener() {

@Override

public void onScrollingStarted(WheelView wheel) {

// TODO Auto-generated method stub

}

@Override

public void onScrollingFinished(WheelView wheel) {

// TODO Auto-generated method stub

String currentText = (String) mDaydapter.getItemText(wheel.getCurrentItem());

setTextviewSize(currentText, mDaydapter);

}

});

然后彈出的彈窗popuwindows里,設置時間

public String getYear() {

Calendar c = Calendar.getInstance();

return c.get(Calendar.YEAR)+"";

}

public String getMonth() {

Calendar c = Calendar.getInstance();

return c.get(Calendar.MONTH) + 1+"";

}

public String getDay() {

Calendar c = Calendar.getInstance();

return c.get(Calendar.DATE)+"";

}

public void initData() {

setDate(getYear(), getMonth(), getDay());

this.currentDay = 1+"";

this.currentMonth = 1+"";

}

/**

* 設置年月日

*

* @param year

* @param month

* @param day

*/

public void setDate(String year, String month, String day) {

selectYear = year + "年";

selectMonth = month + "月";

selectDay = day + "日";

issetdata = true;

this.currentYear = year;

this.currentMonth = month;

this.currentDay = day;

if (year == getYear()) {

this.month = getMonth();

} else {

this.month = 12+"";

}

calDays(year, month);

}

/**

* 設置年份

*

* @param year

*/

public int setYear(String year) {

int yearIndex = 0;

if (!year.equals(getYear())) {

this.month = 12+"";

} else {

this.month = getMonth();

}

for (int i = Integer.parseInt(getYear()); i > 1950; i--) {

if (i == Integer.parseInt(year)) {

return yearIndex;

}

yearIndex++;

}

return yearIndex;

}

/**

* 設置月份

*

* @param month

* @param month

* @return

*/

public int setMonth(String month) {

int monthIndex = 0;

calDays(currentYear, month);

for (int i = 1; i < Integer.parseInt(this.month); i++) {

if (Integer.parseInt(month) == i) {

return monthIndex;

} else {

monthIndex++;

}

}

return monthIndex;

}

/**

* 計算每月多少天

*

* @param month

* @param year

*/

public void calDays(String year, String month) {

boolean leayyear = false;

if (Integer.parseInt(year) % 4 == 0 && Integer.parseInt(year) % 100 != 0) {

leayyear = true;

} else {

leayyear = false;

}

for (int i = 1; i <= 12; i++) {

switch (Integer.parseInt(month)) {

case 1:

case 3:

case 5:

case 7:

case 8:

case 10:

case 12:

this.day = 31+"";

break;

case 2:

if (leayyear) {

this.day = 29+"";

} else {

this.day = 28+"";

}

break;

case 4:

case 6:

case 9:

case 11:

this.day = 30+"";

break;

}

}

if (year.equals( getYear()) && month .equals( getMonth())) {

this.day = getDay();

}

然后設置點擊事件

@Override

public void onClick(View v) {

if (v == btnSure) {

if (onBirthListener != null) {

onBirthListener.onClick(selectYear, selectMonth, selectDay);

Log.d("cy",""+selectYear+""+selectMonth+""+selectDay);

}

} else if (v == btnSure) {

}? else {

dismiss();

}

dismiss();

}

其實就是點擊確定保存選擇的日期,取消dismiss

底下確定鍵是黃色按鈕那個就是換了個樣式而已原理都是一樣的

Demo地址:download.csdn.net/download/qq_32487869/10111865

大神勿噴,像各位大佬學習!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容