Repository navigation
Description
今天主要介绍的是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];
举个例子
比如,我要实现下面这样一个分段组件,点击不同的分类,切换展示不同的商品列表:
这里贴上主要的代码,这里主要用到了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