前言

iOS小技能:自定义tab滑块( segment功能+label混合显示)_iOS

需求:商户交易汇总表使用tab滑块进行切换/筛选不同级别的代理商数据

I、自定义tab滑块的用法

1.1 demo

iOS小技能:自定义tab滑块( segment功能+label混合显示)_滑块_02 ​​​​​​

需求:商户交易汇总表使用tab滑块进行切换/筛选不同级别的代理商数据

接口设计:如果数据比较大,就把统计和列表数据分开请求,这样可先展示列表数据,再展示统计数据

1.2 用法

  • 初始化控件
/**

本级代理商数据
下级代理商数据

*/
- (CRMMultipleSwitch *)MultipleSwitch{
if (nil == _MultipleSwitch) {
CRMMultipleSwitch *switch1 = [[CRMMultipleSwitch alloc]init];
_MultipleSwitch = switch1;
[self addSubview:_MultipleSwitch];

__weak __typeof__(self) weakSelf = self;



[[switch1 rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof CRMMultipleSwitch * multipleSwitch) {


NSLog(@"点击了第%zd个",multipleSwitch.selectedSegmentIndex);

}];

[switch1 mas_makeConstraints:^(MASConstraintMaker *make) {
// switch1.frame = CGRectMake(0, 0, 180, 30);

make.height.mas_equalTo(kAdjustRatio(33));
make.top.offset(kAdjustRatio(18));
make.bottom.offset(kAdjustRatio(-18));

make.left.offset(kAdjustRatio(74));
make.right.offset(kAdjustRatio(-74));


}];


}
//>推荐MultipleSwitch初始化的时候进行数据模型的赋值

return _MultipleSwitch;
}
  • 设置模型数据


推荐MultipleSwitch初始化的时候进行数据模型的赋值


- (void)setModels:(CRMMultipleSwitchCellTableViewCellModel *)models{
_models = models;

if(models.items.count>0){

self.MultipleSwitch.items= models.items;

[self setupswitchStyle];


}
}
- (CRMMerchantTransactionByPageMiddleViewModel *)viewModel{

if (_viewModel == nil) {
_viewModel = [CRMMerchantTransactionByPageMiddleViewModel new];

self.viewModel.multipleSwitchCellTableViewCellModel = [CRMMultipleSwitchCellTableViewCellModel new];
// @[@" 1",@"2 "];
self.viewModel.multipleSwitchCellTableViewCellModel.items = @[@"本级代理商数据",@"下级代理商数据"];


}
return _viewModel;

}
  • 设置更新滑块样式
- (void)layoutSubviews {
[super layoutSubviews];


[self setupswitchStyle];




}

- (void)setupswitchStyle{

[[self MultipleSwitch] layoutIfNeeded];

CRMMultipleSwitch *switch1 = self.MultipleSwitch;
// switch1.layer.borderWidth = 1 / [UIScreen mainScreen].scale;
// switch1.layer.borderColor = [UIColor whiteColor].CGColor;

switch1.layer.backgroundColor = [[UIColor colorWithRed:255.0f/255.0f green:122.0f/255.0f blue:144.0f/255.0f alpha:1.0f] CGColor];



switch1.selectedTitleColor = [UIColor redColor];

// @property (nonatomic, copy) UIColor *trackerColor; // 滑块的颜色
// @property (nonatomic, copy) UIImage *trackerImage; // 滑块的图片

switch1.titleColor = [UIColor whiteColor];

switch1.titleFont = kPingFangFont(14);

switch1.trackerColor = [UIColor whiteColor];

}

II、代码实现

头文件

CRMMultipleSwitch.h

NS_ASSUME_NONNULL_BEGIN
/**
类似segment功能,label混合显示

*/
@interface CRMMultipleSwitch : UIControl
- (instancetype)initWithItems:(NSArray *)items;

@property(nonatomic) NSInteger selectedSegmentIndex;

@property (nonatomic, strong) UIColor *titleColor;
@property (nonatomic, strong) UIColor *selectedTitleColor;

@property (nonatomic, strong) UIFont *titleFont;

@property (nonatomic, assign) CGFloat spacing; // label之间的间距
@property (nonatomic, assign) CGFloat contentInset; // 内容内宿边距

@property (nonatomic, copy) UIColor *trackerColor; // 滑块的颜色
@property (nonatomic, copy) UIImage *trackerImage; // 滑块的图片


@property (nonatomic, strong) NSArray *items;

// *)





@end

视图内部的实现

CRMMultipleSwitch.m

#import "CRMMultipleSwitch.h"

@interface SPMultipleSwitchLayer : CALayer

@end

@implementation SPMultipleSwitchLayer
- (instancetype)init {
if (self = [super init]) {
self.masksToBounds = YES;
}
return self;
}

- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
self.cornerRadius = frame.size.height/2.0;
}

- (void)setCornerRadius:(CGFloat)cornerRadius {
[super setCornerRadius:self.bounds.size.height/2.0];
}

+ (Class)layerClass{
return [SPMultipleSwitchLayer class];
}

- (void)layoutSublayers {
[super layoutSublayers];
[self layoutIfNeeded];
self.cornerRadius = self.frame.size.height/2.0;

}

@end

@interface CRMMultipleSwitch()
@property (nonatomic, strong) UIView *labelContentView;
@property (nonatomic, strong) UIView *selectedLabelContentView;
@property (nonatomic, strong) UIImageView *tracker;
@property (nonatomic, strong) NSMutableArray *labels;
@property (nonatomic, strong) NSMutableArray *selectedLabels;
@property (nonatomic, strong) UIView *maskTracker;
@property (nonatomic, assign) CGPoint beginPoint;
@end

@implementation CRMMultipleSwitch

+ (Class)layerClass{
return [SPMultipleSwitchLayer class];
}

- (instancetype)initWithItems:(NSArray *)items {
if (self = [self init]) {

// 创建子控件
// [self setupSubviewsWithItems:items];
self.items = items;
// [self.tracker addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

}
return self;
}


//- (NSArray *)setit

- (void)setItems:(NSArray *)items{
_items = items;
[self setupSubviewsWithItems:items];


}

//- (void)setupSubviewsWithItems{


// 创建子控件

//}

- (instancetype)init {
if (self = [super init]) {
_titleFont = [UIFont systemFontOfSize:17];
_titleColor = [UIColor redColor];
_selectedTitleColor = [UIColor whiteColor];

}
return self;
}

#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self.tracker) {
if ([keyPath isEqualToString:@"frame"]) {
self.maskTracker.frame = self.tracker.frame;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}

#pragma mark - UIControl Override

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[super beginTrackingWithTouch:touch withEvent:event];
_beginPoint = [touch locationInView:self];
NSInteger index = [self indexForPoint:_beginPoint];
self.selectedSegmentIndex = index;
return YES;
}

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
[super continueTrackingWithTouch:touch withEvent:event];

CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);

CGPoint currentPoint = [touch locationInView:self];
CGFloat diff = currentPoint.x - _beginPoint.x;
CGRect trackerFrame = self.tracker.frame;
trackerFrame.origin.x += diff;
trackerFrame.origin.x = MAX(MIN(CGRectGetMinX(trackerFrame),contentRect.size.width - trackerFrame.size.width), 0);
self.tracker.frame = trackerFrame;
_beginPoint = currentPoint;

[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{
[super endTrackingWithTouch:touch withEvent:event];
NSInteger index = [self indexForPoint:self.tracker.center];
self.selectedSegmentIndex = index;
}

- (void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
NSInteger index = [self indexForPoint:self.tracker.center];
self.selectedSegmentIndex = index;
}

// 根据一个点,取出离该点最近的label对应的index
- (NSInteger)indexForPoint:(CGPoint)point {
CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
NSInteger index = MAX(0, MIN(_labels.count - 1, point.x / (contentRect.size.width / (CGFloat)(_labels.count))));
return index;
}

#pragma mark - setter

- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex {
_selectedSegmentIndex = MAX(0, MIN(selectedSegmentIndex, _labels.count-1));
UILabel *label = _labels[_selectedSegmentIndex];
CGPoint trackerCenter = self.tracker.center;
trackerCenter.x = label.center.x;
self.tracker.center = trackerCenter;
// 这行代码主要是为了走一遍KVO监听的方法
self.tracker.frame = self.tracker.frame;
}

- (void)setContentInset:(CGFloat)contentInset {
_contentInset = contentInset;
[self setNeedsLayout];
[self layoutIfNeeded];
}

- (void)setSpacing:(CGFloat)spacing {
_spacing = spacing;
[self setNeedsLayout];
[self layoutIfNeeded];
}

- (void)setTrackerColor:(UIColor *)trackerColor {
_trackerColor = trackerColor;
self.tracker.backgroundColor = _trackerColor;
}

- (void)setTrackerImage:(UIImage *)trackerImage {
_trackerImage = trackerImage;
self.tracker.image = _trackerImage;
}

- (void)setTitleColor:(UIColor *)titleColor {
_titleColor = titleColor;
[_labels setValue:_titleColor forKeyPath:@"textColor"];
}

- (void)setSelectedTitleColor:(UIColor *)selectedTitleColor {
_selectedTitleColor = selectedTitleColor;
[_selectedLabels setValue:_selectedTitleColor forKeyPath:@"textColor"];
}

- (void)setTitleFont:(UIFont *)titleFont {
_titleFont = titleFont;
[_labels setValue:_titleFont forKeyPath:@"font"];
[_selectedLabels setValue:_titleFont forKeyPath:@"font"];
}

#pragma mark - 添加子控件

- (void)setupSubviewsWithItems:(NSArray *)items {

if(self.labelContentView){
[self.labelContentView removeFromSuperview];

}
//


if(self.labels.count>0){
[self.labels makeObjectsPerformSelector:@selector(removeFromSuperview)];

}

if(self.selectedLabels.count>0){
[self.selectedLabels makeObjectsPerformSelector:@selector(removeFromSuperview)];

}

if(self.tracker){
[self.tracker removeFromSuperview];

}
//

if(self.maskTracker){
[self.maskTracker removeFromSuperview];

}

if(self.selectedLabelContentView){
[self.selectedLabelContentView removeFromSuperview];

}





self.labels = [NSMutableArray array];
self.selectedLabels = [NSMutableArray array];

// 第一层
{
UIView *labelContentView = [[UIView alloc] init];
labelContentView.userInteractionEnabled = NO;
labelContentView.layer.masksToBounds = YES;
[self addSubview:labelContentView];
_labelContentView = labelContentView;

for (int i = 0; i < items.count; i++) {
UILabel *label = [[UILabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.text = items[i];
label.textColor = [UIColor blackColor];
[labelContentView addSubview:label];
[self.labels addObject:label];
}
UIImageView *tracker = [[UIImageView alloc] init];
tracker.userInteractionEnabled = NO;
tracker.layer.masksToBounds = YES;
tracker.backgroundColor = [UIColor redColor];
[labelContentView addSubview:tracker];
_tracker = tracker;
[self.tracker addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

}
// 第二层
{
UIView *selectedLabelContentView = [[UIView alloc] init];
selectedLabelContentView.userInteractionEnabled = NO;
selectedLabelContentView.layer.masksToBounds = YES;
[self addSubview:selectedLabelContentView];
_selectedLabelContentView = selectedLabelContentView;

for (int i = 0; i < items.count; i++) {
UILabel *label = [[UILabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.text = items[i];
label.textColor = [UIColor whiteColor];
[selectedLabelContentView addSubview:label];
[self.selectedLabels addObject:label];
}
UIView *maskTracker = [[UIView alloc] init];
maskTracker.userInteractionEnabled = NO;
maskTracker.backgroundColor = [UIColor redColor];
_maskTracker = maskTracker;

// 设置selectedLabelContentView的maskView,stackView是UIView的非渲染型子类,它无法设置backgroundColor,maskView等属性
_selectedLabelContentView.maskView = maskTracker;
}
}

- (void)layoutSubviews {
[super layoutSubviews];

CGRect contentRect = CGRectInset(self.bounds, self.contentInset, self.contentInset);
self.labelContentView.frame = contentRect;
self.selectedLabelContentView.frame = contentRect;
self.labelContentView.layer.cornerRadius = contentRect.size.height / 2.0;
self.selectedLabelContentView.layer.cornerRadius = contentRect.size.height / 2.0;

CGFloat labelW = (contentRect.size.width - _spacing * self.labels.count) / self.labels.count;
[self.labels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing) , 0, labelW, contentRect.size.height);
}];
[self.selectedLabels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
label.frame = CGRectMake(self->_spacing * 0.5 + idx * (labelW + self->_spacing), 0, labelW, contentRect.size.height);
}];

CGFloat averageWidth = contentRect.size.width / self.labels.count;
self.tracker.frame = CGRectMake(_selectedSegmentIndex * averageWidth, 0, averageWidth, contentRect.size.height);
self.tracker.layer.cornerRadius = contentRect.size.height / 2.0;
self.maskTracker.layer.cornerRadius = contentRect.size.height / 2.0;
}

- (void)dealloc {
[self.tracker removeObserver:self forKeyPath:@"frame"];
}

@end

see also

更多内容请关注​​ #小程序:iOS逆向​​,只为你呈现有价值的信息,专注于移动端技术研究领域。

作者:公众号iOS逆向

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。