您的位置:首页 > 其它

下拉框选择效果的实现原理2

2015-08-08 09:32 471 查看
效果如下



原理:使用第三方XTSegmentControl作为上面选项卡的实现,而弹出视图则是滚动视图跟每一行里面的UIBUTTON结合打勾图标相结合的实现方式;源代码可以下载开源项目Coding.net里的任务模块;这边将分简单的贴出其主要的代码

1:首先是主页面的代码:

// 添加滑块 分三组
_one = @[@"全部讨论", @"我的讨论"];
_two = [NSMutableArray arrayWithObjects:@"全部标签", nil];
_three = @[@"最后评论排序", @"发布时间排序", @"热门排序"];
_total = @[_one, _two, _three];

//用于每一组每个的数字
_oneNumber = [NSMutableArray arrayWithObjects:@0, @0, nil];
_twoNumber = [NSMutableArray arrayWithObjects:@0, nil];
_totalIndex = [NSMutableArray arrayWithObjects:@0, @0, @0, nil];
__weak typeof(self) weakSelf = self;

//选项卡的初始化
self.mySegmentControl = [[XTSegmentControl alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, kMySegmentControl_Height)
Items:@[_one[0], _two[0], _three[0]]
withIcon:YES
selectedBlock:^(NSInteger index) {
//选中哪一组
[weakSelf openList:index];
}];
[self addSubview:self.mySegmentControl];


- (void)openList:(NSInteger)segmentIndex
{
TopicListView *lView = (TopicListView *)[self viewWithTag:9898];

//当前是否存在
if (!lView) {
// 不存在则显示
_segIndex = segmentIndex;
NSArray *lists = (NSArray *)_total[segmentIndex];
CGRect rect = CGRectMake(0, kMySegmentControl_Height, kScreen_Width, self.frame.size.height - kMySegmentControl_Height);

NSArray *nAry = nil;
if (segmentIndex == 0) {
nAry = _oneNumber;
} else if (segmentIndex == 1 && [_totalIndex[0] integerValue] == 0) {
nAry = _twoNumber;
}
__weak typeof(self) weakSelf = self;
TopicListView *listView = [[TopicListView alloc]initWithFrame:rect
titles:lists
numbers:nAry
defaultIndex:[_totalIndex[segmentIndex] integerValue]
selectedBlock:^(NSInteger index) {
[weakSelf changeIndex:index withSegmentIndex:segmentIndex];
}
hideBlock:^() {
[weakSelf.mySegmentControl selectIndex:-1];
}];
listView.tag = 9898;
[self addSubview:listView];
[listView showBtnView];
} else if (_segIndex != segmentIndex) {
// 说明前面已经显示 选中另外一个 另展示
_segIndex = segmentIndex;

NSArray *nAry = nil;

//因为第三组是没有数字的
//被选中第一个数字
if (segmentIndex == 0) {
nAry = _oneNumber;
} else if (segmentIndex == 1 && [_totalIndex[0] integerValue] == 0) {
//被选中第二个数字
nAry = _twoNumber;
}

//获得是哪一组
NSArray *lists = (NSArray *)_total[segmentIndex];
__weak typeof(self) weakSelf = self;
[lView changeWithTitles:lists
numbers:nAry
defaultIndex:[_totalIndex[segmentIndex] integerValue]
selectedBlock:^(NSInteger index) {
[weakSelf changeIndex:index withSegmentIndex:segmentIndex];
}
hideBlock:^() {
[weakSelf.mySegmentControl selectIndex:-1];
}];
} else {
// 隐藏
[lView hideBtnView];
}
}


其中openList为选中某一选项卡时,弹出相应的视图内容;

2:横向选项卡的主要内容:

- (void)initItemsWithTitleArray:(NSArray *)titleArray withIcon:(BOOL)isIcon
{
_itemFrames = @[].mutableCopy;
_items = @[].mutableCopy;
float y = 0;
float height = CGRectGetHeight(self.bounds);

NSObject *obj = [titleArray firstObject];
if ([obj isKindOfClass:[NSString class]]) {
for (int i = 0; i < titleArray.count; i++) {
float x = i > 0 ? CGRectGetMaxX([_itemFrames[i-1] CGRectValue]) : 0;
float width = kScreen_Width/titleArray.count;
CGRect rect = CGRectMake(x, y, width, height);
[_itemFrames addObject:[NSValue valueWithCGRect:rect]];
}

for (int i = 0; i < titleArray.count; i++) {
CGRect rect = [_itemFrames[i] CGRectValue];
NSString *title = titleArray[i];
XTSegmentControlItem *item = [[XTSegmentControlItem alloc] initWithFrame:rect title:title type: isIcon ?
XTSegmentControlItemTypeTitleAndIcon : XTSegmentControlItemTypeTitle];
if (!isIcon && i == 0) {
[item setSelected:YES];
}
[_items addObject:item];
[_contentView addSubview:item];
}

} else if ([obj isKindOfClass:[ProjectMember class]] || [obj isKindOfClass:[Project class]]) {
//        全部任务的frame
CGRect firstFrame = CGRectMake(5.0, 0, XTSegmentControlIconWidth, height);
[_itemFrames addObject:[NSValue valueWithCGRect:firstFrame]];

for (int i = 1; i < titleArray.count; i++) {
float x = CGRectGetMaxX([_itemFrames[i-1] CGRectValue]);
CGRect rect = CGRectMake(x, y, XTSegmentControlIconWidth, height);
[_itemFrames addObject:[NSValue valueWithCGRect:rect]];
}

for (int i = 0; i < titleArray.count; i++) {
CGRect rect = [_itemFrames[i] CGRectValue];
XTSegmentControlItem *item;
if ([obj isKindOfClass:[ProjectMember class]]) {
ProjectMember *title = titleArray[i];
item = [[XTSegmentControlItem alloc] initWithFrame:rect title:title.user.avatar type:XTSegmentControlItemTypeIconUrl];
} else if ([obj isKindOfClass:[Project class]]){
Project *title = titleArray[i];
item = [[XTSegmentControlItem alloc] initWithFrame:rect title:title.icon type:XTSegmentControlItemTypeIconUrl];
}
if (item) {
if (i == 0) {
[item setSelected:YES];
}
[_items addObject:item];
[_contentView addSubview:item];
}
}
}

[_contentView setContentSize:CGSizeMake(CGRectGetMaxX([[_itemFrames lastObject] CGRectValue]), CGRectGetHeight(self.bounds))];
self.currentIndex = 0;
[self selectIndex:0];
if (isIcon) {
//是否有右边的那条线
[self selectIndex:-1];
for (int i=1; i<_itemFrames.count; i++) {
CGRect rect = [_itemFrames[i] CGRectValue];

UIView *lineView  = [[UIView alloc] initWithFrame:CGRectMake(
CGRectGetMinX(rect),
(CGRectGetHeight(rect) - 14) * 0.5,
1,
14)];
lineView.backgroundColor = [UIColor colorWithHexString:@"0xdddddd"];
[self addSubview:lineView];
}
}
}

- (void)addRedLine
{
if (!_lineView) {
CGRect rect = [_itemFrames[0] CGRectValue];
_lineView = [[UIView alloc] initWithFrame:CGRectMake(
CGRectGetMinX(rect),
CGRectGetHeight(rect) - XTSegmentControlLineHeight,
CGRectGetWidth(rect) - 2 * XTSegmentControlHspace,
XTSegmentControlLineHeight)];
_lineView.backgroundColor = [UIColor colorWithHexString:@"0x3bbd79"];
[_contentView addSubview:_lineView];

UIView *bottomLineView = [[UIView alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(rect)-0.5, CGRectGetWidth(self.bounds), 0.5)];
bottomLineView.backgroundColor = [UIColor colorWithHexString:@"0xc8c7cc"];
[self addSubview:bottomLineView];
}
}

- (void)setTitle:(NSString *)title withIndex:(NSInteger)index
{
XTSegmentControlItem *curItem = [_items objectAtIndex:index];
[curItem resetTitle:title];
}


3:横向选项卡中每一个选项的代码如下:

#define XTSegmentControlItemFont (15)

#define XTSegmentControlHspace (0)

#define XTSegmentControlLineHeight (2)

#define XTSegmentControlAnimationTime (0.3)

#define XTSegmentControlIconWidth (50.0)

#define XTSegmentControlIconSpace (4)

typedef NS_ENUM(NSInteger, XTSegmentControlItemType)
{
XTSegmentControlItemTypeTitle = 0,
XTSegmentControlItemTypeIconUrl,
XTSegmentControlItemTypeTitleAndIcon,
};

@interface XTSegmentControlItem : UIView

@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIImageView *titleIconView;
@property (nonatomic, assign) XTSegmentControlItemType type;

- (void)setSelected:(BOOL)selected;
@end

@implementation XTSegmentControlItem

- (id)initWithFrame:(CGRect)frame title:(NSString *)title type:(XTSegmentControlItemType)type
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
_type = type;
switch (_type) {
case XTSegmentControlItemTypeIconUrl:
{
_titleIconView = [[UIImageView alloc] initWithFrame:CGRectMake((CGRectGetWidth(self.bounds)-40)/2, (CGRectGetHeight(self.bounds)-40)/2, 40, 40)];
[_titleIconView doCircleFrame];
if (title) {
[_titleIconView sd_setImageWithURL:[title urlImageWithCodePathResizeToView:_titleIconView] placeholderImage:kPlaceholderMonkeyRoundView(_titleIconView)];
}else{
[_titleIconView setImage:[UIImage imageNamed:@"tasks_all"]];
}
[self addSubview:_titleIconView];
}
break;
case XTSegmentControlItemTypeTitleAndIcon:
{
_titleLabel = ({
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];

label.font = [UIFont systemFontOfSize:(kDevice_Is_iPhone6Plus) ? (XTSegmentControlItemFont + 1) : (kDevice_Is_iPhone6 ? XTSegmentControlItemFont : XTSegmentControlItemFont - 2)];
label.textAlignment = NSTextAlignmentCenter;
label.text = title;
label.textColor = [UIColor colorWithHexString:@"0x222222"];
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
if (label.frame.size.width > CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10) {
CGRect frame = label.frame;
frame.size.width = CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10;
label.frame = frame;
}
label.center = CGPointMake((CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10) * 0.5, CGRectGetHeight(self.bounds) * 0.5);
label;
});

[self addSubview:_titleLabel];

CGFloat x = CGRectGetMaxX(_titleLabel.frame) + XTSegmentControlIconSpace;
_titleIconView = [[UIImageView alloc] initWithFrame:CGRectMake(x, (CGRectGetHeight(self.bounds) - 10) * 0.5, 10, 10)];
[_titleIconView setImage:[UIImage imageNamed:@"tag_list_up"]];
[self addSubview:_titleIconView];
}
break;
case XTSegmentControlItemTypeTitle:
default:
{
_titleLabel = ({
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(XTSegmentControlHspace, 0, CGRectGetWidth(self.bounds) - 2 * XTSegmentControlHspace, CGRectGetHeight(self.bounds))];
label.font = [UIFont systemFontOfSize:XTSegmentControlItemFont];
label.textAlignment = NSTextAlignmentCenter;
label.text = title;
label.textColor = [UIColor colorWithHexString:@"0x222222"];
label.backgroundColor = [UIColor clearColor];
label;
});

[self addSubview:_titleLabel];
}
break;
}
}
return self;
}

- (void)setSelected:(BOOL)selected
{
switch (_type) {
case XTSegmentControlItemTypeIconUrl:
{
}
break;
case XTSegmentControlItemTypeTitleAndIcon:
{
if (_titleLabel) {
[_titleLabel setTextColor:(selected ? [UIColor colorWithHexString:@"0x3bbd79"]:[UIColor colorWithHexString:@"0x222222"])];
}
if (_titleIconView) {
[_titleIconView setImage:[UIImage imageNamed: selected ? @"tag_list_down" : @"tag_list_up"]];
}
}
break;
default:
{
if (_titleLabel) {
[_titleLabel setTextColor:(selected ? [UIColor colorWithHexString:@"0x3bbd79"]:[UIColor colorWithHexString:@"0x222222"])];
}
}
break;
}
}

- (void)resetTitle:(NSString *)title
{
if (_titleLabel) {
_titleLabel.text = title;
}
if (_type == XTSegmentControlItemTypeTitleAndIcon) {
[_titleLabel sizeToFit];
if (_titleLabel.frame.size.width > CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10) {
CGRect frame = _titleLabel.frame;
frame.size.width = CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10;
_titleLabel.frame = frame;
}
_titleLabel.center = CGPointMake((CGRectGetWidth(self.bounds) - XTSegmentControlIconSpace - 10) * 0.5, CGRectGetHeight(self.bounds) * 0.5);

CGRect frame = _titleIconView.frame;
frame.origin.x = CGRectGetMaxX(_titleLabel.frame) + XTSegmentControlIconSpace;
_titleIconView.frame = frame;
}
}

@end


注意:这边创建的选项的布局,及选中时做出来的效果变化

4:弹出视图的内容TopicListView

#import <UIKit/UIKit.h>

typedef void(^TopicListViewBlock)(NSInteger index);
typedef void(^TopicListViewHideBlock)();

@interface TopicListView : UIView

- (id)initWithFrame:(CGRect)frame
titles:(NSArray *)titles
numbers:(NSArray *)numbers
defaultIndex:(NSInteger)index
selectedBlock:(TopicListViewBlock)selectedHandle
hideBlock:(TopicListViewHideBlock)hideHandle;
- (void)changeWithTitles:(NSArray *)titles
numbers:(NSArray *)numbers
defaultIndex:(NSInteger)index
selectedBlock:(TopicListViewBlock)selectedHandle
hideBlock:(TopicListViewHideBlock)hideHandle;

- (void)showBtnView;
- (void)hideBtnView;

@end


#import "TopicListView.h"
#import "TopicListButton.h"

@interface TopicListView ()
{
UIScrollView *_baseView;
UIButton *_baseBtn;
NSInteger _count;
NSInteger _index;
}

@property (nonatomic , copy) TopicListViewBlock block;
@property (nonatomic , copy) TopicListViewHideBlock hideBlock;

@end

@implementation TopicListView

- (id)initWithFrame:(CGRect)frame
titles:(NSArray *)titles
numbers:(NSArray *)numbers
defaultIndex:(NSInteger)index
selectedBlock:(TopicListViewBlock)selectedHandle
hideBlock:(TopicListViewHideBlock)hideHandle
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4];
//回调事件的赋值
self.block = selectedHandle;
self.hideBlock = hideHandle;
self.clipsToBounds = YES;

//—_baseBtn是产生后面的背景阴影
_baseBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, self.frame.size.height)];
_baseBtn.backgroundColor = [UIColor clearColor];
[_baseBtn addTarget:self action:@selector(baseBtnClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_baseBtn];

_index = index;
_count = titles.count;
CGFloat h = _count * kMySegmentControl_Height;
CGFloat sH = h;
if (h + kMySegmentControl_Height > self.frame.size.height) {
sH = self.frame.size.height - kMySegmentControl_Height;
}
//_baseView则是下拉的列表
_baseView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, -sH, kScreen_Width, sH)];
[self addSubview:_baseView];
_baseView.contentSize = CGSizeMake(kScreen_Width, h);
_baseView.bounces = FALSE;

//btnView则是在滚动视图_baseView里面,用于存放按键的容器
UIView *btnView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, h)];
btnView.backgroundColor = [UIColor whiteColor];
[_baseView addSubview:btnView];

//遍历产生按键,并判断是否被选择
for (int i=0; i<titles.count; i++) {
NSString *title = titles[i];
TopicListButton *btn;
if (numbers) {
btn = [TopicListButton buttonWithTitle:title andNumber:[numbers[i] integerValue]];
} else {
btn = [TopicListButton buttonWithTitle:title];
}
CGRect frame = btn.frame;
frame.origin.y = i * kMySegmentControl_Height;
btn.frame = frame;
btn.tag = 1000 + i;
[btn setIconHide:(_index == i ? FALSE : TRUE)];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[btnView addSubview:btn];
}
}
return self;
}

- (void)changeWithTitles:(NSArray *)titles
numbers:(NSArray *)numbers
defaultIndex:(NSInteger)index
selectedBlock:(TopicListViewBlock)selectedHandle
hideBlock:(TopicListViewHideBlock)hideHandle
{
self.block = selectedHandle;
self.hideBlock = hideHandle;

CGRect frame = _baseView.frame;
frame.origin.y = -frame.size.height;
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
_baseView.frame = frame;
} completion:^(BOOL finished) {
[_baseView removeFromSuperview];

_index = index;
_count = titles.count;
CGFloat h = _count * kMySegmentControl_Height;
CGFloat sH = h;
if (h + kMySegmentControl_Height > self.frame.size.height) {
sH = self.frame.size.height - kMySegmentControl_Height;
}
_baseView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, -sH, kScreen_Width, sH)];
[self addSubview:_baseView];
_baseView.contentSize = CGSizeMake(kScreen_Width, h);
_baseView.bounces = FALSE;

UIView *btnView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, h)];
btnView.backgroundColor = [UIColor whiteColor];
[_baseView addSubview:btnView];

for (int i=0; i<titles.count; i++) {
NSString *title = titles[i];
TopicListButton *btn;
if (numbers) {
btn = [TopicListButton buttonWithTitle:title andNumber:[numbers[i] integerValue]];
} else {
btn = [TopicListButton buttonWithTitle:title];
}
CGRect frame = btn.frame;
frame.origin.y = i * kMySegmentControl_Height;
btn.frame = frame;
btn.tag = 1000 + i;
[btn setIconHide:(_index == i ? FALSE : TRUE)];
[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[btnView addSubview:btn];
}

[self showBtnView];
}];
}
//显示下拉列表
- (void)showBtnView
{
CGRect frame = _baseView.frame;
frame.origin.y = 0;
[UIView animateWithDuration:0.3 animations:^{
_baseView.frame = frame;
} completion:^(BOOL finished) {
}];
}

//隐藏回缩事件
- (void)hideBtnView
{
CGRect frame = _baseView.frame;
frame.origin.y = -frame.size.height;
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
_baseView.frame = frame;
} completion:^(BOOL finished) {
if (self.hideBlock) {
self.hideBlock();
}
[UIView animateWithDuration:0.2 animations:^{
self.alpha = 0;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}];
}

- (void)baseBtnClick
{
[self hideBtnView];
}

//按键响应的事件 用TAG进行遍历选取 更新选中跟不选中的状态
- (void)btnClick:(TopicListButton *)sender
{
//用TAG进行遍历选取 更新选中跟不选中的状态
for (int i=1000; i<_count + 1000; i++) {
TopicListButton *btn = (TopicListButton *)[_baseView viewWithTag:i];
[btn setIconHide:(sender.tag == i ? FALSE : TRUE)];
}
//如果当前被选中的跟前面的索引值不一样说明已经发生变化 则回传回去
if (_index!=sender.tag - 1000 && self.block) {
self.block(sender.tag - 1000);
}
//隐藏下拉列表
[self hideBtnView];
}

@end


这边的代码是弹出窗的主要实现代码,以后其它功能也可以参考,包括对视图的显示跟隐藏,按键的增加跟事件创建等,背景视图的创建;

5:弹出项的TopicListButton主要代码

#import <UIKit/UIKit.h>

@interface TopicListButton : UIButton

+ (instancetype)buttonWithTitle:(NSString *)title andNumber:(NSInteger)number;
+ (instancetype)buttonWithTitle:(NSString *)title;

- (void)setIconHide:(BOOL)hide;

@end


#import "TopicListButton.h"

@interface TopicListButton ()
{
UILabel *_titleLbl;
UIImageView *_iconImg;
}
@end

@implementation TopicListButton

- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//左边的文字
_titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(kPaddingLeftWidth, 0, kScreen_Width - kPaddingLeftWidth - 20, kMySegmentControl_Height)];
_titleLbl.font = [UIFont systemFontOfSize:16];
_titleLbl.textColor = [UIColor colorWithHexString:@"0x666666"];
[self addSubview:_titleLbl];

//右边的打勾图片
_iconImg = [[UIImageView alloc] initWithFrame:CGRectMake(kScreen_Width - kPaddingLeftWidth - 18, (kMySegmentControl_Height - 18) * 0.5, 18, 18)];
[_iconImg setImage:[UIImage imageNamed:@"tag_list_s"]];
[self addSubview:_iconImg];

//下划线的实现
UIView *bottomLineView = [[UIView alloc] initWithFrame:CGRectMake(kPaddingLeftWidth, kMySegmentControl_Height - 0.6, kScreen_Width - kPaddingLeftWidth, 0.6)];
bottomLineView.backgroundColor = [UIColor colorWithHexString:@"0xdddddd"];
[self addSubview:bottomLineView];
}
return self;
}

//此方法是用于实现带有数字
+ (instancetype)buttonWithTitle:(NSString *)title andNumber:(NSInteger)number
{
TopicListButton *button = [[TopicListButton alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, kMySegmentControl_Height)];
[button setTitleLbl:[NSString stringWithFormat:@"%@(%ld)", title, (long)number]];
return button;
}

//此方法用于实现不带数字
+ (instancetype)buttonWithTitle:(NSString *)title
{
TopicListButton *button = [[TopicListButton alloc] initWithFrame:CGRectMake(0, 0, kScreen_Width, kMySegmentControl_Height)];
[button setTitleLbl:title];
return button;
}

- (void)setTitleLbl:(NSString *)title
{
_titleLbl.text = title;
}

//对于打勾图片是否显示进行控制
- (void)setIconHide:(BOOL)hide
{
_iconImg.hidden = hide;
}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: