Recently, I reconstructed the communication book page of the project. The index bar of the old version was quite ugly. I looked for the wheel and couldn’t find it, so I had to make it myself. I found that wechat’s address book index bar style is not bad, so I wrote a copy and added the Impact Feedback incidentally.

First let’s look at the effect

When you click the index bar

When the sliding tableView

When you swipe on the index bar

Realize the principle of

1. Each index is UILabel

Arrange all labels vertically in a parent view. There is no reuse pool, and the average index bar is not too many letters.

_labelArr = [NSMutableArray new]; for (int i = 0; i < indexes.count; i++) { CGFloat y = (_sectionHeight * i); UILabel *alphaLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y, width, height)]; alphaLabel.textAlignment = NSTextAlignmentCenter; alphaLabel.text = [[indexes objectAtIndex:i] uppercaseString]; AlphaLabel. The font = [UIFont boldSystemFontOfSize: 10.0]; alphaLabel.backgroundColor = [UIColor clearColor]; alphaLabel.textColor = self.textColor; AlphaLabel. Layer. The cornerRadius = width * 0.5; alphaLabel.clipsToBounds = YES; [self addSubview:alphaLabel]; [_labelArr addObject:alphaLabel]; }Copy the code
2. Associate touch points and index labels

When touched in the parent view, the relationship between the touch point and the index label is handled by methods such as’ touchMoved ‘. If the touch point falls within the label range, the label is highlighted.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self]; [self toSelectTitle:touchPoint]; } / / find the corresponding index through touchPoint label - (void) toSelectTitle: CGPoint touchPoint {the if (touchPoint. < x = 0 | | touchPoint. < y = 0 | | touchPoint.x >= self.bounds.size.width || touchPoint.y >= self.bounds.size.height) return; __block NSString *title; __block NSInteger index = 0; [_labelArr enumerateObjectsUsingBlock:^(__kindof UILabel * _Nonnull subview, NSUInteger idx, BOOL * _Nonnull stop) { if(touchPoint.y < CGRectGetMaxY(subview.frame)) { _preLabel.backgroundColor = [UIColor clearColor]; _preLabel.textColor = _textColor; subview.backgroundColor = _selectedBackgroundColor; subview.textColor = _selectedTextColor; _preLabel = subview; index = idx; title = subview.text; *stop = YES; } }]; . }Copy the code
3, add vibration effect

Add a vibrate effect and trigger a click callback

// Vibrate if (@available(iOS 10.0, *)) { UIImpactFeedbackGenerator *gen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; [gen prepare]; [gen impactOccurred]; } // Callback if (_delegate && [_delegate conformsToProtocol:@protocol(TTIndexBarDelegate)]) {[_delegate indexDidChanged:self index:index title:title]; }Copy the code
4. Select the bubble implementation
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetLineWidth (context, 2.0); CGContextSetFillColorWithColor(context,_drawColor.CGColor); [self getDrawPath:context]; CGContextFillPath(context); } - (void)getDrawPath:(CGContextRef)context { CGFloat width = self.bounds.size.width; CGFloat height = self.bounds.size.height; CGFloat xOffset = self.bounds.size.width * 1/4; CGFloat yOffset = self.bounds.size.height * 1/4; CGFloat radius = sqrt(pow(xOffset, 2) + pow(yOffset, 2)); //Draw triangle CGContextMoveToPoint(context, width-xoffset, height * 0.5-yoffset); CGContextAddLineToPoint (context, width, height * 0.5); CGContextAddLineToPoint(context, width-xoffset, height * 0.5 + yOffset); //Draw semicircle CGContextAddArcToPoint(context, width * 0.5, height, width * 0.5 - xOffset, height * 0.5 + yOffset, radius); CGContextAddArcToPoint(context, 0, height * 0.5, width * 0.5-xoffset, height * 0.5-yoffset, radius); CGContextAddArcToPoint(context, width * 0.5, 0, width * 0.5 + xOffset, height * 0.5-yoffset, radius); CGContextAddArcToPoint(context, width * 0.5, 0, width * 0.5 + xOffset, height * 0.5-yoffset, radius) CGContextClosePath(context); }Copy the code

How to use

The default styles
self.indexBar = [[TTIndexBar alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 30, 0, 30, self.view.frame.size.height)];
self.indexBar.delegate = self;
[self.view addSubview:self.indexBar];
    
[self.indexBar setIndexes:[NSMutableArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J", nil]];
Copy the code
Custom styles
self.indexBar = [[TTIndexBar alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 30, 0, 30, self.view.frame.size.height)];
self.indexBar.delegate = self;
[self.view addSubview:self.indexBar];   

//Custom property
self.indexBar.textColor = [UIColor redColor];
self.indexBar.selectedTextColor = [UIColor greenColor];
self.indexBar.selectedBackgroundColor = [UIColor yellowColor];
self.indexBar.detailViewDrawColor = [UIColor cyanColor];
self.indexBar.detailViewTextColor = [UIColor orangeColor];

[self.indexBar setIndexes:[NSMutableArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J", nil]];
Copy the code
Agent callback
- (void)indexDidChanged:(TTIndexBar *)indexBar index:(NSInteger)index title:(NSString *)title;
Copy the code

GitHub

TTIndexBar

The source of the English annotations are their own translation, a little foot 😂 we may want to see more Chinese annotations

If you have any questions or suggestions, please leave a comment below. Thank you.