UIKit框架-自定义视图-分段控制器

本文详细介绍了一种自定义分段控制器的实现方法,包括创建UIView子类、响应点击事件、添加指示条、实现滚动效果等步骤。通过具体代码展示了如何设置按钮样式、更新指示器位置及与控制器结合的方法。

自定义分段控制器

实现简单点击事件
效果图

这里写图片描述

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];
}
点击获取对应Demo示例

仅供参考,错误勿怪!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值