iOS Library or DIY Etsy like category control?

喜你入骨 提交于 2019-12-04 19:49:35

If you want just the categories and not the whole TableView, then you don't need a 3rd party control. A UIScrollView is all you need.

The idea is you create a scrollview with Paging enabled and set it not to clip the contents and center it in the screen. Now because we need to be able to capture touches even beyond the left edge of the scrollView (when the user has scrolled already), we need a trick to capture the touches. This is done by using a UIView that will be in a full screen width and will pass a long the touches intercepted to our scrollView.

With that set, here is the code: First the View that captures the touches (I named it ExtendedScrollViewCaptureView):

#import <UIKit/UIKit.h>

@interface ExtendedScrollViewCaptureView : UIView {

}

@property (nonatomic,strong)UIScrollView *scrollView;

@end

Here is the implementation file:

#import "ExtendedScrollViewCaptureView.h"

@implementation ExtendedScrollViewCaptureView

@synthesize scrollView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event {
    if ([self pointInside:point withEvent:event]) {
        return scrollView;
    }
    return nil;
}

@end

Now lets go to the main thingy. Create a UIScrollView iVar in your viewController header file:

@property(nonatomic,strong)UIScrollView *scrollView;

also add 2 integer variables that monitor the maximum titles available and keep track of the selected tab:

@interface MyViewController : UIViewController<UIScrollViewDelegate>
{
    int selectedIndex;
    int maxIndex;
}

and in your implementation file:

- (void)viewDidLoad
{
    [super viewDidLoad];
    ExtendedScrollViewCaptureView *extendedView = [[ExtendedScrollViewCaptureView alloc] initWithFrame:self.navigationBar.bounds];
    extendedView.backgroundColor = [UIColor clearColor];
    extendedView.clipsToBounds = YES;

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelTapped:)];
    [extendedView addGestureRecognizer:tap];

    self.scrollView = [[UIScrollView alloc] init];
    self.scrollView.frame = CGRectMake(0,0,320,36);
    self.scrollView.pagingEnabled = YES;
    self.scrollView.showsVerticalScrollIndicator = NO;
    self.scrollView.showsHorizontalScrollIndicator = NO;
    self.scrollView.bounces = YES;
    self.scrollView.alwaysBounceHorizontal = YES;
    self.scrollView.alwaysBounceVertical = NO;
    self.scrollView.backgroundColor = [UIColor clearColor];
    self.scrollView.delegate = self;
    self.scrollView.scrollsToTop = NO;
    //add the scrollView inside the extendedView
    [extendedView addSubview:self.scrollView];

    //get the pointer reference
    extendedView.scrollView = self.scrollView;

    //add the arrow inside the extendedView
    UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow.png"]];
    arrow.frame = CGRectMake(154, 36, 11, 6);
    [extendedView addSubview:arrow];

     //add the extendedSubView to the view
     [self.view addSubview:extendedView];

     //init the scrollView with some entries:
     [self setUpScrollView:[NSArray arrayWithObjects:@"LABEL 1",@"LABEL 2",@"LABEL 3",@"LABEL 4",@"LABEL 5",nil]];
}

Now create the function to init your ScrollView with the title labels (the labels being passed as an NSArray)

- (void)setUpScrollView:(NSArray *)titleLabels {

    int scrollSize = 320;
    int i = 0;
    int offsetX = 0;
    int scrollViewWidth = 0;
    maxIndex = titleLabels.count;

    //if our scrollview has already the labels stop here
    if ([self.scrollView subviews].count>0) {
        self.scrollView.contentOffset = CGPointZero;
        return;
    }
    //get the max width of the labels, which will define our label width
    for (NSString *titleLabel in titleLabels) {
        CGSize expectedLabelSize = [[titleLabel capitalizedString] sizeWithFont:[UIFont fontWithName:kFontFamily1 size:kFontFamily1Correction+13] constrainedToSize:CGSizeMake(320, 22)];
        scrollViewWidth = MAX(scrollViewWidth,expectedLabelSize.width);
    }

    //restrict max width for title items to 106 pixels (to fit 3 labels in the screen)
    //this is optional and can adjusted or removed, but I suggest to make labels equal width

    scrollViewWidth = MIN(scrollViewWidth, 106);

    //now draw the labels
    for (NSString *titleLabel in titleLabels) {

        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(offsetX, 5, scrollViewWidth, 34)];

        label.text = [titleLabel capitalizedString];
        label.adjustsFontSizeToFitWidth = NO;
        label.numberOfLines = 2;
        label.backgroundColor = [UIColor clearColor];
        label.font = [UIFont fontWithName:@"ArialMT" size:13];

        if (i==selectedItem) {
            label.textColor = [UIColor redColor];
        }
        else {
            label.textColor = [UIColor whiteColor];
        }

        label.textAlignment = UITextAlignmentCenter;
        label.tag = 23000+i;

        [self.scrollView addSubview:label];

        offsetX+=scrollViewWidth;

        i++;
    }

    self.scrollView.frame = CGRectMake((320-scrollViewWidth)/2, 0, scrollViewWidth, 36);
    self.scrollView.clipsToBounds = NO;        
    self.scrollView.contentSize = CGSizeMake(MAX(scrollSize,offsetX), 36);
    self.scrollView.contentOffset = CGPointMake(scrollViewWidth*selectedItem, 0);
}

Now capture the UIScrollView scroll event, from the delegate:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    //get the index of the label we scrolled into!
    int visiblePageIndex = round(scrollView.contentOffset.x/scrollView.bounds.size.width);
    //set page number..
    if (selectedIndex!=visiblePageIndex) {

        //get the label and set it to red
        UILabel *label = (UILabel*)[self.scrollView viewWithTag:23000+visiblePageIndex];
        label.textColor = [UIColor redColor];

        //get the previous Label and set it back to White
        UILabel *oldLabel = (UILabel*)[self.scrollView viewWithTag:23000+selectedIndex];
        oldLabel.textColor = [UIColor whiteColor];

        //set the new index to the index holder
        selectedIndex = visiblePageIndex;
    }

}

finally we need the function to capture the title tap events:

- (void)labelTapped:(UITapGestureRecognizer*)gestureRecognizer {
    CGPoint pressPoint = [gestureRecognizer locationInView:gestureRecognizer.view];

    if (pressPoint.x>(self.scrollView.frame.size.width+self.view.frame.size.width)/2) {
        //move to next page if one is available...
        if (selectedIndex+1<maxIndex) {
            float currentOffset = self.scrollView.contentOffset.x+self.scrollView.frame.size.width;
            [self.scrollView setContentOffset:CGPointMake(currentOffset, 0) animated:YES];
        }        
    }
    else if (pressPoint.x<(self.view.frame.size.width-self.scrollView.frame.size.width)/2) {
        //move to previous page if one is available
        if (selectedIndex>0) {
            float currentOffset = self.scrollView.contentOffset.x-self.scrollView.frame.size.width;
            [self.scrollView setContentOffset:CGPointMake(currentOffset, 0) animated:YES];
        }
    }
}

That's it!

There's a similar control up on github at https://github.com/rs/SDSegmentedControl. They use a UISegmentedControl subclass to create the effect. Cocoacontrols.com is your friend. :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!