多按钮-移动小控件

公司的4.0.5要准备开发了,初步看看交互稿,然后发现一个有趣的控件,至于这个控件怎么命名,我也不知道。类似自适应的那种。

这里就简单描述一下:

  1. 筛选item默认显示在第一个item下。
  2. 点击对应的item,筛选item就在哪个下面

由于已经做出了效果,就先睹为快:

image

首先想到的是创建5个item。然后调整位置。OK,看代码:

1
2
3
4
5
6
7
8
9
@interface AdaptItemView()
{
UIButton *_mineItem;
UIButton *_teamItem;
UIButton *_friendItem;
UIButton *_nearItem;
UIButton *_changeItem;
}
@end
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@implementation AdaptItemView

- (instancetype)init{
self = [super init];
if (self) {
self.backgroundColor = [UIColor redColor];
[self proccessView];
}
return self;
}

- (void)proccessView{
_mineItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"我的" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn.tag = 0;
[btn addTarget:self action:@selector(clickItemBtn:) forControlEvents:UIControlEventTouchUpInside];
btn;
});
[self addSubview:_mineItem];

_teamItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"团队" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn.tag = 1;
[btn addTarget:self action:@selector(clickItemBtn:) forControlEvents:UIControlEventTouchUpInside];
btn;
});
[self addSubview:_teamItem];

_friendItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"好友" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn.tag = 2;
[btn addTarget:self action:@selector(clickItemBtn:) forControlEvents:UIControlEventTouchUpInside];
btn;
});
[self addSubview:_friendItem];

_nearItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"附近" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn.tag = 3;
[btn addTarget:self action:@selector(clickItemBtn:) forControlEvents:UIControlEventTouchUpInside];
btn;
});
[self addSubview:_nearItem];

_changeItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"筛选" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn;
});
[self addSubview:_changeItem];
}


- (void)layoutSubviews{
[super layoutSubviews];

[_mineItem setFrame:0 y:0 w:40 h:40];
[_changeItem setFrame:0 y:_mineItem.botm w:40 h:40];
[_teamItem setFrame:0 y:_changeItem.botm+10 w:40 h:40];
[_friendItem setFrame:0 y:_teamItem.botm+10 w:40 h:40];
[_nearItem setFrame:0 y:_friendItem.botm+10 w:40 h:40];
}

- (void)clickItemBtn:(UIButton *)btn{
switch (btn.tag) {
case 0:
{
[UIView animateWithDuration:0.25 animations:^{
_changeItem.y = btn.botm;
_teamItem.y = _changeItem.botm+10;
_friendItem.y = _teamItem.botm+10;
_nearItem.y = _friendItem.botm+10;
}];
}
break;
case 1:
{
[UIView animateWithDuration:0.25 animations:^{
_teamItem.y = _mineItem.botm+10;
_changeItem.y = btn.botm;
_friendItem.y = _changeItem.botm+10;
_nearItem.y = _friendItem.botm+10;
}];
}
break;
case 2:
{
[UIView animateWithDuration:0.25 animations:^{
_teamItem.y = _mineItem.botm+10;
_friendItem.y = _teamItem.botm+10;
_changeItem.y = btn.botm;
_nearItem.y = _changeItem.botm+10;
}];
}
break;
case 3:
{
[UIView animateWithDuration:0.25 animations:^{
_teamItem.y = _mineItem.botm+10;
_friendItem.y = _teamItem.botm+10;
_nearItem.y = _friendItem.botm+10;
_changeItem.y = btn.botm;
}];
}
break;

default:
break;
}

}

OK,基本实现。只是调整y坐标就可以了。没什么难度,代码看起来恶心而已。我就想着,如果再多一个item,那我就写多一坨代码。加两三个就更多代码了。我就想着无论添加多少个,效果还是那样,而且我不用写额外的代码。

来吧:

初步想法是:

image

也是调整y的坐标,重新调整位置。算法就在于如何调整。上面的图片已经描述。

下面看代码:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@interface AdaptItemView()
{
UIButton *_changeItem;

NSMutableArray *_itemArrs;
}
@end

@implementation AdaptItemView

- (instancetype)init{
self = [super init];
if (self) {
self.backgroundColor = [UIColor redColor];
[self proccessView];
}
return self;
}

- (void)proccessView{
_itemArrs = [NSMutableArray array];
NSArray *titles = @[@"我的", @"团队", @"好友", @"附近", @"其他"];

for (int i = 0; i < titles.count; i++) {
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:titles[i] forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn.tag = i;
[btn addTarget:self action:@selector(clickItemsBtn:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:btn];
[_itemArrs addObject:btn];
}

_changeItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setTitle:@"筛选" forState:UIControlStateNormal];
[btn setTitleColor:TGSystemColorBlackTitle forState:UIControlStateNormal];
btn.backgroundColor = TGSystemColorGray_BG;
btn;
});
[self addSubview:_changeItem];
}


- (void)layoutSubviews{
[super layoutSubviews];

for (int i = 0; i < _itemArrs.count; i++) {
UIButton *btn = _itemArrs[i];
CGFloat y = i * (40 + 10);
if (i > 0) {
y += 40;
}
[btn setFrame:0 y:y w:40 h:40];
}
[_changeItem setFrame:0 y:40 w:40 h:40];

}

- (void)clickItemsBtn:(UIButton *)btn{
NSInteger tag = btn.tag;
CGFloat margin = 10;
CGFloat itemHeight = 40;
// 获取前部分的item
NSRange fontrange = NSMakeRange(0, tag+1);
NSArray *fontItems = [_itemArrs subarrayWithRange:fontrange];
CGFloat fy = 0;
for (UIButton *btn in fontItems) {
[UIView animateWithDuration:0.25 animations:^{
btn.y = fy;
}];
fy += (itemHeight + margin);
}

[UIView animateWithDuration:0.25 animations:^{
_changeItem.y = fy - margin;
}];


// 获取后部分的item
NSRange backrange = NSMakeRange(tag+1, (_itemArrs.count - (tag + 1)));
NSArray *backItems = [_itemArrs subarrayWithRange:backrange];
CGFloat by = _changeItem.botm + 10;
for (UIButton *btn in backItems) {
[UIView animateWithDuration:0.25 animations:^{
btn.y = by;
}];
by += (itemHeight + margin);
}

}

看一下效果:

image

这样我就可以实现多个item,而且不用继续重复代码了。当然还可以封装一层,把item的title或者image放到外部。具体可根据实际情况调整。

我就以图片为例,重构成最终的控件。

AdaptItemView.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface AdaptItemView : UIView

- (instancetype)initWithItemImages:(NSArray<NSString *> *)itemImages
itemSelectImages:(NSArray<NSString *> *)itemSelectImages
moveItemImage:(NSString *)moveitemImage
moveItemSelectImage:(NSString *)moveItemSelectImage;

@property (nonatomic, strong, readonly) NSMutableArray *itemViews;
@property (nonatomic, strong, readonly) NSArray *itemImages;
@property (nonatomic, strong, readonly) NSArray *itemSelectImages;

/// margin = 10.0
@property (nonatomic, assign) CGFloat margin;
@property (nonatomic, assign) CGSize viewSize;

@end

AdaptItemView.m

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
@interface AdaptItemView ()
{
UIButton *_moveItem;
}
@end

@implementation AdaptItemView



- (instancetype)initWithItemImages:(NSArray<NSString *> *)itemImages
itemSelectImages:(NSArray<NSString *> *)itemSelectImages
moveItemImage:(NSString *)moveitemImage
moveItemSelectImage:(NSString *)moveItemSelectImage{
self = [super init];
if (self) {
self.backgroundColor = UIColorFromRGB16AndAlpha(0x000000, 0.6);

_itemImages = itemImages;
_itemSelectImages = itemSelectImages;
_itemViews = [NSMutableArray array];
_margin = 10.0;

for (int i = 0; i < itemImages.count; i++) {
UIImage *image = [UIImage getImageWithName:itemImages[i]];
UIImage *selectImage = [UIImage getImageWithName:itemSelectImages[i]];
UIButton *btn = [[UIButton alloc] init];
[btn setImage:image forState:UIControlStateNormal];
[btn setImage:selectImage forState:UIControlStateSelected];
btn.tag = i;
[btn addTarget:self action:@selector(clickItemsBtn:) forControlEvents:UIControlEventTouchUpInside];
if (i == 0) {
btn.selected = YES;
}
[self addSubview:btn];
[_itemViews addObject:btn];
}

_moveItem = ({
UIButton *btn = [[UIButton alloc] init];
[btn setImage:[UIImage getImageWithName:moveitemImage] forState:UIControlStateNormal];
[btn setImage:[UIImage getImageWithName:moveItemSelectImage] forState:UIControlStateSelected];
[btn addTarget:self action:@selector(clickMoveItemBtn) forControlEvents:UIControlEventTouchUpInside];
btn;
});
[self addSubview:_moveItem];
}
return self;
}

- (void)layoutSubviews{
[super layoutSubviews];

CGSize moveSize = _moveItem.currentImage.size;
CGFloat firstItemBottom = 0;
for (int i = 0; i < _itemViews.count; i++) {
UIButton *btn = _itemViews[i];
CGSize btnSize = btn.currentImage.size;
CGFloat y = i * (btnSize.height + _margin);
if (i == 0) {
firstItemBottom = btnSize.height;
} else {
y += moveSize.height;
}
[btn setFrame:0 y:y w:btnSize.width h:btnSize.height];
}
[_moveItem setFrame:0 y:firstItemBottom w:moveSize.width h:moveSize.height];
}


- (void)clickItemsBtn:(UIButton *)btn{
// 取消之前选中的
for (UIButton *item in _itemViews) {
item.selected = NO;
}
btn.selected = YES;

NSInteger tag = btn.tag;
// 前面部分
NSRange fontrange = NSMakeRange(0, tag + 1);
NSArray *fontItems = [_itemViews subarrayWithRange:fontrange];

// 后面部分
NSRange backrange = NSMakeRange(tag + 1, (_itemViews.count - (tag + 1)));
NSArray *backItems = [_itemViews subarrayWithRange:backrange];

// 添加动画,这里使用首尾动画,更简洁一些
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
CGFloat fy = 0;
for (UIButton *item in fontItems) {
item.y = fy;
CGSize itemSize = item.currentImage.size;
fy += (itemSize.height + _margin);
}

// 中间部分
_moveItem.y = fy - _margin;

CGFloat by = _moveItem.botm + _margin;
for (UIButton *item in backItems) {
item.y = by;
CGSize itemSize = item.currentImage.size;
by += (itemSize.height + _margin);
}

[UIView commitAnimations];
}

- (CGSize)viewSize{
CGFloat width = 0;
CGFloat height = 0;
for (UIButton *btn in _itemViews) {
CGSize itemSize = btn.currentImage.size;
if (width < itemSize.width) {
width = itemSize.width;
}
height += (itemSize.height + _margin);
}
height += _moveItem.currentImage.size.height;

return CGSizeMake(width, height);
}

好了,基本重构完成,效果如下:

image

当然也可以设置title,这里就不重构了。希望看完文章对你有帮助。