效果如下
![]() | ![]() |
原理:使用第三方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
新聞熱點
疑難解答