Android動(dòng)畫機(jī)制總結(jié)筆記--屬性動(dòng)畫PropertyAnimation篇之ValueAnimator

注意:本篇文章是本人閱讀關(guān)于Android動(dòng)畫的文章所寫下的總結(jié)徘意,方便以后查閱,所有內(nèi)容非原創(chuàng),侵權(quán)刪宝穗。

本篇文章內(nèi)容來自于

  1. Android高級(jí)進(jìn)階 顧浩鑫
  2. Android自定義控件三部曲文章索引之動(dòng)畫篇

目錄

4.屬性動(dòng)畫PropertyAnimation(基類Animator)
--4.1 ValueAnimator
----4.1.1 ValueAnimator構(gòu)造函數(shù)
----4.1.2 ValueAnimator常用方法
----4.1.3 ValueAnimator監(jiān)聽器(2種)
----4.1.4 ValueAnimator代碼實(shí)現(xiàn)(5種)【3和5待補(bǔ)】
----4.1.5 首先理解interpolator和Evaluator的功能和關(guān)系
----4.1.6 interpolator插值器(系統(tǒng)+自定義)
----4.1.7 Evaluator(系統(tǒng)+自定義)
----4.1.8 ValueAnimator XML實(shí)現(xiàn)

4.屬性動(dòng)畫PropertyAnimation(基類Animator)

一個(gè)完整的屬性動(dòng)畫由兩部分組成:
1.計(jì)算動(dòng)畫各個(gè)幀的相關(guān)屬性值
2.將這些屬性值設(shè)置給指定的對(duì)象

4.1 ValueAnimator(屬性動(dòng)畫最重要的類)

ValueAnimator只實(shí)現(xiàn)了屬性動(dòng)畫應(yīng)該具備的兩個(gè)功能的第一個(gè)昂芜,第二部分由開發(fā)者自行設(shè)置。
即ValueAnimator不會(huì)對(duì)控件做任何操作请梢,我們可以給它設(shè)定從哪個(gè)值運(yùn)動(dòng)到哪個(gè)值,通過監(jiān)聽這些值的漸變過程來自己操作控件力穗。

4.1.1 ValueAnimator構(gòu)造函數(shù)

ValueAnimator的構(gòu)造函數(shù)是空實(shí)現(xiàn)毅弧,一般使用靜態(tài)工廠方法來實(shí)現(xiàn)實(shí)例化。

public static ValueAnimator ofInt(int... values)
public static ValueAnimator ofArgb(int... values)
public static ValueAnimator ofFloat(float... values)
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)

參數(shù)類型都是可變參數(shù)長(zhǎng)參數(shù)当窗,所以我們可以傳入任何數(shù)量的值够坐;
傳進(jìn)去的值列表,就表示動(dòng)畫時(shí)的變化范圍崖面;
比如ofInt(2,90,45)就表示從數(shù)值2變化到數(shù)字90再變化到數(shù)字45元咙;

4.1.2 ValueAnimator常用方法
//設(shè)置動(dòng)畫時(shí)長(zhǎng),單位是毫秒 
ValueAnimator setDuration(long duration)  
//獲取ValueAnimator在運(yùn)動(dòng)時(shí)巫员,當(dāng)前運(yùn)動(dòng)點(diǎn)的值 
Object getAnimatedValue();  
//開始動(dòng)畫 
void start()  
//設(shè)置循環(huán)次數(shù),設(shè)置為0表示不循環(huán)庶香,設(shè)置為ValueAnimation.INFINITE表示無限循環(huán)。 
void setRepeatCount(int value)  
//設(shè)置循環(huán)模式 
//取值為ValueAnimation.RESTART時(shí),表示正序重新開始简识,當(dāng)取值為ValueAnimation.REVERSE表示倒序重新開始赶掖。 
void setRepeatMode(int value)  
//設(shè)置插值器
setInterpolator(xxxx)
//取消動(dòng)畫 
void cancel() 

// 延時(shí)多久時(shí)間開始,單位是毫秒  
public void setStartDelay(long startDelay)  
//完全克隆一個(gè)ValueAnimator實(shí)例七扰,包括它所有的設(shè)置以及所有對(duì)監(jiān)聽器代碼的處理 
public ValueAnimator clone()  
4.1.3 ValueAnimator監(jiān)聽器(2種)

監(jiān)聽器一:監(jiān)聽動(dòng)畫變化時(shí)的實(shí)時(shí)值

public static interface AnimatorUpdateListener {  
    void onAnimationUpdate(ValueAnimator animation);  
}  

//添加方法
public void addUpdateListener(AnimatorUpdateListener listener) 
//移除方法
public void removeUpdateListener(AnimatorUpdateListener listener);  
public void removeAllUpdateListeners();   

//===代碼實(shí)現(xiàn)===
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            int curValue = (int)animation.getAnimatedValue();  
            tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
        }  
    }); 

監(jiān)聽器二:監(jiān)聽動(dòng)畫變化時(shí)四個(gè)狀態(tài)

public static interface AnimatorListener {  
    void onAnimationStart(Animator animation);  
    void onAnimationEnd(Animator animation);  
    void onAnimationCancel(Animator animation);  
    void onAnimationRepeat(Animator animation);  
}  
//添加方法
public void addListener(AnimatorListener listener)   
//移除方法
void removeListener(AnimatorListener listener);  
void removeAllListeners();  

//===代碼實(shí)現(xiàn)===
animator.addListener(new Animator.AnimatorListener() {  
        @Override  
        public void onAnimationStart(Animator animation) {  
            Log.d("xl","animation start");  
        }  
  
        @Override  
        public void onAnimationEnd(Animator animation) {  
            Log.d("xl","animation end");  
        }  
  
        @Override  
        public void onAnimationCancel(Animator animation) {  
            Log.d("xl","animation cancel");  
        }  
  
        @Override  
        public void onAnimationRepeat(Animator animation) {  
            Log.d("xl","animation repeat");  
        }  
    });
4.1.4 ValueAnimator代碼實(shí)現(xiàn)(5種)
1?? ofInt(只能傳入Integer類型的值)
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 400);
valueAnimatorInt.setDuration(1000);

valueAnimatorInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int curValue = (int) animation.getAnimatedValue();
                        tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
                    }
                });

valueAnimatorInt.start();
2?? ofFloat(只能傳入Float類型的值)
ValueAnimator valueAnimatorFloat = ValueAnimator.ofFloat(0f, 400f, 50f, 300f);
valueAnimatorFloat.setDuration(3000);

valueAnimatorFloat.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float animatedValue = (float) animation.getAnimatedValue();
                        int curValue = (int) animatedValue;
                        tvAnimPropertyValue.layout(curValue,curValue,curValue+tvAnimPropertyValue.getWidth(),curValue+tvAnimPropertyValue.getHeight());
                    }
                });

valueAnimatorFloat.start();
3?? ofArgb
4?? ofObject(可以傳進(jìn)去任何類型的變量)

構(gòu)造方法解釋

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values);  
/*兩個(gè)參數(shù)奢赂,第一個(gè)是自定義的Evaluator,第二個(gè)是可變長(zhǎng)參數(shù)戳寸,Object類型的呈驶;
為什么要強(qiáng)制傳進(jìn)去自定義的Evaluator拷泽?
Evaluator的作用是根據(jù)當(dāng)前動(dòng)畫的顯示進(jìn)度疫鹊,計(jì)算出當(dāng)前進(jìn)度下把對(duì)應(yīng)的值袖瞻。
既然Object對(duì)象是我們自定的,那必然從進(jìn)度到值的轉(zhuǎn)換過程也必須由我們來做拆吆,不然系統(tǒng)不知道要轉(zhuǎn)成什么鬼聋迎。*/

實(shí)例

ValueAnimator valueAnimatorObject = ValueAnimator.ofObject(new CharEvaluator(), new Character('A'), new Character('Z'));
valueAnimatorObject.setDuration(10000);
valueAnimatorObject.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        char animatedValue = (char) animation.getAnimatedValue();
                        tvAnimPropertyValue.setText(String.valueOf(animatedValue));
                    }
                });
valueAnimatorObject.start();
public class CharEvaluator implements TypeEvaluator<Character> {
    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
        int startInt = (int)startValue;
        int endInt = (int)endValue;
        int curInt = (int)(startInt + fraction *(endInt - startInt));
        char result = (char) curInt;
        return result;
    }
}
5?? ofPropertyValuesHolder

參考ObjectAnimator的ofPropertyValuesHolder的實(shí)現(xiàn)

4.1.5 首先理解interpolator和Evaluator的功能和關(guān)系

如果看完還是不懂就戳這

ValueAnimator anim = ValueAnimator.ofInt(100, 400);    
anim.setDuration(1000);    
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    
    @Override    
    public void onAnimationUpdate(ValueAnimator animation) {    
        float currentValue = (float) animation.getAnimatedValue();    
        Log.d("TAG", "cuurent value is " + currentValue);    
    }    
});    
anim.start(); 

在添加了AnimatorUpdateListener的監(jiān)聽以后,通過在監(jiān)聽函數(shù)中調(diào)用 animation.getAnimatedValue()就可以得到當(dāng)前的值枣耀;
那當(dāng)前的值是怎么來的呢霉晕?
當(dāng)前的值 = 100 + (400 - 100)* 顯示進(jìn)度

  • 100和400就是我們?cè)O(shè)置的ofInt(100,400)中的值
  • 顯示進(jìn)度是通過interpolator得到 [interpolator將時(shí)間變化(0-1)轉(zhuǎn)化成顯示進(jìn)度(0-1,但也可以大于1小于0)]
  • 而整個(gè)公式當(dāng)前的值 = 100 + (400 - 100)* 顯示進(jìn)度是在Evaluator中計(jì)算的。

關(guān)系圖如下


關(guān)系圖
4.1.6 interpolator插值器

插值器用來將時(shí)間進(jìn)度轉(zhuǎn)換成顯示進(jìn)度

1.系統(tǒng)自帶插值器
interpolator的系統(tǒng)值

意義如下:

AccelerateDecelerateInterpolator 在動(dòng)畫開始與介紹的地方速率改變比較慢捞奕,在中間的時(shí)候加速
AccelerateInterpolator 在動(dòng)畫開始的地方速率改變比較慢牺堰,然后開始加速
AnticipateInterpolator 開始的時(shí)候向后然后向前甩
AnticipateOvershootInterpolator 開始的時(shí)候向后然后向前甩一定值后返回最后的值
BounceInterpolator 動(dòng)畫結(jié)束的時(shí)候彈起
CycleInterpolator 動(dòng)畫循環(huán)播放特定的次數(shù),速率改變沿著正弦曲線
DecelerateInterpolator 在動(dòng)畫開始的地方快然后慢
LinearInterpolator 以常量速率改變
OvershootInterpolator 向前甩一定值后再回到原來位置

使用

ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new BounceInterpolator());
....
2.自定義插值器

先看看系統(tǒng)加速器LinearInterpolator的寫法:

//以常量速率改變的加速器LinearInterpolator
public class LinearInterpolator implements Interpolator {  
  
    public LinearInterpolator() {  
    }  
  
    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  
  
    public float getInterpolation(float input) {  
        return input;  
    }  
}  

//接口Interpolator(LinearInterpolator實(shí)現(xiàn)了Interpolator接口)
public interface Interpolator extends TimeInterpolator {  
}  

//(Interpolator接口則直接繼承自TimeInterpolator)
public interface TimeInterpolator {  
    float getInterpolation(float input);  
/*
  參數(shù)input:
  input參數(shù)是一個(gè)float類型颅围,它取值范圍是0到1伟葫,表示當(dāng)前動(dòng)畫的時(shí)間進(jìn)度(與我們的任何設(shè)置無關(guān)).
  取0時(shí)表示動(dòng)畫剛開始,取1時(shí)表示動(dòng)畫結(jié)束院促,取0.5時(shí)表示動(dòng)畫中間的位置筏养,其它類推。
 
  返回值:
  表示當(dāng)前實(shí)際想要顯示的進(jìn)度常拓。取值可以超過1也可以小于0渐溶。
  超過1表示已經(jīng)超過目標(biāo)值,小于0表示小于開始位置弄抬。
 */
}  

從上面可以看到茎辐,LinearInterpolator在getInterpolation函數(shù)中,直接把input值返回掂恕,即以當(dāng)前動(dòng)畫的進(jìn)度做為動(dòng)畫的數(shù)值進(jìn)度荔茬,這也就表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度與動(dòng)畫的時(shí)間進(jìn)度一致,比如竹海,如果當(dāng)前動(dòng)畫進(jìn)度為0慕蔚,那動(dòng)畫的數(shù)值進(jìn)度也是0,那如果動(dòng)畫進(jìn)度為0.5斋配,那動(dòng)畫的數(shù)值進(jìn)度也是在0.5孔飒,當(dāng)動(dòng)畫結(jié)束,動(dòng)畫的進(jìn)度就變成1了艰争,而動(dòng)畫的數(shù)值進(jìn)度也是1了坏瞄。

則自定義Interpolator

public class MyInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        return 1-input;
    }
}

使用

ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setInterpolator(new MyInterpolator());
...
4.1.7 Evaluator

Evaluator是根據(jù)加速器返回的小數(shù)進(jìn)度轉(zhuǎn)換成當(dāng)前數(shù)值進(jìn)度所對(duì)應(yīng)的值。

1.系統(tǒng)自帶Evaluator

Evaluator是專用的甩卓。
Evalutor一般來講不能通用鸠匀,會(huì)報(bào)強(qiáng)轉(zhuǎn)錯(cuò)誤,也就是說逾柿,只有在數(shù)值類型相同的情況下缀棍,Evalutor才能共用宅此。

ofInt()對(duì)應(yīng)的Evaluator類名叫IntEvaluator
ofFloat()對(duì)應(yīng)的Evaluator類名叫FloatEvaluator
ofInt和ofFloat都是系統(tǒng)直接提供的函數(shù),所以在使用時(shí)都會(huì)有默認(rèn)的加速器和Evaluator來使用的爬范,不指定則使用默認(rèn)的父腕;

ArgbEvalutor是用來做顏色值過渡轉(zhuǎn)換的∏嗥伲可配合使用ofInt()

ValueAnimator valueAnimatorIntArgb = ValueAnimator.ofInt(0xffffff00, 0xff0000ff);
valueAnimatorIntArgb.setDuration(3000);
valueAnimatorIntArgb.setEvaluator(new ArgbEvaluator());
valueAnimatorIntArgb.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        int curValue = (int)animation.getAnimatedValue();
                        tvAnimPropertyValue.setBackgroundColor(curValue);

                    }
                });
valueAnimatorIntArgb.start();
2.自定義Evaluator

看看IntEvaluator內(nèi)部是怎么實(shí)現(xiàn):

public class IntEvaluator implements TypeEvaluator<Integer> {  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
          /*
         其中fraction就是加速器中的返回值璧亮,表示當(dāng)前動(dòng)畫的數(shù)值顯示進(jìn)度,百分制的小數(shù)表示斥难。 
         startValue和endValue分別對(duì)應(yīng)ofInt(int start,int end)中的start和end的數(shù)值枝嘶;
         */
        int startInt = startValue;  
        return (int)(startInt + fraction * (endValue - startInt));  
        //也就是 當(dāng)前的值 = 100 + (400 - 100)* 顯示進(jìn)度  
    }  
}  

自定義Evaluator

public class MyEvaluator implements TypeEvaluator<Integer> {
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int) (200 + startInt + fraction * (endValue - startInt));
    }
}
3.使用
ValueAnimator valueAnimatorInt = ValueAnimator.ofInt(0, 800);
valueAnimatorInt.setEvaluator(new IntEvaluator());
...
4.1.8 ValueAnimator XML實(shí)現(xiàn)

標(biāo)簽<animator />對(duì)應(yīng)ValueAnimator

4.1.8.1 animator所有的字段及取值范圍
<animator
    android:duration="int"
    android:valueFrom="float | int | color"
    android:valueTo="float | int | color"
    android:startOffset="int"
    android:repeatCount="int"
    android:repeatMode=["repeat" | "reverse"]
    android:valueType=["intType" | "floatType"]
    android:interpolator=["@android:interpolator/XXX"]/>

android:valueType:表示參數(shù)值類型,取值為intType和floatType哑诊;
與android:valueFrom躬络、android:valueTo相對(duì)應(yīng)。
如果這里的取值為intType搭儒,那么android:valueFrom穷当、android:valueTo的值也就要對(duì)應(yīng)的是int類型的數(shù)值。
非常注意的是淹禾,如果android:valueFrom馁菜、android:valueTo的值設(shè)置為color類型的值,那么不需要設(shè)置這個(gè)參數(shù)铃岔;

4.1.8.2 代碼實(shí)現(xiàn)

1.在res/animator目錄下創(chuàng)建animator_value.xml

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="300"
    android:valueType="intType"
    android:duration="1000"
    android:interpolator="@android:anim/bounce_interpolator"
    />

2.加載到程序中

ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animtor_value);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
            int offset = (int) animation.getAnimatedValue();
            tvAnimPropertyValue.layout(offset,offset,offset+tvAnimPropertyValue.getWidth(),offset+tvAnimPropertyValue.getHeight());
      }
});
animator.start();

更多案例

自定義彈性圓控件(配合使用ValueAnimator的ofObject)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汪疮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毁习,更是在濱河造成了極大的恐慌智嚷,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺且,死亡現(xiàn)場(chǎng)離奇詭異盏道,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)载碌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門猜嘱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嫁艇,你說我怎么就攤上這事朗伶。” “怎么了步咪?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵论皆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)点晴,這世上最難降的妖魔是什么感凤? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮觉鼻,結(jié)果婚禮上俊扭,老公的妹妹穿的比我還像新娘队橙。我一直安慰自己坠陈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布捐康。 她就那樣靜靜地躺著仇矾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪解总。 梳的紋絲不亂的頭發(fā)上贮匕,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音花枫,去河邊找鬼刻盐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛劳翰,可吹牛的內(nèi)容都是我干的敦锌。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼佳簸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼乙墙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起生均,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤听想,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后马胧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汉买,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年佩脊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了录别。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡邻吞,死狀恐怖组题,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抱冷,我是刑警寧澤崔列,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響赵讯,放射性物質(zhì)發(fā)生泄漏盈咳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一边翼、第九天 我趴在偏房一處隱蔽的房頂上張望鱼响。 院中可真熱鬧,春花似錦组底、人聲如沸丈积。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽江滨。三九已至,卻和暖如春厌均,著一層夾襖步出監(jiān)牢的瞬間唬滑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工棺弊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晶密,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓模她,卻偏偏與公主長(zhǎng)得像稻艰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缝驳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361