Skip to content

iOS — HMSegmentedControl实现选项卡 #8

Open

Description

@cssoul

今天主要介绍的是HMSegmentedControl ,它是 UISegmentedControl 的替代品,模仿了 Google Currents 使用的效果,在界面和交互上可以更好的定制。通常项目中遇到切换或者筛选的功能,使用这个第三方库能够很方便的解决问题。

详细了解,请戳:https://github.com/HeshamMegid/HMSegmentedControl

安装

一、CocoaPods

如果安装了CocoaPods,只需要执行:

pod 'HMSegmentedControl'

二、原始的方式

1、拷贝HMSegmentedControl.h 和 HMSegmentedControl.m到项目中;
2、添加QuartzCore.framework到  'linked frameworks and libraries'
3、在需要使用的文件引入 #import "HMSegmentedControl.h"

使用姿势

- (void)viewDidLoad {
    [super viewDidLoad];

    //初始化并设置分段控件标题
    HMSegmentedControl *segmentedControl = [[HMSegmentedControl alloc] initWithSectionTitles:@[@"热门", @"关注", @"直播"]];

    //设置控件的Frame
    segmentedControl.frame = CGRectMake(10, 10, 300, 60);

    //绑定代理事件
    [segmentedControl addTarget:self action:@selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged];

    //添加控件到View中
    [self.view addSubview:segmentedControl];
}

- (void)segmentedControlChangedValue:(HMSegmentedControl *)segmentedControl {
    NSLog(@"Selected index %ld ", (long)segmentedControl.selectedSegmentIndex); //打印选中索引 (eg:Selected index 6)
}

拜读源码

和UISegmentedControl一样,HMSegmentedControl也继承UIControl,可见作者是完全自定义了一个UISegmentedControl

@interface HMSegmentedControl : UIControl

    ...

@end

继续阅读HMSegmentedControl.h,会发现作者定义了很多枚举,不仅仅代码看起来很清晰,而且能够很方便的扩展和维护;

//定义分段控件的样式
typedef enum {
    HMSegmentedControlTypeText,     //纯文本
    HMSegmentedControlTypeImages,   //图片
    HMSegmentedControlTypeTextImages    //图文结合
} HMSegmentedControlType;


//定义分段控件选中项的风格
typedef enum {
    HMSegmentedControlSelectionStyleTextWidthStripe, // 指示器根据文本长度自适应宽度

    HMSegmentedControlSelectionStyleFullWidthStripe, // 指示器填充整个Segment

    HMSegmentedControlSelectionStyleBox, // 选中项会有整块背景色

    HMSegmentedControlSelectionStyleArrow // 有箭头标识选中项,尽头的方向可以通过设置`HMSegmentedControlSelectionIndicatorLocation`的值

} HMSegmentedControlSelectionStyle;


....

接下来就是一堆的属性和方法定义,这里就不再罗列了;

打开HMSegmentedControl.m,看到作者定义了一个HMScrollView,继承自UIScrollView,用来处理控件对touch事件的相应;

@implementation HMScrollView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}

@end

同时HMSegmentedControl还定义了一些私有的属性,比如:

@property (nonatomic, strong) CALayer *selectionIndicatorStripLayer;    //指示器的横条Layer

@property (nonatomic, strong) HMScrollView *scrollView; //控件的外层View容器

这里看到作者只用了CALayer。正因为使用了CALayer,所以头部引用了QuartzCore.h;
接下来阅读,就是各种初始化的方法:

- (id)initWithSectionTitles:(NSArray *)sectiontitles {

}
......

初始化的方法都调用了- (void)commonInit方法,查阅該方法,可以看到这里主要处理属性的默认值,比如:

_backgroundColor = [UIColor whiteColor];
self.opaque = NO;
......

接下来是一个比较重要的方法- (void)drawRect:(CGRect)rect,通过条件语句判断type,来渲染不同的样式,其中HMSegmentedControlTypeTextImages这种图文混合的排版比较复杂,有兴趣可以细读这块源码。同时,根据不同的selectionStyle设置选择指示器的样式;

后面的- (void)setSelectedSegmentIndex:***方法比较重要,主要用来处理点击响应事件,从而移动选中指示器的位置,里面用到了CALayer的位移动画;

[CATransaction begin];
[CATransaction setAnimationDuration:0.15f];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[self setArrowFrame];
self.selectionIndicatorBoxLayer.frame = [self frameForSelectionIndicator];
self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
[CATransaction commit];

举个例子

比如,我要实现下面这样一个分段组件,点击不同的分类,切换展示不同的商品列表:

CAAnimation

这里贴上主要的代码,这里主要用到了HMSegmentedControlTypeTextImages的图文混排方式,然后需要注意的是,设置Indicator图片要适当的在上方留白处理,就能做到选中状态那种效果

#import <HMSegmentedControl/HMSegmentedControl.h>

@interface FilterView ()
@property (nonatomic, strong) HMSegmentedControl *segmentControl;
@end

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.frame = CGRectMake(0, 0, FULL_WIDTH, 45.f)];
        self.backgroundColor = [UIColor whiteColor];

        [self addSubview:self.segmentControl];
    }
    return self;
}


- (void)setEntity:(NSArray *)entity {

    NSMutableArray *titles = [NSMutableArray arrayWithCapacity:5];
    NSMutableArray *images = [NSMutableArray arrayWithCapacity:5];
    NSMutableArray *selectedImages = [NSMutableArray arrayWithCapacity:5];

    UIImage *image = [UIImage imageNamed:@"icon"];  //透明背景
    UIImage *sImage = [UIImage imageNamed:@"icon_selected"]; //带图标的选中状态背景

    for (.... *item in entity) {
        NSString *title = item.title;

        if (title) {
            [titles addObject:title];
            [images addObject:title];
            [sImage addObject:title];
        }
    }

    [self showSegmentControl:titles sectionImages:images sectionSelectedImages:sImage];
}


-(void)showSegmentControl:(NSArray *)titles sectionImages:(NSArray *)images sectionSelectedImages:(NSArray *)sImage
{
    if(sectiontitles.count > 0){
        _segmentControl.sectionTitles = titles;
        _segmentControl.sectionImages = images;
        _segmentControl.sectionSelectedImages = sImage;

        __weak typeof(self) weakSelf = self;
        [_segmentControl setIndexChangeBlock:^(NSInteger index) {
            [weakSelf segmentDidSelectedAtIndex:index];
        }];
    }
}

- (void)segmentDidSelectedAtIndex:(NSInteger)index
{
    NSLog(@"Selected index %ld ", (long)index); //打印索引
}


-(HMSegmentedControl *)segmentControl
{
    if(!_segmentControl){
        _segmentControl = [[HMSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, FULL_WIDTH, 45.f)];
        _segmentControl.type = HMSegmentedControlTypeTextImages;
        _segmentControl.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
        _segmentControl.segmentEdgeInset = UIEdgeInsetsMake(0, 18, 0, 18);

        _segmentControl.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationNone;
        _segmentControl.backgroundColor = [UIColor clearColor];
        _segmentControl.selectionStyle = HMSegmentedControlSelectionStyleTextWidthStripe;
        _segmentControl.segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;
        _segmentControl.titleTextAttributes = @{NSFontAttributeName : FONT(15), NSForegroundColorAttributeName : RGB(103, 103, 103)};
        _segmentControl.selectedTitleTextAttributes = @{NSForegroundColorAttributeName : RGB(255, 51, 0)};          _segmentControl.selectedSegmentIndex = 0;
    }       
    return _segmentControl;
}

@end

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions