《Motion Design for iOS》(四十二)

來源:互聯網
上載者:User

標籤:

構建立即響應的按鈕

你玩過Loren Brichter的遊戲Letterpress嗎?我很喜歡的Loren構建的一個關於介面的東西可能不是每個人都明顯喜歡的:我喜歡每個按鈕在使用者按下時立即切換到一個不同的狀態的樣子。絕對不會延遲。這不是一個簡單實現的行為,因為即使你可以將一個圖片設為UIButtonUIControlStateHighlighted狀態圖,它也只會在點擊發生後一小會啟動,而且它不允許更進一步的代碼來運行它。如果我想要在使用者點擊一個UIButton後立即運行一個動畫,我就不得不自己寫一個簡單的自訂按鈕類。但首先,先來看一看我們要構建的是什麼。

如果我想要在使用者點擊後立即運行代碼,我就不得不自己寫一個好的UIButton子類,這樣我就可以重寫一些方法,即 -touchesBegan:withEvent: 和 -touchesEnded:withEvent:。iOS中的每個介面的控制都從UIResponder繼承了這些方法,它是一個處理所有觸摸控制事件的父類。有了子類,我就可以塞一些自己的代碼來在這些方法啟動的時候運行。來看看DTCTestButton的實現檔案,這是我們的按鈕子類,會為我們處理一些魔法。

#import "DTCTestButton.h"#import "POP.h"@implementation DTCTestButton- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    // 自訂一些按鈕第一次被點擊時要啟動並執行代碼    [super touchesBegan:touches withEvent:event];}- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {    // 自訂一些按鈕不再被點擊時要啟動並執行代碼    [super touchesEnded:touches withEvent:event];}@end

我們這裡只定義了兩個方法,我們想要將我們的代碼放到這些方法裡面去。當子類化一個蘋果提供的對象,比如UIButton時,做一個好的城市居民並確保調用super的關於這些方法的實現是很重要的,因為我們不知道蘋果在這兩個方法中需要運行什麼代碼,而且不想破壞按鈕的預設行為。我們調用super後,就可以在這兩個方法中添加任何我們想要的行為。

讓我們添加一個Pop動畫到 -touchesBegan:withEvent:中去。

POPSpringAnimation *scale = [self pop_animationForKey:@"scale"];if (scale) {    scale.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];} else {    scale = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY];    scale.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];    scale.springBounciness = 20;    scale.springSpeed = 18.0f;    [self pop_addAnimation:scale forKey:@"scale"];}

這和我們之前寫的Pop代碼有點不同。當使用Pop來構建好的響應動畫去關聯觸摸動作時,一個聰明的做法是看看是否已經有一個Pop動畫關聯到這個視圖或者layer了。如果有,只要更新已經存在的動畫的toValue屬性就可以了。Pop知道當前的值是什麼並且已經設定好彈性和速度變數了,所以你不用做任何其他的事情。這避免了添加另一個錯誤的Pop動畫來操作同樣的值(在這個例子中,是kPOPViewScaleXY),這會造成愚蠢的結果。通過使用現存的動畫,Pop可以優雅地從它的當前位置修改到你設定的新的toValue並進行一個漂亮、平滑的過度。這也是為什麼Pop動畫有一個名字:這樣你就可以通過給出你之前設定的動畫的名字來詢問視圖或者layer它們是否有已經添加進去的Pop動畫並擷取到動畫對象。

如果動畫不是已經存在,我們就和平常一樣建立一個新的Pop動畫對象,設定彈簧的動作屬性,比如彈性,設定toValue,然後添加動畫到視圖或者layer上。在這個例子中,我們動畫了視圖的尺寸,所以我們將動畫添加到視圖上。

現在讓我們在觸摸事件結束時做同樣的事情。這次代碼放在 -touchesEnded:withEvent:中。

POPSpringAnimation *scale = [self pop_animationForKey:@"scale"];if (scale) {    scale.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];} else {    scale = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY];    scale.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];    scale.springBounciness = 20;    scale.springSpeed = 18.0f;    [self pop_addAnimation:scale forKey:@"scale"];}

如果你看看觸摸事件開始時0.8的toValue以及觸摸結束時的1.0的toValue,你就可以猜到整個動畫會在使用者點擊按鈕時稍微收縮按鈕的尺寸,然後會在他們停止觸摸時彈回完整的尺寸。完全正確!這裡是它現在的樣子。

很有意思!讓我們再加一點點旋轉動畫來增色。它基本上和我們已經添加的代碼一樣,只是重複它,修改動畫類型,然後改變toValue值。這裡是完整的代碼,以及一些注釋。

// 當使用者開始點擊時立即調用- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {        // 看動畫是否已經被添加到視圖或者layer上    POPSpringAnimation *scale = [self pop_animationForKey:@"scale"];    POPSpringAnimation *rotate = [self.layer pop_animationForKey:@"rotate"];    // 如果scale動畫已經存在,就設定toValue    if (scale) {        scale.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];    } else {        // 如果不存在,就建立並添加它        scale = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY];        scale.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];        scale.springBounciness = 20;        scale.springSpeed = 18.0f;        [self pop_addAnimation:scale forKey:@"scale"];    }    // 如果旋轉動畫已經存在,就設定toValue    if (rotate) {        rotate.toValue = @(M_PI/6); // 旋轉到1/6th π角度    } else {        // 旋轉動畫時layer上的,所以我們添加到layer上去        rotate = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation];        rotate.toValue = @(M_PI/6);        rotate.springBounciness = 20;        rotate.springSpeed = 18.0f;        // 添加到layer上,而不是view        [self.layer pop_addAnimation:rotate forKey:@"rotate"];    }    [super touchesBegan:touches withEvent:event];}// 在使用者離開手指時立即調用- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {    // 看動畫是否存在(由於這是使用者離開時,基本是已經存在的)    POPSpringAnimation *scale = [self pop_animationForKey:@"scale"];    POPSpringAnimation *rotate = [self pop_animationForKey:@"rotate"];    if (scale) {        // 展開回1.0的完整尺寸        scale.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];    } else {        scale = [POPSpringAnimation animationWithPropertyNamed:kPOPViewScaleXY];        scale.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];        scale.springBounciness = 20;        scale.springSpeed = 18.0f;        [self pop_addAnimation:scale forKey:@"scale"];    }    if (rotate) {        // 旋轉回0角度的初始位置        rotate.toValue = @(0);    } else {        rotate = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation];        rotate.toValue = @(0);        rotate.springBounciness = 20;        rotate.springSpeed = 18.0f;        // 再次確保添加你的layer動畫到layer上去。我曾經失誤過很多次,這會導致一個有趣的bug :)        [self.layer pop_addAnimation:rotate forKey:@"rotate"];    }    [super touchesEnded:touches withEvent:event];}

動畫代碼是重複的。簡單,但是重複。它的一個缺點是需要很多行代碼來完整構建你的動畫,但優點是能讓你練習寫很多動畫代碼,所以我認為你可以學的更快。

再一次,這裡是我們構建的最終動畫。它是一個很有趣的效果,會在使用者點擊按鈕時立即啟動,它會讓你的介面感覺響應很快。這裡的彈性效果很顯著,所以當添加動畫到你的真實app介面時,去使用一會app的動畫,並確保它們的速度和動作時合適且不分散注意力的。

現在讓我們來用Pop做一些有趣的東西!

查看完整合集:https://github.com/Cloudox/Motion-Design-for-iOS
著作權:http://blog.csdn.net/cloudox_

《Motion Design for iOS》(四十二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.