自定义分段控制器
实现简单点击事件
效果图
1.创建工程、创建UIView子类YYJTopView;
2.YYJTopView.h文件声明一个数组用于接受内容;
#import <UIKit/UIKit.h>
@interface YYJTopScrollView : UIScrollView
/** 存放标题的数组 */
@property (nonatomic,strong) NSArray *titleArray;
@end
3.YYJTopView.m文件实现数组seter方法,常见标题按钮
#pragma mark ~~~~~~~~~~ Setter ~~~~~~~~~~
- (void)setTitleArray:(NSArray *)titleArray {
_titleArray = titleArray;
// 初始化内部标题按钮
CGFloat buttonW = self.frame.size.width / titleArray.count;
CGFloat buttonH = self.frame.size.height;
for (int i=0; i<titleArray.count; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
// 设置标题
[button setTitle:titleArray[i] forState:UIControlStateNormal];
// 设置默认字体颜色
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
// 设置点击时字体颜色
[button setTitleColor:[UIColor redColor] forState:UIControlStateDisabled];
// 设置按钮尺寸
[button setFrame:CGRectMake(buttonW * i, 0, buttonW, buttonH)];
// 设置点击方法
[button addTarget:self action:@selector(tap:) forControlEvents:UIControlEventTouchUpInside];
// 记入标签
button.tag = i;
if (i == 0) {
[self tap:button];
}
[self addSubview:button];
}
}
4.实现按钮点击方法
#pragma mark ~~~~~~~~~~ 点击方法 ~~~~~~~~~~
- (void)tap:(UIButton *)button {
// 将上一个点击的按钮设置可以点击(如果没有点击按钮不妨碍代码执行)
_selectBtn.enabled = YES;
// 叫点击的按钮设置不能点击
button.enabled = NO;
// 将点击按钮赋值给selectBtn进行保存记录
_selectBtn = button;
NSLog(@"你点击了第%zd个按钮",button.tag);
}
这里按钮的状态不用UIControlStateSelected而用UIControlStateDisabled,是因为当按钮处于selected状态时,按钮仍然可以点击,如果在处于selected状态的按钮再次点击,会再次执行button点击事件方法,而Disabled状态是不能点击。防止了页面刷新后多次反复点击会反复调用点击方法。
添加指示条
效果图
1.添加UIView的分类(作用是快速设置/获取UIView子类的属性)
File > Objective-C file
2. UIIView-YYJExtension.h 声明属性
#import <UIKit/UIKit.h>
@interface UIView (YYJExtentsion)
@property (nonatomic,assign) CGFloat x;
@property (nonatomic,assign) CGFloat y;
@property (nonatomic,assign) CGFloat centerx;
@property (nonatomic,assign) CGFloat centery;
@property (nonatomic,assign) CGFloat width;
@property (nonatomic,assign) CGFloat height;
@end
3. UIIView-YYJExtension.m 实现setter/getter方法
#pragma mark ~~~~~~~~~~ Setter ~~~~~~~~~~
- (void)setX:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (void)setY:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (void)setWidth:(CGFloat)width {
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (void)setHeight:(CGFloat)height {
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (void)setCenterx:(CGFloat)centerx {
CGPoint center = self.center;
center.x = centerx;
self.center = center;
}
- (void)setCentery:(CGFloat)centery {
CGPoint center = self.center;
center.y = centery;
self.center = center;
}
#pragma mark ~~~~~~~~~~ Getter ~~~~~~~~~~
- (CGFloat)x {
return self.frame.origin.x;
}
- (CGFloat)y {
return self.frame.origin.y;
}
- (CGFloat)width {
return self.frame.size.width;
}
- (CGFloat)height {
return self.frame.size.height;
}
- (CGFloat)centerx {
return self.center.x;
}
- (CGFloat)centery {
return self.center.y;
}
3.创建指示器
// 创建指示器,并设置他的颜色、高度和y值
_indicatorView = [[UIView alloc] init];
_indicatorView.backgroundColor = [UIColor redColor];
_indicatorView.height = 2;
_indicatorView.y = self.frame.size.height - _indicatorView.height;
[self addSubview:_indicatorView];
4.设置指示器宽度
// button执行sizeToFit方法,强制更新尺寸
[button.titleLabel sizeToFit];
_indicatorView.width = button.titleLabel.width;
_indicatorView.centerx = button.centerx;
5.点击按钮时更新指示器位置
[UIView animateWithDuration:0.5 animations:^{
_indicatorView.centerx = button.centerx;
}];
实现多内容滚动效果
效果图
1.计算内容长度
// 计算内容的长度
CGFloat buttonW = [titleArray[i] boundingRectWithSize:CGSizeMake(MAXFLOAT, buttonH) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:20]} context:nil].size.width + 30;
2.设置不同按钮x值
// 设置按钮尺寸
[button setFrame:CGRectMake(buttonX , 0, buttonW, buttonH)];
buttonX += buttonW;
3.实现标题居中
- (void)setupButtonCenter:(UIButton *)button {
// 居中时偏移量为0
CGFloat offset = button.centerx - self.centerx;
// 如果按钮在左边,则不做操作
if (offset < 0) offset = 0;
// 如果按钮在右边,则偏移
// 获取最大的偏移量(最大偏移量=内容宽-屏幕宽)
CGFloat maxOffset = self.contentSize.width - self.width;
// 如果最大偏移量还小于0(内容数组不够充满屏幕)则赋值0
if (maxOffset < 0) maxOffset = 0;
// 如果按钮偏移量大于最大偏移量,则等于最大偏移量(相当于不做操作)
if (offset > maxOffset) offset = maxOffset;
// 实现动态偏移
[self setContentOffset:CGPointMake(offset, 0) animated:YES];
}
与控制器结合
效果图
1.添加子控制器
for (int i=0; i<array.count; i++) {
UIViewController *view = [[UIViewController alloc] init];
[self addChildViewController:view];
}
2.初始化底部滚动视图(用于盛放子控制器视图),并展示第一个视图
self.mainScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, topScroll.y+topScroll.height, self.view.width, self.view.height)];
self.mainScroll.showsVerticalScrollIndicator = NO;
self.mainScroll.showsHorizontalScrollIndicator = NO;
self.mainScroll.bounces = NO;
self.mainScroll.delegate = self;
self.mainScroll.pagingEnabled = YES;
self.mainScroll.contentSize = CGSizeMake(self.view.width * array.count, 0);
[self.view addSubview:self.mainScroll];
// 获取第一个视图
[self scrollViewDidEndScrollingAnimation:self.mainScroll];
3.YYJTopScollView.h声明代理方法
@protocol YYJTopScrollViewDelegate <NSObject>
// 按钮点击方法(index:按钮索引)
- (void)tap:(NSInteger)index;
@end
@interface YYJTopScrollView : UIScrollView
/** 代理 */
@property (nonatomic,weak) id <YYJTopScrollViewDelegate>YYJTopScrollViewDelegate;
// 按钮点击方法
- (void)tap:(UIButton *)button;
@end
4.实现YYJTopScrollViewDelegate
// 代理
if ([self.YYJTopScrollViewDelegate respondsToSelector:@selector(tap:)]) {
[self.YYJTopScrollViewDelegate tap:button.tag];
}
5.实现UIScollViewDelegate
#pragma mark ~~~~~~~~~~ ScrollViewDelegate ~~~~~~~~~~
// 滑动结束调用
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
// 获取当前偏移的索引
NSInteger index = scrollView.contentOffset.x / scrollView.width;
// 获取第index个子控制器设置尺寸,并添加到滚动视图上
UIViewController *vc = self.childViewControllers[index];
vc.view.frame = CGRectMake(scrollView.width * index, 0, scrollView.width, scrollView.height);
CGFloat r = arc4random()%255/255.0;
CGFloat g = arc4random()%255/255.0;
CGFloat b = arc4random()%255/255.0;
vc.view.backgroundColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];
[scrollView addSubview:vc.view];
UILabel *label = [[UILabel alloc] initWithFrame:vc.view.bounds];
[vc.view addSubview:label];
label.text = [NSString stringWithFormat:@"%zd",index];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont systemFontOfSize:50];
}
// 滑动减速停止时调用
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self scrollViewDidEndScrollingAnimation:scrollView];
// 找到当前点击的按钮
NSMutableArray *buttonArray = [NSMutableArray array];
for (UIView *view in self.topScroll.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
[buttonArray addObject:view];
}
}
// 当前视图索引
NSInteger index = scrollView.contentOffset.x / scrollView.width;
UIButton *button = buttonArray[index];
// 点击button改变按钮属性
[self.topScroll tap:button];
}
6.实现监听按钮点击的代理方法
- (void)tap:(NSInteger)index {
// 底部滚动视图偏移到对应索引位置
[self.mainScroll setContentOffset:CGPointMake(self.mainScroll.width * index, 0) animated:YES];
}