仿猪来了转盘button的实现

写在前面

猪来了中转盘的按钮十分带感,有一种3D的效果,而实际上是伪3D,且实现起来十分容易,本篇文章就记录一下如何实现这个按钮的效果。

正文

首先解压猪来了的ipa包,从里面找出它的资源文件,然后发现了很多类似于下面的图片资源:

1

从这张图中我们可以很明显的看出这个按钮的实现方式,底座图片共有两张,大的那张放在下面,小的那张盖在button的上面,然后让button做上下的移动,然后就能做出类似的效果,下面是张效果图:

2

实现

由于本人文笔比较差,大家可以跳过我的介绍直接下载我的Demo
我这里还是简单说一下具体的代码实现:

首先重写View的两个方法,检测手指的按下和抬起,并用一个变量来记录Touch的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (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];
}

然后我们看一下核心的两个方法playPressAnimationAndCallDelegateplayFreeAnimationAndCallDelegate,这里只分析第一个方法。开始先判断当前是否有动画在进行,如果是直接返回。然后判断当前转盘的状态,如果是free状态,则播放完全按下的动画,在动画结束的回掉中,更新button的状态,此时要注意的是去检查Touch的状态,如果如果是松开的状态,那还要去调用playFreeAnimationAndCallDelegate,在动画block外,根据转盘的状态决定是否通知代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (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是被按下的,我们要再次播放动画并通知代理(这里应对的情况是如果能一直按着这个按钮,当转盘停下来时是会继续转的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
- (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:方法的,因为按下后转盘转起来按钮就按不下去了。

1
2
3
4
5
6
7
- (void)giftSpinButtonDidPress:(DPSpinButton *)giftSpinButton {
...
[giftSpinButton spinStateChangeTo:SpinStateBusy];
}

其实很简单的代码,但是实现的效果却很赞!

(本文结束^_^)