1. Write at the front:

Some time ago, the project used the scrollbar at the top of the similar news client. Although there are many online, I wrote one by myself in order to exercise myself. Fortunately, the effect was not bad, so I shared it for everyone’s reference on the one hand, and also for my own record.

Upper effect picture:

2. Usage:

Method 1:

NSArray *titleArray = @[@ "recommended".@ "hot spots".@ "video".@ "sports".@ "funny"];
NSMutableArray *vcArray = @[].mutableCopy;
for (int i = 0; i<titleArray.count; i++) {
    ViewController *vc = [ViewController new];
    [vcArray addObject:vc];
}
XBYTopTabBarViewController *tabVC = [[XBYTopTabBarViewController alloc] initWithSegmentTitles:titleArray childVcs:vcArray];
[self.navigationController pushViewController:tabVC animated:YES];
Copy the code

Method 2 :(recommended)

/ / new ViewController inheritance XBYTopTabBarViewController, rewrite the init method
- (instancetype)init {
    if (self = [super init]) {
        NSArray *tabNames = @[@ "recommended".@ "hot spots".@ "video".@ "sports".@ "funny"];

        NSMutableArray *vcs = @[].mutableCopy;
        for (NSString *name in tabNames) {
            ViewController *vc = [[ViewController alloc]init];
            [vcs addObject:vc];
        }
        self = [super initWithSegmentTitles:tabNames childVcs:vcs];
    }

    return self;
}

Copy the code

Here is encapsulated is a ViewController, online a lot of encapsulation is the view, need a series of configuration, I feel more troublesome, or inherited some fast, after inheriting XBYTopTabBarViewController, how much is a new multiple vc, call

- (instancetype)initWithSegmentTitles:(NSArray *)titles
                             childVcs:(NSArray *)childVcs;
Copy the code

Method, here inherited VC and many children vc life cycle has been set, can not care, just need to inherit (lazy bit inheritance also do not, directly call the above method), other do not care.

3. Implementation ideas:

I’m going to use two ScrollViews, and I’m going to use a scrollView in the title column (I can use other views, too, because I don’t need to slide left or right, but I need to respond to clicks), and I’m going to use smallScrollViews, The bottom part that slides left and right is also a scrollView, followed by a bigScrollView. SmallScrollView smallScrollView smallScrollView smallScrollView smallScrollView smallScrollView smallScrollView smallScrollView smallScrollView

- (void)setupSmallScrollView {
    CGFloat labelW = kScreenWidth/(self.segmentTitles.count>5?5:self.segmentTitles.count);
    self.smallScrollView.contentSize = CGSizeMake(labelW * self.segmentTitles.count, 44);
    
    CGFloat labelX,labelY = 0, labelH = smallScrollViewH;
    for (int i = 0; i < self.segmentTitles.count; i++) {
        labelX = i * labelW;
        GGSOrderStatusLabel *label = [[GGSOrderStatusLabel alloc]initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)];
        label.text = self.segmentTitles[i];
        label.tag = i;
        label.userInteractionEnabled = YES;
        [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelTapAction:)]];
        [self.smallScrollView addSubview:label]; }}Copy the code

Add a gesture to the label in response to the click event, and make the bigScrollView associate with the smallScrollView’s children:

- (void)labelTapAction:(UITapGestureRecognizer *)gesture {
    GGSOrderStatusLabel *titlelable = (GGSOrderStatusLabel *)gesture.view;
    if (titlelable.tag == _currentIndex) {
        return;
    }
    
    CGFloat offsetX = titlelable.tag * self.bigScrollView.frame.size.width;
    
    CGFloat offsetY = self.bigScrollView.contentOffset.y;
    CGPoint offset = CGPointMake(offsetX, offsetY);
    
    [self.bigScrollView setContentOffset:offset animated:YES];  // Click on the label TAB of the smallScrollView.
    
}
Copy the code

SmallScrollView/bigScrollView/smallScrollView

/** call */ after scrolling
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    // Get the index
    NSUInteger index = scrollView.contentOffset.x / self.bigScrollView.frame.size.width;
    
    // Scroll the title bar
    GGSOrderStatusLabel *titleLable = (GGSOrderStatusLabel *)self.smallScrollView.subviews[index];
    // label is in the middle offsetx
    CGFloat offsetx = titleLable.center.x - self.smallScrollView.frame.size.width * 0.5;
    CGFloat offsetMax = self.smallScrollView.contentSize.width - self.smallScrollView.frame.size.width;
    if (offsetx < 0) {
        offsetx = 0;
    }else if (offsetx > offsetMax){
        offsetx = offsetMax;
    }
    CGPoint offset = CGPointMake(offsetx, self.smallScrollView.contentOffset.y);
    // Only if you put it in the GCD
    dispatch_async(GCD_MAINQUEUE, ^{
        [self.smallScrollView setContentOffset:offset animated:YES];
    });
    
    UIViewController *oldVC = nil;
    if(_currentIndex ! =- 1) {
        oldVC = self.childVcs[_currentIndex];
    }
    
    UIViewController *newsVc = self.childVcs[index];
    self.currentIndex = index;
    // Set other labels to their initial state
    [self.smallScrollView.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if(idx ! = index) { GGSOrderStatusLabel *temlabel =self.smallScrollView.subviews[idx];
            temlabel.scale = 0.0; }}];if (newsVc.view.superview)  {// Call lifecycle functions (viewwillAppear, etc.)
        if (oldVC) {
            [newsVc beginAppearanceTransition:NO animated:YES];
            [newsVc endAppearanceTransition];
        }
        
        [newsVc beginAppearanceTransition:YES animated:YES];
        [newsVc endAppearanceTransition];
        return;
    }
    
    [self addChildViewController:newsVc];
    newsVc.view.frame = scrollView.bounds;// Bounds x is the offsetx of the scrollView
    [self.bigScrollView addSubview:newsVc.view];
    [newsVc didMoveToParentViewController:self];
    
    if ([self.delegate respondsToSelector:@selector(segmentViewController:didAddChildViewController:)]) {
        [self.delegate segmentViewController:selfdidAddChildViewController:newsVc]; }}Copy the code

3. The other

See the following header description:

@protocol XBYTopTabBarViewControllerDelegate <NSObject>

@optional
- (void)topTabBarViewController:(XBYTopTabBarViewController *)topTabBarVC
didAddChildViewController:(UIViewController *)childVC;

@end

@interface XBYTopTabBarViewController : UIViewController

/** The title of the slider above */
@property (nonatomic.strong.readonly) NSArray *segmentTitles;

/** A slider corresponds to a viewController */
@property (nonatomic.strong.readonly) NSMutableArray *childVcs;

/** Index of the current slider */
@property (nonatomic.assign) NSInteger currentIndex;

/** scrollView */
@property (nonatomic.strong) UIScrollView *smallScrollView;

/** Hold scrollView */ for viewController
@property (nonatomic.strong) UIScrollView *bigScrollView;

@property (nonatomic.weak) id<XBYTopTabBarViewControllerDelegate> delegate;

/** <#Description#> @param childVcs slider @return <#return value Description#> */
- (instancetype)initWithSegmentTitles:(NSArray *)titles
childVcs:(NSArray *)childVcs;

Copy the code

4. Contact information

Email: [email protected] Related Account:

  • Denver – Adrenine
  • Jane – Adrenine book
  • Blog – Adrenine
  • Github – Adrenine

5.Demo:

XBYTopTabBarViewController