iOS Library or DIY Etsy like category control?

2019-04-16 15:03发布

I'm trying to find a library or sample project for the sliding categories view that Etsy has in their iPhone app.

enter image description here

I'm talking about re-creating the "Handpicked, History, and Seasonal" categories swipe effect at the top of the app's main view.

If anybody knows of one on Github, or maybe a kickstart on how to do something like this, that would be awesome!

2条回答
劫难
2楼-- · 2019-04-16 15:38

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. :)

查看更多
来,给爷笑一个
3楼-- · 2019-04-16 15:44

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!

查看更多
登录 后发表回答