iOS之AlertController的使用

iOS 8的新特性之一就是讓接口更有適應(yīng)性、更靈活,因此許多視圖控制器的實現(xiàn)方式發(fā)生了巨大的變化。全新的UIPresentationController 在實現(xiàn)視圖控制器間的過渡動畫效果和自適應(yīng)設(shè)備尺寸變化效果(比如說旋轉(zhuǎn))中發(fā)揮了重要的作用,它有效地節(jié)省了程序員們的工作量(天地良心啊)。還有,某 些舊的UIKit控件也同樣發(fā)生了許多變化,比如說Alert Views、Action Sheets、Popovers以及Search Bar Controllers。本文將會對Alert Views和Action Sheets發(fā)生的改變進行一個大致的介紹,我們會采用Objective-C和swift兩種語言同時進行代碼說明。

UIAlertView

隨著蘋果上次iOS 5的發(fā)布,對話框視圖樣式出現(xiàn)在了我們面前,直到現(xiàn)在它都沒有發(fā)生過很大的變化。下面的代碼片段展示了如何初始化和顯示一個帶有“取消”和“好的”按鈕的對話框視圖。

Objective-C版本:

UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:@"標(biāo)題" message:@"這個是UIAlertView的默認(rèn)樣式" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"好的", nil];
[alertview show];
UIAlertView的默認(rèn)樣式

swift版本和Objective-C版本不同,在swift中,alertView的初始化只允許創(chuàng)建擁有一個取消按鈕的對話框視圖。或許您可以看到帶有otherButtonTitles的init方法,但是很遺憾,這個方法是沒有辦法通過編譯的。

var alertView = UIAlertView(title: "標(biāo)題", message: "這個是UIAlertView的默認(rèn)樣式", delegate: self, cancelButtonTitle: "取消")
alertView.show()
swift版本的UIAlertView

要能夠創(chuàng)建和上面Objective-C版本相同的對話框視圖,我們可以采取曲線救國的方法,雖然麻煩了些,但是我們?yōu)榱四康目梢圆粨袷侄蔚模前桑?/p>

var alertView = UIAlertView()
alertView.delegate = self
alertView.title = "標(biāo)題"
alertView.message = "這個是UIAlertView的默認(rèn)樣式"
alertView.addButtonWithTitle("取消")
alertView.addButtonWithTitle("好的")
alertView.show()

您也可以通過更改UIAlertView的alertViewStyle屬性來實現(xiàn)輸入文字、密碼甚至登錄框的效果。

UIAlertView文本對話框
UIAlertView密碼對話框
UIAlertView登錄對話框

UIAlertViewDelegate協(xié)議擁有響應(yīng)對話框視圖的按鈕動作的回調(diào)方法。還有當(dāng)文本框內(nèi)容改變時,調(diào)用alertViewShouldEnableOtherButton:方法可以讓按鈕動態(tài)地可用或者不可用。

要說明一點,蘋果官方現(xiàn)在并不提倡在iOS 8中使用UIAlertView,取而代之的是UIAlertController。下面我們就來介紹UIAlertController的使用方法。

                                       UIAlertController

在iOS 8中,UIAlertController在功能上是和UIAlertView以及UIActionSheet相同 的,UIAlertController以一種模塊化替換的方式來代替這兩貨的功能和作用。是使用對話框(alert)還是使用上拉菜單(action sheet),就取決于在創(chuàng)建控制器時,您是如何設(shè)置首選樣式的。

一個簡單的對話框例子

您可以比較一下兩種不同的創(chuàng)建對話框的代碼,創(chuàng)建基礎(chǔ)UIAlertController的代碼和創(chuàng)建UIAlertView的代碼非常相似:

Objective-C版本:

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"標(biāo)題" message:@"這個是UIAlertController的默認(rèn)樣式" preferredStyle:UIAlertControllerStyleAlert];

swift版本:

var alertController = UIAlertController(title: "標(biāo)題", message: "這個是UIAlertController的默認(rèn)樣式", preferredStyle: UIAlertControllerStyle.Alert)

同創(chuàng)建UIAlertView相比,我們無需指定代理,也無需在初始化過程中指定按鈕。不過要特別注意第三個參數(shù),要確定您選擇的是對話框樣式還是上拉菜單樣式。

通 過創(chuàng)建UIAlertAction的實例,您可以將動作按鈕添加到控制器上。UIAlertAction由標(biāo)題字符串、樣式以及當(dāng)用戶選中該動作時運行的 代碼塊組成。通過UIAlertActionStyle,您可以選擇如下三種動作樣式:常規(guī)(default)、取消(cancel)以及警示 (destruective)。為了實現(xiàn)原來我們在創(chuàng)建UIAlertView時創(chuàng)建的按鈕效果,我們只需創(chuàng)建這兩個動作按鈕并將它們添加到控制器上即 可。

Objective-C版本:

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];

swift版本:

var cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.Cancel, handler: nil)
var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(okAction)

最后,我們只需顯示這個對話框視圖控制器即可:

Objective-C版本:

[self presentViewController:alertController animated:YES completion:nil];

swift版本:

self.presentViewController(alertController, animated: true, completion: nil)
UIAlertController默認(rèn)樣式

按鈕顯示的次序取決于它們添加到對話框控制器上的次序。一般來說,根據(jù)蘋果官方制定的《iOS 用戶界面指南》,在擁有兩個按鈕的對話框中,您應(yīng)當(dāng)將取消按鈕放在左邊。要注意,取消按鈕是唯一的,如果您添加了第二個取消按鈕,那么你就會得到如下的一個運行時異常:

  • Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘UIAlertController can only have one action with a style of UIAlertActionStyleCancel’

異常信息簡潔明了,我們在此就不贅述了。

“警示”樣式

什么是“警示”樣式呢?我們先不著急回答這個問題,先來看一下下面關(guān)于“警示”樣式的簡單示例。在這個示例中,我們將前面的示例中的“好的”按鈕替換為了“重置”按鈕。

Objective-C版本:

UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"重置" style:UIAlertActionStyleDestructive handler:nil];
[alertController addAction:resetAction];

swift版本:

var resetAction = UIAlertAction(title: "重置", style: UIAlertActionStyle.Destructive, handler: nil)
alertController.addAction(resetAction)
“警示”樣式

可以看出,我們新增的那個“重置”按鈕變成了紅色。根據(jù)蘋果官方的定義,“警示”樣式的按鈕是用在可能會改變或刪除數(shù)據(jù)的操作上。因此用了紅色的醒目標(biāo)識來警示用戶。

文本對話框

UIAlertController 極大的靈活性意味著您不必拘泥于內(nèi)置樣式。以前我們只能在默認(rèn)視圖、文本框視圖、密碼框視圖、登錄和密碼輸入框視圖中選擇,現(xiàn)在我們可以向?qū)υ捒蛑刑砑尤?意數(shù)目的UITextField對象,并且可以使用所有的UITextField特性。當(dāng)您向?qū)υ捒蚩刂破髦刑砑游谋究驎r,您需要指定一個用來配置文本框 的代碼塊。

舉個栗子吧,要重新建立原來的登錄和密碼樣式對話框,我們可以向其中添加兩個文本框,然后用合適的占位符來配置它們,最后將密碼輸入框設(shè)置使用安全文本輸入。

Objective-C版本:

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"文本對話框" message:@"登錄和密碼對話框示例" preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
    textField.placeholder = @"登錄";
}];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
    textField.placeholder = @"密碼";
    textField.secureTextEntry = YES;
}];

swift版本:

alertController.addTextFieldWithConfigurationHandler { 
(textField: UITextField!) -> Void in
    textField.placeholder = "登錄"
}
alertController.addTextFieldWithConfigurationHandler { 
(textField: UITextField!) -> Void in
    textField.placeholder = "密碼"
    textField.secureTextEntry = true
}

在“好的”按鈕按下時,我們讓程序讀取文本框中的值。

Objective-C版本:

UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    UITextField *login = alertController.textFields.firstObject;
    UITextField *password = alertController.textFields.lastObject;
    ...
}];

swift版本:

var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default) {
(action: UIAlertAction!) -> Void in
    var login = alertController.textFields?.first as UITextField
    var password = alertController.textFields?.last as UITextField
}

如 果我們想要實現(xiàn)UIAlertView中的委托方法alertViewShouldEnableOtherButton:方法的話可能會有一些復(fù)雜。假定 我們要讓“登錄”文本框中至少有3個字符才能激活“好的”按鈕。很遺憾的是,在UIAlertController中并沒有相應(yīng)的委托方法,因此我們需要 向“登錄”文本框中添加一個Observer。Observer模式定義對象間的一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時, 所有依賴于它的對象都得到通知并被自動更新。我們可以在構(gòu)造代碼塊中添加如下的代碼片段來實現(xiàn)。

Objective-C版本:

[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField){
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(alertTextFieldDidChange:) name:UITextFieldTextDidChangeNotification object:textField];
}];

swift版本:

alertController.addTextFieldWithConfigurationHandler {
(textField: UITextField!) -> Void in
    ...
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("alertTextFieldDidChange:"), name: UITextFieldTextDidChangeNotification, object: textField)
}

當(dāng)視圖控制器釋放的時候我們需要移除這個Observer,我們通過在每個按鈕動作的handler代碼塊(還有其他任何可能釋放視圖控制器的地方)中添加合適的代碼來實現(xiàn)它。比如說在okAction這個按鈕動作中:

Objective-C版本:

UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    ...
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
}];

swift版本:

var okAction = UIAlertAction(title: "好的", style: UIAlertActionStyle.Default) {
(action: UIAlertAction!) -> Void in
    ...
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
}

在顯示對話框之前,我們要凍結(jié)“好的”按鈕

Objective-C版本:

okAction.enabled = NO;

swift版本:

okAction.enabled = false

接下來,在通知觀察者(notification observer)中,我們需要在激活按鈕狀態(tài)前檢查“登錄”文本框的內(nèi)容。

Objective-C版本:

- (void)alertTextFieldDidChange:(NSNotification *)notification{
    UIAlertController *alertController = (UIAlertController *)self.presentedViewController;
    if (alertController) {
        UITextField *login = alertController.textFields.firstObject;
        UIAlertAction *okAction = alertController.actions.lastObject;
        okAction.enabled = login.text.length > 2;
    }
}

swift版本:

func alertTextFieldDidChange(notification: NSNotification){
    var alertController = self.presentedViewController as UIAlertController?
    if (alertController != nil) {
        var login = alertController!.textFields?.first as UITextField
        var okAction = alertController!.actions.last as UIAlertAction
        okAction.enabled = countElements(login.text) > 2
    }
}
UIAlertController的登錄和密碼對話框示例

好了,現(xiàn)在對話框的“好的”按鈕被凍結(jié)了,除非在“登錄”文本框中輸入3個以上的字符:

上拉菜單

當(dāng)需要給用戶展示一系列選擇的時候(選擇恐懼癥患者殺手),上拉菜單就能夠派上大用場了。和對話框不同,上拉菜單的展示形式和設(shè)備大小有關(guān)。在iPhone上(緊縮寬度),上拉菜單從屏幕底部升起。在iPad上(常規(guī)寬度),上拉菜單以彈出框的形式展現(xiàn)。

創(chuàng)建上拉菜單的方式和創(chuàng)建對話框的方式非常類似,唯一的區(qū)別是它們的形式。

Objective-C版本:

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"保存或刪除數(shù)據(jù)" message:@"刪除數(shù)據(jù)將不可恢復(fù)" preferredStyle: UIAlertControllerStyleActionSheet];

swift版本:

var alertController = UIAlertController(title: "保存或刪除數(shù)據(jù)", message: "刪除數(shù)據(jù)將不可恢復(fù)", preferredStyle: UIAlertControllerStyle.ActionSheet)

添加按鈕動作的方式和對話框相同。

Objective-C版本:

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"刪除" style:UIAlertActionStyleDestructive handler:nil];
UIAlertAction *archiveAction = [UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:deleteAction];
[alertController addAction:archiveAction];

swift版本:

var cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.Cancel, handler: nil)
var deleteAction = UIAlertAction(title: "刪除", style: UIAlertActionStyle.Destructive, handler: nil)
var archiveAction = UIAlertAction(title: "保存", style: UIAlertActionStyle.Default, handler: nil)
alertController.addAction(cancelAction)
alertController.addAction(deleteAction)
alertController.addAction(archiveAction)

您不能在上拉菜單中添加文本框,如果您強行作死添加了文本框,那么就會榮幸地得到一個運行時異常:

  • Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Text fields can only be added to an alert controller of style UIAlertControllerStyleAlert’

同樣,簡單的異常說明,我們也不多說了。

接下來我們就可以在iPhone或者其他緊縮寬度的設(shè)備上展示了,不出我們所料,運行得很成功。

Objective-C版本:

[self presentViewController:alertController animated:YES completion:nil];

swift版本:

self.presentViewController(alertController, animated: true, completion: nil);
iPhone上的上拉菜單效果

如果上拉菜單中有“取消”按鈕的話,那么它永遠(yuǎn)都會出現(xiàn)在菜單的底部,不管添加的次序是如何(就是這么任性)。其他的按鈕將會按照添加的次序從上往下依次顯示。《iOS 用戶界面指南》要求所有的“毀壞”樣式按鈕都必須排名第一(紅榜嘛,很好理解的,對不對?)。

別激動得太早,我們現(xiàn)在還有一個很嚴(yán)重的問題,這個問題隱藏得比較深。當(dāng)我們使用iPad或其他常規(guī)寬度的設(shè)備時,就會得到一個運行時異常:

Terminating app due to uncaught exception ‘NSGenericException’, reason: ‘UIPopoverPresentationController (<_uialertcontrolleractionsheetregularpresentationcontroller: 0x7fc619588110="">) should have a non-nil sourceView or barButtonItem set before the presentation occurs.’

就如我們之前所說,在常規(guī)寬度的設(shè)備上,上拉菜單是以彈出框的形式展現(xiàn)。彈出框必須要有一個能夠作為源視圖或者欄按鈕項目的描點(anchor point)。由于在本例中我們是使用了常規(guī)的UIButton來觸發(fā)上拉菜單的,因此我們就將其作為描點。

在iOS 8中我們不再需要小心翼翼地計算出彈出框的大小,UIAlertController將會根據(jù)設(shè)備大小自適應(yīng)彈出框的大小。并且在iPhone或者緊縮寬度的設(shè)備中它將會返回nil值。配置該彈出框的代碼如下:

Objective-C版本:

UIPopoverPresentationController *popover = alertController.popoverPresentationController;
if (popover){
    popover.sourceView = sender;
    popover.sourceRect = sender.bounds;
    popover.permittedArrowDirections = UIPopoverArrowDirectionAny;
}

swift版本:

var popover = alertController.popoverPresentationController
if (popover != nil){
    popover?.sourceView = sender
    popover?.sourceRect = sender.bounds
    popover?.permittedArrowDirections = UIPopoverArrowDirection.Any
}
iPad上的上拉菜單效果

UIPopoverPresentationController類同樣也是在iOS 8中新出現(xiàn)的類,用來替換UIPopoverController的。這個時候上拉菜單是以一個固定在源按鈕上的彈出框的形式顯示的。

要注意UIAlertController在使用彈出框的時候自動移除了取消按鈕。用戶通過點擊彈出框的外圍部分來實現(xiàn)取消操作,因此取消按鈕便不再必需。

釋放對話框控制器

通 常情況下,當(dāng)用戶選中一個動作后對話框控制器將會自行釋放。不過您仍然可以在需要的時候以編程方式釋放它,就像釋放其他視圖控制器一樣。您應(yīng)當(dāng)在應(yīng)用程序 轉(zhuǎn)至后臺運行時移除對話框或者上拉菜單。假定我們正在監(jiān)聽UIApplicationDidEnterBackgroundNotification通知 消息,我們可以在observer中釋放任何顯示出來的視圖控制器。(參考在viewDidLoad方法中設(shè)立observer的示例代碼)。

Objective-C版本:

- (void)didEnterBackground:(NSNotification *)notification
{
  [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
  [self.presentedViewController dismissViewControllerAnimated:NO completion:nil];
}

swift版本:

func didEnterackground(notification: NSNotification){
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
    self.presentedViewController?.dismissViewControllerAnimated(false, completion: nil)
}

注意,要保證運行安全我們同樣要確保移除所有的文本框observer。

我們來總結(jié)一下

這 篇文章比較長,但是希望能夠?qū)δ兴鶐椭T鹊腢IAlertView和UIActionSheet類仍然可以在iOS 8中工作得很好,所以沒有必要急于更換代碼(要知道本文用到的許多函數(shù)盡在iOS 8中支持)。

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

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,156評論 4 61
  • 作為一個馬上就要榮升二胎麻麻的我,準(zhǔn)備跟大家分享下孕期的各種小知識。 第一胎懷的特別輕松,雖然已27歲高齡,但是由...
    0c816ecf0927閱讀 116評論 0 0
  • 1 我愛上你,便是想和你走過余生 對于內(nèi)心排斥英語打小英語就差,又五音不全的我來說,《愛樂之城》開篇的動感音樂和熱...
    溫溫恭人_閱讀 529評論 2 6
  • 最近特別忙,心累。根本不想寫任何文字。連吐槽的氣力和欲望都殆盡。周末回到家,原以為能輕松一下,結(jié)果發(fā)生了一系列可與...
    左佳妮閱讀 239評論 2 0
  • 昨日成功的地方,耐心看完透明度與漸變色并制作了。 了解了:布置任務(wù)但是沒有檢查就是耍流氓,沒有反思復(fù)盤就沒有進步。...
    好涂鴉閱讀 151評論 0 0