作者:代培
地址:http://daipei.me/posts/imitate_button_in_pigcoming/
我的博客已經搬家了^_^,我的新博客地址:daipei.me
寫在前面
豬來了中轉盤的按鈕十分帶感,有一種3D的效果,而實際上是僞3D,且實現起來十分容易,本篇文章就記錄一下如何實現這個按鈕的效果。
正文
首先解壓豬來了的ipa包,從裏面找出它的資源文件,然後發現了很多類似於下面的圖片資源:
從這張圖中我們可以很明顯的看出這個按鈕的實現方式,底座圖片共有兩張,大的那張放在下面,小的那張蓋在button的上面,然後讓button做上下的移動,然後就能做出類似的效果,下面是張效果圖:
實現
由於本人文筆比較差,大家可以跳過我的介紹直接下載我的Demo
我這裏還是簡單說一下具體的代碼實現:
首先重寫View的兩個方法,檢測手指的按下和擡起,並用一個變量來記錄Touch的狀態
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
self.touchState = TouchStatePress;
[self playPressAnimationAndCallDelegate];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
self.touchState = TouchStateFree;
[self playFreeAnimationAndCallDelegate];
}
然後我們看一下核心的兩個方法playPressAnimationAndCallDelegate
和playFreeAnimationAndCallDelegate
,這裏只分析第一個方法。開始先判斷當前是否有動畫在進行,如果是直接返回。然後判斷當前轉盤的狀態,如果是free狀態,則播放完全按下的動畫,在動畫結束的回掉中,更新button的狀態,此時要注意的是去檢查Touch的狀態,如果如果是鬆開的狀態,那還要去調用playFreeAnimationAndCallDelegate
,在動畫block外,根據轉盤的狀態決定是否通知代理。
- (void)playPressAnimationAndCallDelegate {
if (self.animated) {
return ;
}
self.animated = YES;
CGFloat height = self.frame.size.height;
if (self.spinState == SpinStateFree) {
[UIView animateWithDuration:0.08 animations:^{
self.button.frame = CGRectMake(0, height / 16, self.button.frame.size.width, self.button.frame.size.height);
} completion:^(BOOL finished) {
self.button.frame = CGRectMake(0, height / 16, self.button.frame.size.width, self.button.frame.size.height);
self.animated = NO;
self.buttonState = ButtonStateLow;
if (self.touchState == TouchStateFree) {
[self playFreeAnimationAndCallDelegate];
}
}];
}else if (self.spinState == SpinStateBusy) {
[UIView animateWithDuration:0.05 animations:^{
self.button.frame = CGRectMake(0, height / 60, self.button.frame.size.width, self.button.frame.size.height);
} completion:^(BOOL finished) {
self.button.frame = CGRectMake(0, height / 60, self.button.frame.size.width, self.button.frame.size.height);
self.animated = NO;
self.buttonState = ButtonStateMid;
if (self.touchState == TouchStateFree) {
[self playFreeAnimationAndCallDelegate];
}
}];
}
if (self.spinState == SpinStateFree) {
if (self.delegate && [self.delegate respondsToSelector:@selector(giftSpinButtonDidPress:)]) {
[self.delegate giftSpinButtonDidPress:self];
}
}
}
最後我們看一下唯一的一個接口的實現,首先記錄轉盤的狀態,這裏要注意如果轉盤狀態變爲free而button是被按下的,我們要再次播放動畫並通知代理(這裏應對的情況是如果能一直按着這個按鈕,當轉盤停下來時是會繼續轉的)。
- (void)spinStateChangeTo:(SpinState)state {
self.spinState = state;
if (state == SpinStateFree && self.touchState == TouchStatePress) {
if (self.buttonState == ButtonStateMid) {
[self playPressAnimationAndCallDelegate];
} else if (self.buttonState == ButtonStateLow) {
if (self.delegate && [self.delegate respondsToSelector:@selector(giftSpinButtonDidPress:)]) {
[self.delegate giftSpinButtonDidPress:self];
}
}
}
}
使用
說完實現,說一下這個View該如果使用。在VC中實例化這個View,並將其代理設爲這個VC,這裏要注意的一點是一般情況下是要在-giftSpinButtonDidPress:
的代理方法中調用spinStateChangeTo:
方法的,因爲按下後轉盤轉起來按鈕就按不下去了。
- (void)giftSpinButtonDidPress:(DPSpinButton *)giftSpinButton {
...
[giftSpinButton spinStateChangeTo:SpinStateBusy];
}
其實很簡單的代碼,但是實現的效果卻很贊!
(本文結束^_^)