This is the 10th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021.

preface

Requirement: Merchant transaction summary table uses TAB slider to switch/filter different levels of agent data

Video address: live.csdn.net/v/156406

Download Demo:https://download.csdn.net/download/u011018979/19790950

I. Custom TAB slider usage

1.1 the demo

Download Demo:https://download.csdn.net/download/u011018979/19790950Video Address:live.csdn.net/v/156406

Requirement: Merchant transaction summary table uses TAB slider to switch/filter different levels of agent data

Interface design: If the data is large, request statistics and tabular data separately so that tabular data is displayed first and statistics are displayed later

1.2 usage

  • Initialize the controller
/** Agent data */
- (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(@" Click on the %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.));


        }];
        
        
    }
    //> It is recommended that the data model be assigned when MultipleSwitch is initialized

    return _MultipleSwitch;
}


Copy the code
  • Setting model data

It is recommended that the data model be assigned when MultipleSwitch is initialized

- (void)setModels:(CRMMultipleSwitchCellTableViewCellModel *)models{
    _models = models;
    
    if(models.items.count>0) {self.MultipleSwitch.items= models.items;
  
  [selfsetupswitchStyle]; }}Copy the code
- (CRMMerchantTransactionByPageMiddleViewModel *)viewModel{
    
    if (_viewModel == nil) {
        _viewModel = [CRMMerchantTransactionByPageMiddleViewModel new];
        
        self.viewModel.multipleSwitchCellTableViewCellModel = [CRMMultipleSwitchCellTableViewCellModel new];
/ / @ [@ "1," @ "2");
        self.viewModel.multipleSwitchCellTableViewCellModel.items = @[@" Agent data of this level".@" Sub-agent data"];
        
        
    }
    return _viewModel;
    
}

Copy the code
  • Set the update slider style
- (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; // Color of the slider
        // @property (nonatomic, copy) UIImage *trackerImage; // The slider image

                switch1.titleColor = [UIColor whiteColor];
                
    switch1.titleFont = kPingFangFont(14);

                switch1.trackerColor = [UIColor whiteColor];
    
}

Copy the code

II. Code implementation

The header file

CRMMultipleSwitch.h

NS_ASSUME_NONNULL_BEGIN
/** Similar to segment function, label mixed display */
@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; // The spacing between labels
@property (nonatomic.assign) CGFloat  contentInset; // Inside the content of the margin

@property (nonatomic.copy) UIColor *trackerColor; // Color of the slider
@property (nonatomic.copy) UIImage *trackerImage; // The slider image


@property (nonatomic.strong) NSArray *items;

/ / *)





@end

Copy the code

Internal implementation of the view

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(a)
@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]) {
        
        // Create a child control
// [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{
    
    
    // Create a child control

/ /}

- (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{[superobserveValueForKeyPath: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;
}

// According to a point, fetch the index corresponding to the nearest label to that point
- (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;
    // This line of code is mainly to walk through the KVO listening method
    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"];
}

#pragmaMark - Adds child controls

- (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];
    
    / / the first layer
    {
        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];

    }
    / / the second floor
    {
        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;
        
        // Set selectedLabelContentView's maskView. StackView is a non-render subclass of UIView. It cannot set backgroundColor,maskView, etc_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


Copy the code

see also

For more, check out # Applets: iOS Reverse, which presents valuable information only for you, focusing on the mobile technology research field.

The copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.