IOS登錄頁面動畫、轉(zhuǎn)場動畫開發(fā)詳解

動畫效果
需求分析
分析方法
下載這個gif動圖,用mac默認的打開方式打開這個gif圖(雙擊圖片即可),效果如下

鼠標選中紅色箭頭所指的位置,然后按住鍵盤方向鍵下鍵,圖片會以緩慢的可控的速度播放,便于分析動畫的構(gòu)成。
小tips:macos系統(tǒng)想正常瀏覽一個gif動圖,可以鼠標單擊圖片后按空格,也可以選擇用瀏覽器打開,gif圖會以正常速度播放。
技術(shù)點分析
如何生成一個動畫讓控件執(zhí)行?
現(xiàn)流行的方式主要有三種:
1、基本動畫
2、核心動畫
3、三方框架——POP框架(由Facebook開發(fā))
它們的主要差別:
1、控件的位置、大小等是不是真的發(fā)生了改變?
基本動畫、pop動畫,是給控件添加動畫(一般也不會有用基本動畫給layer添加動畫的做法),所有動畫完成時,控件的屬性已經(jīng)改變,而核心動畫,是給控件的圖層(view.layer)添加動畫,看似發(fā)生了位置大小的變化,實際上控件本身的屬性并未改變。
2、它們分別的優(yōu)劣勢
2.1、基本動畫
優(yōu)勢:代碼簡單,代碼量少
劣勢:功能相對單一
2.2、核心動畫的優(yōu)勢
優(yōu)勢:功能強大、流暢性好、連續(xù)幾個動畫之間的銜接度好。流暢主要是因為操作layer是輕量級的,不容易產(chǎn)生動畫卡頓的感覺。
劣勢:代碼量大;容易寫錯(某些參數(shù)沒有定義宏,寫錯了都不知道);如有需要,還要手動在動畫完成時將控件的屬性同步修改了。
2.3、pop動畫的優(yōu)勢
優(yōu)勢:比核心動畫代碼要簡單,最大的優(yōu)勢在于,容易做彈簧效果,所以很多有“Q彈”感覺的都用pop動畫做
劣勢:要在一個動畫完成時開始另一個動畫,pop動畫不擅長,主要因為它的動畫執(zhí)行時間由"速度"和"彈性系數(shù)"兩個參數(shù)控制,不好直觀判斷動畫執(zhí)行了多久,而如果在pop動畫完成回調(diào)的block里提交下一個動畫,會不連貫(親測,原因不詳)。
轉(zhuǎn)場動畫怎么實現(xiàn)?
明明從A控制器跳往B控制器,各是各的頁面,各是各的控件,怎么做到A里的控件變化形成了B的控件的效果?
的確,A和B是兩個獨立的頁面,它們跳轉(zhuǎn)過程需要動畫的效果時,需要另外一個呈現(xiàn)于屏幕上的載體(或者稱頁面)來裝那些做動畫的控件,然后在動畫完成、轉(zhuǎn)場結(jié)束時,把這個載體移除掉,宣告轉(zhuǎn)場結(jié)束,這個時候把真正的B的頁面展示出來。
這就需要轉(zhuǎn)場代理transitioningDelegate發(fā)揮作用了,具體做法和原理下文詳述。
登錄頁分解、實現(xiàn)
點擊了GET按鈕,logo圖和logo文字上移

思路:
移動屬于比較簡單的操作,但這個移動效果具有彈簧效果,所以可以采用核心動畫中的關鍵幀動畫CAKeyframeAnimation,或者pop動畫來實現(xiàn),這里我用了pop,后面登錄失敗按鈕左右擺動的動畫,我用了CAKeyframeAnimation。
代碼:
//圖片移動動畫 POPSpringAnimation *anim4 = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame];//kPOPViewFrame表示改變的值是frame //動畫開始的值(.yy_x是我寫的分類的語法,等同于.frame.origin.x,其它同理) anim4.fromValue = [NSValue valueWithCGRect:CGRectMake(self.LoginImage.yy_x, self.LoginImage.yy_y, self.LoginImage.yy_width, self.LoginImage.yy_height)]; //動畫結(jié)束時的值 anim4.toValue = [NSValue valueWithCGRect:CGRectMake(self.LoginImage.yy_x, self.LoginImage.yy_y-75, self.LoginImage.yy_width, self.LoginImage.yy_height)]; //開始的時間 anim4.beginTime = CACurrentMediaTime()+0.2; //彈性系數(shù) anim4.springBounciness = YYSpringBounciness;//YYSpringBounciness是我定義的靜態(tài)變量,值是16.0 //速度 anim4.springSpeed = YYSpringSpeed;//YYSpringSpeed是我定義的靜態(tài)變量,值是6.0 //加到控件上執(zhí)行 [self.LoginImage pop_addAnimation:anim4 forKey:nil]; //文字移動動畫 POPSpringAnimation *anim5 = [POPSpringAnimation animationWithPropertyNamed:kPOPViewFrame]; anim5.fromValue = [NSValue valueWithCGRect:CGRectMake(self.LoginWord.yy_x, self.LoginWord.yy_y, self.LoginWord.yy_width, self.LoginWord.yy_height)]; anim5.toValue = [NSValue valueWithCGRect:CGRectMake(self.LoginWord.yy_x, self.LoginWord.yy_y-75, self.LoginWord.yy_width, self.LoginWord.yy_height)]; anim5.beginTime = CACurrentMediaTime()+0.2; anim5.springBounciness = YYSpringBounciness; anim5.springSpeed = YYSpringSpeed; [self.LoginWord pop_addAnimation:anim5 forKey:nil];
點擊get按鈕出現(xiàn)輸入框

1、get按鈕的變化
思路:
get按鈕分別進行了變寬、變寬的同時圓角變小,然后變高,然后向上移動,整個過程顏色由初始顏色變白。由于這是N個動畫,有同時執(zhí)行的,有接著上一步執(zhí)行的,所以我選擇核心動畫CABasicAnimation,更容易控制每個動畫的執(zhí)行時間、開始時間,容易銜接得流暢。
代碼:
//get背景顏色
CABasicAnimation *changeColor1 = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
changeColor1.fromValue = (__bridge id)ButtonColor.CGColor;
changeColor1.toValue = (__bridge id)[UIColor whiteColor].CGColor;
changeColor1.duration = 0.8f;
changeColor1.beginTime = CACurrentMediaTime();
//以下兩個參數(shù),是為了動畫完成后,控件的樣子不回到動畫前的樣子
//因為上文中提到過,核心動畫是給layer做動畫,控件本身的屬性不會變
changeColor1.fillMode = kCAFillModeForwards;
changeColor1.removedOnCompletion = false;
[animView.layer addAnimation:changeColor1 forKey:changeColor1.keyPath];
//get按鈕變寬
CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:@"bounds.size.width"];
anim1.fromValue = @(CGRectGetWidth(animView.bounds));
anim1.toValue = @(YYScreenW*0.8);
anim1.duration = 0.1;
anim1.beginTime = CACurrentMediaTime();
anim1.fillMode = kCAFillModeForwards;
anim1.removedOnCompletion = false;
[animView.layer addAnimation:anim1 forKey:anim1.keyPath];
//get按鈕變高
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@"bounds.size.height"];
anim2.fromValue = @(CGRectGetHeight(animView.bounds));
anim2.toValue = @(YYScreenH*0.3);
anim2.duration = 0.1;
anim2.beginTime = CACurrentMediaTime()+0.1;
anim2.fillMode = kCAFillModeForwards;
anim2.removedOnCompletion = false;
[animView.layer addAnimation:anim2 forKey:anim2.keyPath];
//get按鈕移動動畫
//這里的移動跟logo的移動是同步的,所以用pop
POPSpringAnimation *anim3 = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
anim3.fromValue = [NSValue valueWithCGRect:CGRectMake(animView.yy_centerX, animView.yy_centerY, animView.yy_width, animView.yy_height)];
anim3.toValue = [NSValue valueWithCGRect:CGRectMake(animView.yy_centerX, animView.yy_centerY-75, animView.yy_width, animView.yy_height)];
anim3.beginTime = CACurrentMediaTime()+0.2;
anim3.springBounciness = YYSpringBounciness;
anim3.springSpeed = YYSpringSpeed;
[animView pop_addAnimation:anim3 forKey:nil];
2、輸入框出現(xiàn)、LOGIN按鈕出現(xiàn)
思路:
輸入框是透明度的改變,LOGIN按鈕是大小的改變。
代碼:
//賬號密碼輸入框出現(xiàn)
self.userTextField.alpha = 0.0;
self.passwordTextField.alpha = 0.0;
[UIView animateWithDuration:0.4 delay:0.2 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.userTextField.alpha = 1.0;
self.passwordTextField.alpha = 1.0;
} completion:^(BOOL finished) {
}];
//login按鈕出現(xiàn)動畫
self.LoginButton.yy_centerX = YYScreenW*0.5;
self.LoginButton.yy_centerY = YYScreenH*0.7+44+(YYScreenH*0.3-44)*0.5-75;
CABasicAnimation *animLoginBtn = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
animLoginBtn.fromValue = [NSValue valueWithCGSize:CGSizeMake(0, 0)];
animLoginBtn.toValue = [NSValue valueWithCGSize:CGSizeMake(YYScreenW*0.5, 44)];
animLoginBtn.duration = 0.4;
animLoginBtn.beginTime = CACurrentMediaTime()+0.2;
animLoginBtn.fillMode = kCAFillModeForwards;
animLoginBtn.removedOnCompletion = false;
animLoginBtn.delegate = self;//在代理方法(動畫完成回調(diào))里,讓按鈕真正的寬高改變,而不僅僅是它的layer,否則看得到點不到
[self.LoginButton.layer addAnimation:animLoginBtn forKey:animLoginBtn.keyPath];
/** 動畫執(zhí)行結(jié)束回調(diào) */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if ([((CABasicAnimation *)anim).keyPath isEqualToString:@"bounds.size"])
{
self.LoginButton.bounds = CGRectMake(YYScreenW*0.5, YYScreenH*0.7+44+(YYScreenH*0.3-44)*0.5-75, YYScreenW*0.5, 44);
}
}
點擊LOGIN,按鈕轉(zhuǎn)圈

思路:
點擊了LOGIN,按鈕先從寬變圓,然后給按鈕添加一條半圓的白色圓弧線,然后讓這個按鈕開始旋轉(zhuǎn)。
代碼:
//執(zhí)行登錄按鈕轉(zhuǎn)圈動畫的view
//為了不影響按鈕本身的效果,這里新建一個空間做轉(zhuǎn)圈動畫
self.LoginAnimView = [[UIView alloc] initWithFrame:self.LoginButton.frame];
self.LoginAnimView.layer.cornerRadius = 10;
self.LoginAnimView.layer.masksToBounds = YES;
self.LoginAnimView.frame = self.LoginButton.frame;
self.LoginAnimView.backgroundColor = self.LoginButton.backgroundColor;
[self.view addSubview:self.LoginAnimView];
self.LoginButton.hidden = YES;
//把view從寬的樣子變圓
CGPoint centerPoint = self.LoginAnimView.center;
CGFloat radius = MIN(self.LoginButton.frame.size.width, self.LoginButton.frame.size.height);
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.LoginAnimView.frame = CGRectMake(0, 0, radius, radius);
self.LoginAnimView.center = centerPoint;
self.LoginAnimView.layer.cornerRadius = radius/2;
self.LoginAnimView.layer.masksToBounds = YES;
}completion:^(BOOL finished) {
//給圓加一條不封閉的白色曲線
UIBezierPath* path = [[UIBezierPath alloc] init];
[path addArcWithCenter:CGPointMake(radius/2, radius/2) radius:(radius/2 - 5) startAngle:0 endAngle:M_PI_2 * 2 clockwise:YES];
self.shapeLayer = [[CAShapeLayer alloc] init];
self.shapeLayer.lineWidth = 1.5;
self.shapeLayer.strokeColor = [UIColor whiteColor].CGColor;
self.shapeLayer.fillColor = self.LoginButton.backgroundColor.CGColor;
self.shapeLayer.frame = CGRectMake(0, 0, radius, radius);
self.shapeLayer.path = path.CGPath;
[self.LoginAnimView.layer addSublayer:self.shapeLayer];
//讓圓轉(zhuǎn)圈,實現(xiàn)"加載中"的效果
CABasicAnimation* baseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
baseAnimation.duration = 0.4;
baseAnimation.fromValue = @(0);
baseAnimation.toValue = @(2 * M_PI);
baseAnimation.repeatCount = MAXFLOAT;
[self.LoginAnimView.layer addAnimation:baseAnimation forKey:nil];
}];
登錄失敗按鈕抖動

思路:
這個效果跟pop動畫移動后抖動的效果很類似,這里我選擇用關鍵幀動畫CAKeyframeAnimation做,它與CABasicAnimation略有不同,CABasicAnimation是從一個值到另一個值,CAKeyframeAnimation是值變化的數(shù)組。
代碼:
//給按鈕添加左右擺動的效果(關鍵幀動畫)
CAKeyframeAnimation *keyFrame = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGPoint point = self.LoginAnimView.layer.position;
//這個參數(shù)就是值變化的數(shù)組
keyFrame.values = @[[NSValue valueWithCGPoint:CGPointMake(point.x, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x - 10, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x + 10, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x - 10, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x + 10, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x - 10, point.y)],
[NSValue valueWithCGPoint:CGPointMake(point.x + 10, point.y)],
[NSValue valueWithCGPoint:point]];
//timingFunction意思是動畫執(zhí)行的效果(這個屬性玩HTML+CSS的童鞋應該很熟悉吧)
//kCAMediaTimingFunctionEaseInEaseOut表示淡入淡出
keyFrame.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
keyFrame.duration = 0.5f;
[self.LoginButton.layer addAnimation:keyFrame forKey:keyFrame.keyPath];
轉(zhuǎn)場動畫的原理和實現(xiàn)方法
上文說到,從A跳向B,需要一個中間載體來做動畫,那么怎么得到這個載體呢?
需要用到轉(zhuǎn)場代理transitioningDelegate。
具體做法、步驟:
1、從A控制器跳到B控制器,寫跳轉(zhuǎn)的代碼時候,賦值代理
YYFirstViewController *vc = [[YYFirstViewController alloc] init]; vc.transitioningDelegate = self;//也就是這里 [self presentViewController:vc animated:YES completion:nil];
2、A控制器遵守代理,實現(xiàn)代理方法
//遵守代理
@interface YYLoginViewController () #pragma mark UIViewControllerTransitioningDelegate(轉(zhuǎn)場動畫代理)
//這個是B回到A時執(zhí)行的方法
- (id)animationControllerForDismissedController:(UIViewController *)dismissed
{
//暫時別糾結(jié)YYLoginTranslation是什么,看下文
YYLoginTranslation *loginTranslation = [[YYLoginTranslation alloc] init];
return loginTranslation;
}
//這個是A跳到B時執(zhí)行的方法
- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
YYLoginTranslation *loginTranslation = [[YYLoginTranslation alloc] init];
return loginTranslation;
}
3、顯而易見,上述兩個方法需要返回一個遵守了
//類的.h文件
#import #import @interface YYLoginTranslation : NSObject @end
//類的.m文件
#import "YYLoginTranslation.h"
@interface YYLoginTranslation () @end
@implementation YYLoginTranslation
//代碼方法-轉(zhuǎn)場時長
- (NSTimeInterval)transitionDuration:(id)transitionContext
{
return 1.0;
}
//代理方法-轉(zhuǎn)場動畫的代碼
- (void)animateTransition:(id)transitionContext
{
//transitionContext:轉(zhuǎn)場上下文
//轉(zhuǎn)場過程中顯示的view,所有動畫控件都應該加在這上面
//這就是那個所謂的載體
UIView* containerView = [transitionContext containerView];
//在這里把要做動畫效果的控件往containerView上面加
//開始開心的做動畫
//最后,在動畫完成的時候,記得標識轉(zhuǎn)場結(jié)束
[transitionContext completeTransition:YES];
}
4、現(xiàn)在回頭看第2步,那個返回的對象,就是我們第三步創(chuàng)建的類的對象。從A跳到B開始時,會先來到第2步中的"這個是A跳到B時執(zhí)行的方法",根據(jù)你返回的對象,去對象中找代理方法,執(zhí)行里面的代碼,也就是第三步中的"代理方法-轉(zhuǎn)場動畫的代碼"這個方法,這里代碼執(zhí)行結(jié)束后,控制器跳轉(zhuǎn)也就完成了。
轉(zhuǎn)場動畫分解、實現(xiàn)


思路:
如上圖AB控制器本來的樣子是這樣,轉(zhuǎn)場動畫需要完成一下操作:
1、LOGO圖逐漸消失;
2、LOGO文字逐漸變小、上移至B中頭部文字的位置;
3、A控制器的登錄框消失、A控制器背景顏色變白;
4、轉(zhuǎn)圈控件經(jīng)過弧線運動到右下角,白色加號逐漸形成
5、B控制器背景圖上移的動畫。
下面分析下第4步和第2步的做法。
圓形的弧線位移、加號的出現(xiàn)

圓形的弧線位移、加號的出現(xiàn).gif
思路:
先用設定一條曲線,然后讓圓沿著曲線移動,最后把加號展示出來。
代碼:
//設定曲線 CGMutablePathRef path = CGPathCreateMutable(); //開始的點 CGPathMoveToPoint(path, NULL, (circularAnimView.yy_x+circularAnimView.yy_width*0.5), (circularAnimView.yy_y+circularAnimView.yy_height*0.5)); //設置結(jié)束的點和拉力點,第三個參數(shù)是拉力點 CGPathAddQuadCurveToPoint(path, NULL, YYScreenW*0.9, circularAnimView.yy_y+circularAnimView.yy_height, (originalX+circularAnimView.yy_width*0.5), (originalY+circularAnimView.yy_height*0.5)); CAKeyframeAnimation *animate = [CAKeyframeAnimation animationWithKeyPath:@"position"]; animate.delegate = self;//在動畫結(jié)束的代理方法中讓加號出現(xiàn) animate.duration = 0.4; animate.beginTime = CACurrentMediaTime()+0.15; animate.fillMode = kCAFillModeForwards; animate.repeatCount = 0; animate.path = path;//移動路徑 animate.removedOnCompletion = NO; CGPathRelease(path); [circularAnimView.layer addAnimation:animate forKey:@"circleMoveAnimation"];
生成曲線的原理:
設置開始的點、結(jié)束的點、拉力點,首先會從開始點指結(jié)束點形成一條直線,然后向拉力點彎曲,就好像,拉力點會“伸出一只手”,把線拉彎。

logo文字的縮小、移動

思路:
這是一個UILabel,它的形變就不能靠改變frame實現(xiàn)了,因為如果你縮小它的寬度,當寬度不夠裝內(nèi)容時,內(nèi)容會顯示不全,顯示不下的會用...代替。所以縮小UILabel需要靠專門的形變屬性。至于移動就好說了,只需要算準位置。
代碼:
CGFloat proportion = toVC.navWord.yy_width / fromVC.LoginWord.yy_width;
CABasicAnimation * LoginWordScale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
LoginWordScale.fromValue = [NSNumber numberWithFloat:1.0];
LoginWordScale.toValue = [NSNumber numberWithFloat:proportion];
LoginWordScale.duration = 0.4;
LoginWordScale.beginTime = CACurrentMediaTime()+0.15;
LoginWordScale.removedOnCompletion = NO;
LoginWordScale.fillMode = kCAFillModeForwards;
[fromVC.LoginWord.layer addAnimation:LoginWordScale forKey:LoginWordScale.keyPath];
CGPoint newPosition = [toVC.view convertPoint:toVC.navWord.center fromView:toVC.navView];
[UIView animateWithDuration:0.4 delay:0.15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
fromVC.LoginWord.yy_centerX = newPosition.x;
fromVC.LoginWord.yy_centerY = newPosition.y;
} completion:^(BOOL finished) {
}];
退出登錄動畫

思路:
這個效果比較簡單,但同時也比較實用。實現(xiàn)方式就是改變兩個控制器view的透明度。
代碼:
//transitionContext:轉(zhuǎn)場上下文
//轉(zhuǎn)場過程中顯示的view,所有動畫控件都應該加在這上面
UIView *containerView = [transitionContext containerView];
//轉(zhuǎn)場的來源控制器
YYLoginViewController* toVC = (YYLoginViewController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//轉(zhuǎn)場去往的控制器
YYFirstViewController* fromVC = (YYFirstViewController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
//做一個淡入淡出的效果
toVC.view.alpha = 0;
[containerView addSubview:toVC.view];
[UIView animateWithDuration:1.0 animations:^{
fromVC.view.alpha = 0;
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.6 delay:0.4 options:UIViewAnimationOptionCurveEaseInOut animations:^{
toVC.view.alpha = 1;
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
備注
POP框架的手動集成報錯的問題
pop框架推薦使用pods集成,如果要手動集成的話,比較麻煩,由于處理這個問題的時間已經(jīng)有點久了,集成的麻煩點記不全了,大概就是它框架里的所有頭文件的import方式要從<>改成"",還有它好像有個.cpp文件,要把后綴改成.mm,還有什么記不住了。
如果需要手動集成pop框架,可以下這個demo,里面有手動集成的pop框架,直接把整個文件夾拖走即可。
Demo下載地址:https://github.com/YYProgrammer/YYLoginTranslationDemo
以上就是本次小編為大家整理的全部內(nèi)容,感謝你對腳本之家的支持。
相關文章
iOS App使用SQLite之句柄的定義及數(shù)據(jù)庫的基本操作
SQLite中在定義過句柄之后就可以指向數(shù)據(jù)庫,從而利用iOS應用程序進行打開或關閉等各種操作,這里我們就來看一下iOS App使用SQLite之句柄的定義及數(shù)據(jù)庫的基本操作2016-06-06
iOS WKWebView無法處理URL Scheme和App Store鏈接的問題解決
這篇文章主要給大家介紹了關于iOS WKWebView無法處理URL Scheme和App Store鏈接的問題解決的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2018-03-03
iOS開發(fā)使用GDataXML框架解析網(wǎng)絡數(shù)據(jù)
GDataXML是Google開發(fā)的一個XML解析庫,輕便,特點使用非常簡單,支持XPath。今天把前兩天弄的IOS XML解析記錄下來,也供大家參考。2016-02-02
iOS開發(fā)中實現(xiàn)一個簡單的圖片瀏覽器的實例講解
這篇文章主要介紹了iOS開發(fā)中實現(xiàn)一個簡單的圖片瀏覽器的實例講解,代碼基礎傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-01-01
ios獲取數(shù)據(jù)之encodeURI和decodeURI的實例
下面小編就為大家?guī)硪黄猧os獲取數(shù)據(jù)之encodeURI和decodeURI的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11

