HMSegmentedControl地址
HMSegmentedControl是一款選項卡的三方框架,github上有3000星左右。
研究了一下源碼,并添加了一點注釋。
HMSegmentedControl基于UIControl,上面有一個UIScrollView。
文字,圖片,指示器都是用CALayer,UIBezierPath處理創建的。
//
// HMSegmentedControl.h
// HMSegmentedControl
//
// Created by Hesham Abd-Elmegid on 23/12/12.
// Copyright (c) 2012-2015 Hesham Abd-Elmegid. All rights reserved.
//
#import <UIKit/UIKit.h>
@class HMSegmentedControl;
//點擊按鈕的block
typedef void (^IndexChangeBlock)(NSInteger index);
//Title富文本
typedef NSAttributedString *(^HMTitleFormatterBlock)(HMSegmentedControl *segmentedControl, NSString *title, NSUInteger index, BOOL selected);
//指示器的樣式
typedef NS_ENUM(NSInteger, HMSegmentedControlSelectionStyle) {
//指示器和文字同寬
HMSegmentedControlSelectionStyleTextWidthStripe, // Indicator width will only be as big as the text width
//指示器和segment同寬
HMSegmentedControlSelectionStyleFullWidthStripe, // Indicator width will fill the whole segment
//矩形指示器
HMSegmentedControlSelectionStyleBox, // A rectangle that covers the whole segment
//箭頭指示器
HMSegmentedControlSelectionStyleArrow // An arrow in the middle of the segment pointing up or down depending on `HMSegmentedControlSelectionIndicatorLocation`
};
//指示器位置樣式
typedef NS_ENUM(NSInteger, HMSegmentedControlSelectionIndicatorLocation) {
//上
HMSegmentedControlSelectionIndicatorLocationUp,
//下
HMSegmentedControlSelectionIndicatorLocationDown,
//無
HMSegmentedControlSelectionIndicatorLocationNone // No selection indicator
};
typedef NS_ENUM(NSInteger, HMSegmentedControlSegmentWidthStyle) {
//寬度fix
HMSegmentedControlSegmentWidthStyleFixed, // Segment width is fixed
//segment的寬度和text的寬度一致
HMSegmentedControlSegmentWidthStyleDynamic, // Segment width will only be as big as the text width (including inset)
};
//邊框類型
typedef NS_OPTIONS(NSInteger, HMSegmentedControlBorderType) {
HMSegmentedControlBorderTypeNone = 0,
HMSegmentedControlBorderTypeTop = (1 << 0),
HMSegmentedControlBorderTypeLeft = (1 << 1),
HMSegmentedControlBorderTypeBottom = (1 << 2),
HMSegmentedControlBorderTypeRight = (1 << 3)
};
enum {
HMSegmentedControlNoSegment = -1 // Segment index for no selected segment
};
//segment類型
typedef NS_ENUM(NSInteger, HMSegmentedControlType) {
//文本
HMSegmentedControlTypeText,
//圖片
HMSegmentedControlTypeImages,
//圖文
HMSegmentedControlTypeTextImages
};
@interface HMSegmentedControl : UIControl
@property (nonatomic, strong) NSArray<NSString *> *sectionTitles; // section標題
@property (nonatomic, strong) NSArray<UIImage *> *sectionImages; // section圖片
@property (nonatomic, strong) NSArray<UIImage *> *sectionSelectedImages; // 選中的section圖片
/**
Provide a block to be executed when selected index is changed.
Alternativly, you could use `addTarget:action:forControlEvents:`
*/
/**
選中index之后的回調
可以使用`addTarget:action:forControlEvents:`替代
*/
@property (nonatomic, copy) IndexChangeBlock indexChangeBlock;
/**
Used to apply custom text styling to titles when set.
When this block is set, no additional styling is applied to the `NSAttributedString` object returned from this block.
*/
/**
自定義富文本標題
*/
@property (nonatomic, copy) HMTitleFormatterBlock titleFormatter;
/**
Text attributes to apply to item title text.
*/
/**
標題 text 屬性
*/
@property (nonatomic, strong) NSDictionary *titleTextAttributes UI_APPEARANCE_SELECTOR;
/*
Text attributes to apply to selected item title text.
Attributes not set in this dictionary are inherited from `titleTextAttributes`.
*/
@property (nonatomic, strong) NSDictionary *selectedTitleTextAttributes UI_APPEARANCE_SELECTOR;
/**
Segmented control background color.
Default is `[UIColor whiteColor]`
*/
/**
背景顏色
*/
@property (nonatomic, strong) UIColor *backgroundColor UI_APPEARANCE_SELECTOR;
/**
Color for the selection indicator stripe
Default is `R:52, G:181, B:229`
*/
/**
指示器顏色
*/
@property (nonatomic, strong) UIColor *selectionIndicatorColor UI_APPEARANCE_SELECTOR;
/**
Color for the selection indicator box
Default is selectionIndicatorColor
*/
/**
box顏色
*/
@property (nonatomic, strong) UIColor *selectionIndicatorBoxColor UI_APPEARANCE_SELECTOR;
/**
Color for the vertical divider between segments.
Default is `[UIColor blackColor]`
*/
/**
segment間的分割線的顏色
*/
@property (nonatomic, strong) UIColor *verticalDividerColor UI_APPEARANCE_SELECTOR;
/**
Opacity for the seletion indicator box.
Default is `0.2f`
*/
/**
不透明的盒子對比指標
*/
@property (nonatomic) CGFloat selectionIndicatorBoxOpacity;
/**
Width the vertical divider between segments that is added when `verticalDividerEnabled` is set to YES.
Default is `1.0f`
*/
/**
分割線高度
*/
@property (nonatomic, assign) CGFloat verticalDividerWidth;
/**
Specifies the style of the control
Default is `HMSegmentedControlTypeText`
*/
@property (nonatomic, assign) HMSegmentedControlType type;
/**
Specifies the style of the selection indicator.
Default is `HMSegmentedControlSelectionStyleTextWidthStripe`
*/
@property (nonatomic, assign) HMSegmentedControlSelectionStyle selectionStyle;
/**
Specifies the style of the segment's width.
Default is `HMSegmentedControlSegmentWidthStyleFixed`
*/
@property (nonatomic, assign) HMSegmentedControlSegmentWidthStyle segmentWidthStyle;
/**
Specifies the location of the selection indicator.
Default is `HMSegmentedControlSelectionIndicatorLocationUp`
*/
@property (nonatomic, assign) HMSegmentedControlSelectionIndicatorLocation selectionIndicatorLocation;
/*
Specifies the border type.
Default is `HMSegmentedControlBorderTypeNone`
*/
@property (nonatomic, assign) HMSegmentedControlBorderType borderType;
/**
Specifies the border color.
Default is `[UIColor blackColor]`
*/
@property (nonatomic, strong) UIColor *borderColor;
/**
Specifies the border width.
Default is `1.0f`
*/
/**
邊框顏色
*/
@property (nonatomic, assign) CGFloat borderWidth;
/**
Default is YES. Set to NO to deny scrolling by dragging the scrollView by the user.
*/
/**
是否可以拖拽
*/
@property(nonatomic, getter = isUserDraggable) BOOL userDraggable;
/**
Default is YES. Set to NO to deny any touch events by the user.
*/
/**
是否可以點擊
*/
@property(nonatomic, getter = isTouchEnabled) BOOL touchEnabled;
/**
Default is NO. Set to YES to show a vertical divider between the segments.
*/
/**
分割線是否顯示
*/
@property(nonatomic, getter = isVerticalDividerEnabled) BOOL verticalDividerEnabled;
/**
Index of the currently selected segment.
*/
/**
選中的標號
*/
@property (nonatomic, assign) NSInteger selectedSegmentIndex;
/**
Height of the selection indicator. Only effective when `HMSegmentedControlSelectionStyle` is either `HMSegmentedControlSelectionStyleTextWidthStripe` or `HMSegmentedControlSelectionStyleFullWidthStripe`.
Default is 5.0
*/
/**
指示器高度
*/
@property (nonatomic, readwrite) CGFloat selectionIndicatorHeight;
/**
Edge insets for the selection indicator.
NOTE: This does not affect the bounding box of HMSegmentedControlSelectionStyleBox
When HMSegmentedControlSelectionIndicatorLocationUp is selected, bottom edge insets are not used
When HMSegmentedControlSelectionIndicatorLocationDown is selected, top edge insets are not used
Defaults are top: 0.0f
left: 0.0f
bottom: 0.0f
right: 0.0f
*/
@property (nonatomic, readwrite) UIEdgeInsets selectionIndicatorEdgeInsets;
/**
Inset left and right edges of segments.
Default is UIEdgeInsetsMake(0, 5, 0, 5)
*/
@property (nonatomic, readwrite) UIEdgeInsets segmentEdgeInset;
@property (nonatomic, readwrite) UIEdgeInsets enlargeEdgeInset;
/**
Default is YES. Set to NO to disable animation during user selection.
*/
@property (nonatomic) BOOL shouldAnimateUserSelection;
//初始化
- (id)initWithSectionTitles:(NSArray<NSString *> *)sectiontitles;
- (id)initWithSectionImages:(NSArray<UIImage *> *)sectionImages sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages;
- (instancetype)initWithSectionImages:(NSArray<UIImage *> *)sectionImages sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages titlesForSections:(NSArray<NSString *> *)sectiontitles;
- (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated;
- (void)setIndexChangeBlock:(IndexChangeBlock)indexChangeBlock;
- (void)setTitleFormatter:(HMTitleFormatterBlock)titleFormatter;
@end
segment
//
// HMSegmentedControl.m
// HMSegmentedControl
//
// Created by Hesham Abd-Elmegid on 23/12/12.
// Copyright (c) 2012-2015 Hesham Abd-Elmegid. All rights reserved.
//
#import "HMSegmentedControl.h"
#import <QuartzCore/QuartzCore.h>
#import <math.h>
@interface HMScrollView : UIScrollView
@end
@implementation HMScrollView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (!self.dragging) {
[self.nextResponder touchesBegan:touches withEvent:event];
} else {
[super touchesBegan:touches withEvent:event];
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (!self.dragging) {
[self.nextResponder touchesMoved:touches withEvent:event];
} else{
[super touchesMoved:touches withEvent:event];
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (!self.dragging) {
[self.nextResponder touchesEnded:touches withEvent:event];
} else {
[super touchesEnded:touches withEvent:event];
}
}
@end
@interface HMSegmentedControl ()
//3中不同的指示器的layer
@property (nonatomic, strong) CALayer *selectionIndicatorStripLayer;
@property (nonatomic, strong) CALayer *selectionIndicatorBoxLayer;
@property (nonatomic, strong) CALayer *selectionIndicatorArrowLayer;
@property (nonatomic, readwrite) CGFloat segmentWidth;
@property (nonatomic, readwrite) NSArray<NSNumber *> *segmentWidthsArray;
@property (nonatomic, strong) HMScrollView *scrollView;
@end
@implementation HMSegmentedControl
#pragma mark - 初始化
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithSectionTitles:(NSArray<NSString *> *)sectiontitles {
self = [super initWithFrame:CGRectZero];
if (self) {
[self commonInit];
self.sectionTitles = sectiontitles;
self.type = HMSegmentedControlTypeText;
}
return self;
}
- (id)initWithSectionImages:(NSArray<UIImage *> *)sectionImages sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages {
self = [super initWithFrame:CGRectZero];
if (self) {
[self commonInit];
self.sectionImages = sectionImages;
self.sectionSelectedImages = sectionSelectedImages;
self.type = HMSegmentedControlTypeImages;
}
return self;
}
- (instancetype)initWithSectionImages:(NSArray<UIImage *> *)sectionImages sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages titlesForSections:(NSArray<NSString *> *)sectiontitles {
self = [super initWithFrame:CGRectZero];
if (self) {
[self commonInit];
if (sectionImages.count != sectiontitles.count) {
//報錯信息
[NSException raise:NSRangeException format:@"***%s: Images bounds (%ld) Don't match Title bounds (%ld)", sel_getName(_cmd), (unsigned long)sectionImages.count, (unsigned long)sectiontitles.count];
}
self.sectionImages = sectionImages;
self.sectionSelectedImages = sectionSelectedImages;
self.sectionTitles = sectiontitles;
self.type = HMSegmentedControlTypeTextImages;
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
self.segmentWidth = 0.0f;
}
#pragma mark - createView
/**
初始化界面與參數
*/
- (void)commonInit {
//創建底層scrollview
self.scrollView = [[HMScrollView alloc] init];
self.scrollView.scrollsToTop = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
[self addSubview:self.scrollView];
_backgroundColor = [UIColor whiteColor];
//opaque也是表示當前的UIView的不透明度,設置是否之后對于UIView的顯示并沒有什么影響,官方文檔的意思簡單點說就是opaque默認為YES,如果alpha小于1,那么應該設置opaque設置為NO,但是如果alpha為1,opaque設置為NO,產生的后果是不可預料的~
self.opaque = NO;
//設置指示器背景顏色
_selectionIndicatorColor = [UIColor colorWithRed:52.0f/255.0f green:181.0f/255.0f blue:229.0f/255.0f alpha:1.0f];
_selectionIndicatorBoxColor = _selectionIndicatorColor;
//默認選中0
self.selectedSegmentIndex = 0;
self.segmentEdgeInset = UIEdgeInsetsMake(0, 5, 0, 5);
self.selectionIndicatorHeight = 5.0f;
self.selectionIndicatorEdgeInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
self.selectionStyle = HMSegmentedControlSelectionStyleTextWidthStripe;
self.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationUp;
self.segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;
self.userDraggable = YES;
self.touchEnabled = YES;
self.verticalDividerEnabled = NO;
self.type = HMSegmentedControlTypeText;
self.verticalDividerWidth = 1.0f;
_verticalDividerColor = [UIColor blackColor];
self.borderColor = [UIColor blackColor];
self.borderWidth = 1.0f;
self.shouldAnimateUserSelection = YES;
//初始化三個layer
self.selectionIndicatorArrowLayer = [CALayer layer];
self.selectionIndicatorStripLayer = [CALayer layer];
self.selectionIndicatorBoxLayer = [CALayer layer];
self.selectionIndicatorBoxLayer.opacity = self.selectionIndicatorBoxOpacity;
self.selectionIndicatorBoxLayer.borderWidth = 1.0f;
self.selectionIndicatorBoxOpacity = 0.2;
// redraw on bounds change (calls -setNeedsDisplay)
// 當界面的bounds改變的時候調用-setNeedsDisplay
self.contentMode = UIViewContentModeRedraw;
}
- (void)layoutSubviews {
[super layoutSubviews];
[self updateSegmentsRects];
}
getter & setter
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self updateSegmentsRects];
}
- (void)setSectionTitles:(NSArray<NSString *> *)sectionTitles {
_sectionTitles = sectionTitles;
// Allows you to perform layout before the drawing cycle happens. -layoutIfNeeded forces layout early
[self setNeedsLayout];
[self setNeedsDisplay];
}
- (void)setSectionImages:(NSArray<UIImage *> *)sectionImages {
_sectionImages = sectionImages;
[self setNeedsLayout];
[self setNeedsDisplay];
}
- (void)setSelectionIndicatorLocation:(HMSegmentedControlSelectionIndicatorLocation)selectionIndicatorLocation {
_selectionIndicatorLocation = selectionIndicatorLocation;
if (selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationNone) {
self.selectionIndicatorHeight = 0.0f;
}
}
- (void)setSelectionIndicatorBoxOpacity:(CGFloat)selectionIndicatorBoxOpacity {
_selectionIndicatorBoxOpacity = selectionIndicatorBoxOpacity;
self.selectionIndicatorBoxLayer.opacity = _selectionIndicatorBoxOpacity;
}
- (void)setSegmentWidthStyle:(HMSegmentedControlSegmentWidthStyle)segmentWidthStyle {
// Force HMSegmentedControlSegmentWidthStyleFixed when type is HMSegmentedControlTypeImages.
if (self.type == HMSegmentedControlTypeImages) {
_segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;
} else {
_segmentWidthStyle = segmentWidthStyle;
}
}
- (void)setBorderType:(HMSegmentedControlBorderType)borderType {
_borderType = borderType;
[self setNeedsDisplay];
}
UIView的setNeedsDisplay和setNeedsLayout方法
兩個方法都是異步執行的。而setNeedsDisplay會調用自動調用drawRect方法,這樣可以拿到 UIGraphicsGetCurrentContext,就可以畫畫了。而setNeedsLayout會默認調用layoutSubViews,
就可以 處理子視圖中的一些數據。
綜上所訴,setNeedsDisplay方便繪圖,而layoutSubViews方便出來數據。
layoutSubviews在以下情況下會被調用:
1、init初始化不會觸發layoutSubviews。
2、addSubview會觸發layoutSubviews。
3、設置view的Frame會觸發layoutSubviews,當然前提是frame的值設置前后發生了變化。
4、滾動一個UIScrollView會觸發layoutSubviews。
5、旋轉Screen會觸發父UIView上的layoutSubviews事件。
6、改變一個UIView大小的時候也會觸發父UIView上的layoutSubviews事件。
7、直接調用setLayoutSubviews。
drawRect在以下情況下會被調用:
1、如果在UIView初始化時沒有設置rect大小,將直接導致drawRect不被自動調用。drawRect調用是在Controller->loadView, Controller->viewDidLoad 兩方法之后掉用的.所以不用擔心在控制器中,這些View的drawRect就開始畫了.這樣可以在控制器中設置一些值給View(如果這些View draw的時候需要用到某些變量值).
2、該方法在調用sizeToFit后被調用,所以可以先調用sizeToFit計算出size。然后系統自動調用drawRect:方法。
3、通過設置contentMode屬性值為UIViewContentModeRedraw。那么將在每次設置或更改frame的時候自動調用drawRect:。
4、直接調用setNeedsDisplay,或者setNeedsDisplayInRect:觸發drawRect:,但是有個前提條件是rect不能為0。
以上1,2推薦;而3,4不提倡
- (void)drawRect:(CGRect)rect {
// 設置背景填充色
[self.backgroundColor setFill];
UIRectFill([self bounds]);
// 箭頭layer指示器的顏色
self.selectionIndicatorArrowLayer.backgroundColor = self.selectionIndicatorColor.CGColor;
self.selectionIndicatorStripLayer.backgroundColor = self.selectionIndicatorColor.CGColor;
// boxlayer背景顏色與線框顏色
self.selectionIndicatorBoxLayer.backgroundColor = self.selectionIndicatorBoxColor.CGColor;
self.selectionIndicatorBoxLayer.borderColor = self.selectionIndicatorBoxColor.CGColor;
// Remove all sublayers to avoid drawing images over existing ones
// 移除scrollview的所有的layer防止重繪
self.scrollView.layer.sublayers = nil;
CGRect oldRect = rect;
if (self.type == HMSegmentedControlTypeText) {
//當segment的type 等于文字的時候
[self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
// 初始化文字高度寬度
CGFloat stringWidth = 0;
CGFloat stringHeight = 0;
// 計算文字在有無富文本的高度
CGSize size = [self measureTitleAtIndex:idx];
stringWidth = size.width;
stringHeight = size.height;
CGRect rectDiv = CGRectZero;
CGRect fullRect = CGRectZero;
// Text inside the CATextLayer will appear blurry unless the rect values are rounded
// 判斷指示器位置是否在上方
BOOL locationUp = (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp);
// 判斷指示器是不是box類型
BOOL selectionStyleNotBox = (self.selectionStyle != HMSegmentedControlSelectionStyleBox);
// y =(frame的高度 - 是否是box類型 * 指示器的高度) / 2 - 文字高度 / 2 + 指示器的高度 * 是否在上方
CGFloat y = roundf((CGRectGetHeight(self.frame) - selectionStyleNotBox * self.selectionIndicatorHeight) / 2 - stringHeight / 2 + self.selectionIndicatorHeight * locationUp);
CGRect rect;
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
// 當width 的類型是 fixed的時候
rect = CGRectMake((self.segmentWidth * idx) + (self.segmentWidth - stringWidth) / 2, y, stringWidth, stringHeight);
rectDiv = CGRectMake((self.segmentWidth * idx) - (self.verticalDividerWidth / 2), self.selectionIndicatorHeight * 2, self.verticalDividerWidth, self.frame.size.height - (self.selectionIndicatorHeight * 4));
fullRect = CGRectMake(self.segmentWidth * idx, 0, self.segmentWidth, oldRect.size.height);
} else {
// When we are drawing dynamic widths, we need to loop the widths array to calculate the xOffset
CGFloat xOffset = 0;
NSInteger i = 0;
for (NSNumber *width in self.segmentWidthsArray) {
if (idx == i)
break;
xOffset = xOffset + [width floatValue];
i++;
}
CGFloat widthForIndex = [[self.segmentWidthsArray objectAtIndex:idx] floatValue];
rect = CGRectMake(xOffset, y, widthForIndex, stringHeight);
fullRect = CGRectMake(self.segmentWidth * idx, 0, widthForIndex, oldRect.size.height);
rectDiv = CGRectMake(xOffset - (self.verticalDividerWidth / 2), self.selectionIndicatorHeight * 2, self.verticalDividerWidth, self.frame.size.height - (self.selectionIndicatorHeight * 4));
}
// Fix rect position/size to avoid blurry labels
rect = CGRectMake(ceilf(rect.origin.x), ceilf(rect.origin.y), ceilf(rect.size.width), ceilf(rect.size.height));
//不用label 用 catextlayer
CATextLayer *titleLayer = [CATextLayer layer];
titleLayer.frame = rect;
titleLayer.alignmentMode = kCAAlignmentCenter;
if ([UIDevice currentDevice].systemVersion.floatValue < 10.0 ) {
titleLayer.truncationMode = kCATruncationEnd;
}
titleLayer.string = [self attributedTitleAtIndex:idx];
titleLayer.contentsScale = [[UIScreen mainScreen] scale];
[self.scrollView.layer addSublayer:titleLayer];
// Vertical Divider
// 判斷是否顯示分割線
if (self.isVerticalDividerEnabled && idx > 0) {
CALayer *verticalDividerLayer = [CALayer layer];
verticalDividerLayer.frame = rectDiv;
verticalDividerLayer.backgroundColor = self.verticalDividerColor.CGColor;
[self.scrollView.layer addSublayer:verticalDividerLayer];
}
[self addBackgroundAndBorderLayerWithRect:fullRect];
}];
} else if (self.type == HMSegmentedControlTypeImages) {
//當segment的type 等于圖片的時候
[self.sectionImages enumerateObjectsUsingBlock:^(id iconImage, NSUInteger idx, BOOL *stop) {
UIImage *icon = iconImage;
CGFloat imageWidth = icon.size.width;
CGFloat imageHeight = icon.size.height;
CGFloat y = roundf(CGRectGetHeight(self.frame) - self.selectionIndicatorHeight) / 2 - imageHeight / 2 + ((self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp) ? self.selectionIndicatorHeight : 0);
CGFloat x = self.segmentWidth * idx + (self.segmentWidth - imageWidth)/2.0f;
CGRect rect = CGRectMake(x, y, imageWidth, imageHeight);
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = rect;
if (self.selectedSegmentIndex == idx) {
if (self.sectionSelectedImages) {
UIImage *highlightIcon = [self.sectionSelectedImages objectAtIndex:idx];
imageLayer.contents = (id)highlightIcon.CGImage;
} else {
imageLayer.contents = (id)icon.CGImage;
}
} else {
imageLayer.contents = (id)icon.CGImage;
}
[self.scrollView.layer addSublayer:imageLayer];
// Vertical Divider
if (self.isVerticalDividerEnabled && idx>0) {
CALayer *verticalDividerLayer = [CALayer layer];
verticalDividerLayer.frame = CGRectMake((self.segmentWidth * idx) - (self.verticalDividerWidth / 2), self.selectionIndicatorHeight * 2, self.verticalDividerWidth, self.frame.size.height-(self.selectionIndicatorHeight * 4));
verticalDividerLayer.backgroundColor = self.verticalDividerColor.CGColor;
[self.scrollView.layer addSublayer:verticalDividerLayer];
}
[self addBackgroundAndBorderLayerWithRect:rect];
}];
} else if (self.type == HMSegmentedControlTypeTextImages){
//當segment的type 等于圖文的時候
[self.sectionImages enumerateObjectsUsingBlock:^(id iconImage, NSUInteger idx, BOOL *stop) {
UIImage *icon = iconImage;
CGFloat imageWidth = icon.size.width;
CGFloat imageHeight = icon.size.height;
CGFloat stringHeight = [self measureTitleAtIndex:idx].height;
CGFloat yOffset = roundf(((CGRectGetHeight(self.frame) - self.selectionIndicatorHeight) / 2) - (stringHeight / 2));
CGFloat imageXOffset = self.segmentEdgeInset.left; // Start with edge inset
CGFloat textXOffset = self.segmentEdgeInset.left;
CGFloat textWidth = 0;
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
imageXOffset = (self.segmentWidth * idx) + (self.segmentWidth / 2.0f) - (imageWidth / 2.0f);
textXOffset = self.segmentWidth * idx;
textWidth = self.segmentWidth;
} else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
// When we are drawing dynamic widths, we need to loop the widths array to calculate the xOffset
CGFloat xOffset = 0;
NSInteger i = 0;
for (NSNumber *width in self.segmentWidthsArray) {
if (idx == i) {
break;
}
xOffset = xOffset + [width floatValue];
i++;
}
imageXOffset = xOffset + ([self.segmentWidthsArray[idx] floatValue] / 2.0f) - (imageWidth / 2.0f); //(self.segmentWidth / 2.0f) - (imageWidth / 2.0f)
textXOffset = xOffset;
textWidth = [self.segmentWidthsArray[idx] floatValue];
}
CGFloat imageYOffset = roundf((CGRectGetHeight(self.frame) - self.selectionIndicatorHeight) / 2.0f);
CGRect imageRect = CGRectMake(imageXOffset, imageYOffset, imageWidth, imageHeight);
CGRect textRect = CGRectMake(textXOffset, yOffset, textWidth, stringHeight);
// Fix rect position/size to avoid blurry labels
textRect = CGRectMake(ceilf(textRect.origin.x), ceilf(textRect.origin.y), ceilf(textRect.size.width), ceilf(textRect.size.height));
CATextLayer *titleLayer = [CATextLayer layer];
titleLayer.frame = textRect;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.string = [self attributedTitleAtIndex:idx];
if ([UIDevice currentDevice].systemVersion.floatValue < 10.0 ) {
titleLayer.truncationMode = kCATruncationEnd;
}
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = imageRect;
if (self.selectedSegmentIndex == idx) {
if (self.sectionSelectedImages) {
UIImage *highlightIcon = [self.sectionSelectedImages objectAtIndex:idx];
imageLayer.contents = (id)highlightIcon.CGImage;
} else {
imageLayer.contents = (id)icon.CGImage;
}
} else {
imageLayer.contents = (id)icon.CGImage;
}
[self.scrollView.layer addSublayer:imageLayer];
titleLayer.contentsScale = [[UIScreen mainScreen] scale];
[self.scrollView.layer addSublayer:titleLayer];
[self addBackgroundAndBorderLayerWithRect:imageRect];
}];
}
// Add the selection indicators
// 添加選中的指示器
if (self.selectedSegmentIndex != HMSegmentedControlNoSegment) {
if (self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
if (!self.selectionIndicatorArrowLayer.superlayer) {
[self setArrowFrame];
[self.scrollView.layer addSublayer:self.selectionIndicatorArrowLayer];
}
} else {
if (!self.selectionIndicatorStripLayer.superlayer) {
self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
[self.scrollView.layer addSublayer:self.selectionIndicatorStripLayer];
if (self.selectionStyle == HMSegmentedControlSelectionStyleBox && !self.selectionIndicatorBoxLayer.superlayer) {
self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
[self.scrollView.layer insertSublayer:self.selectionIndicatorBoxLayer atIndex:0];
}
}
}
}
}
/**
計算title的cgsize
@param index 位置
@return 寬高
*/
- (CGSize)measureTitleAtIndex:(NSUInteger)index {
if (index >= self.sectionTitles.count) {
return CGSizeZero;
}
id title = self.sectionTitles[index];
CGSize size = CGSizeZero;
// 判斷index是否和當前選中的index相等
BOOL selected = (index == self.selectedSegmentIndex) ? YES : NO;
if ([title isKindOfClass:[NSString class]] && !self.titleFormatter) {
// 當title是string類型 而且formatter不存在的時候
// 選中與非選中的時候返回一個富文本
NSDictionary *titleAttrs = selected ? [self resultingSelectedTitleTextAttributes] : [self resultingTitleTextAttributes];
size = [(NSString *)title sizeWithAttributes:titleAttrs];//計算文字經過富文本處理后的size
} else if ([title isKindOfClass:[NSString class]] && self.titleFormatter) {
// 當title是string類型 而且富文本存在的時候
size = [self.titleFormatter(self, title, index, selected) size];
} else if ([title isKindOfClass:[NSAttributedString class]]) {
size = [(NSAttributedString *)title size];
} else {
NSAssert(title == nil, @"Unexpected type of segment title: %@", [title class]);
size = CGSizeZero;
}
// 返回結果的最小矩形將源矩形值轉換為整數。
return CGRectIntegral((CGRect){CGPointZero, size}).size;
}
/**
返回一個富文本string
@param index index
@return 富文本string
*/
- (NSAttributedString *)attributedTitleAtIndex:(NSUInteger)index {
id title = self.sectionTitles[index];
BOOL selected = (index == self.selectedSegmentIndex) ? YES : NO;
if ([title isKindOfClass:[NSAttributedString class]]) {
return (NSAttributedString *)title;
} else if (!self.titleFormatter) {
NSDictionary *titleAttrs = selected ? [self resultingSelectedTitleTextAttributes] : [self resultingTitleTextAttributes];
// the color should be cast to CGColor in order to avoid invalid context on iOS7
UIColor *titleColor = titleAttrs[NSForegroundColorAttributeName];
if (titleColor) {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:titleAttrs];
dict[NSForegroundColorAttributeName] = (id)titleColor.CGColor;
titleAttrs = [NSDictionary dictionaryWithDictionary:dict];
}
return [[NSAttributedString alloc] initWithString:(NSString *)title attributes:titleAttrs];
} else {
return self.titleFormatter(self, title, index, selected);
}
}
/**
添加背景和border 的layer
@param fullRect cgrect
*/
- (void)addBackgroundAndBorderLayerWithRect:(CGRect)fullRect {
// Background layer
CALayer *backgroundLayer = [CALayer layer];
backgroundLayer.frame = fullRect;
[self.layer insertSublayer:backgroundLayer atIndex:0];
// Border layer
if (self.borderType & HMSegmentedControlBorderTypeTop) {
CALayer *borderLayer = [CALayer layer];
borderLayer.frame = CGRectMake(0, 0, fullRect.size.width, self.borderWidth);
borderLayer.backgroundColor = self.borderColor.CGColor;
[backgroundLayer addSublayer: borderLayer];
}
if (self.borderType & HMSegmentedControlBorderTypeLeft) {
CALayer *borderLayer = [CALayer layer];
borderLayer.frame = CGRectMake(0, 0, self.borderWidth, fullRect.size.height);
borderLayer.backgroundColor = self.borderColor.CGColor;
[backgroundLayer addSublayer: borderLayer];
}
if (self.borderType & HMSegmentedControlBorderTypeBottom) {
CALayer *borderLayer = [CALayer layer];
borderLayer.frame = CGRectMake(0, fullRect.size.height - self.borderWidth, fullRect.size.width, self.borderWidth);
borderLayer.backgroundColor = self.borderColor.CGColor;
[backgroundLayer addSublayer: borderLayer];
}
if (self.borderType & HMSegmentedControlBorderTypeRight) {
CALayer *borderLayer = [CALayer layer];
borderLayer.frame = CGRectMake(fullRect.size.width - self.borderWidth, 0, self.borderWidth, fullRect.size.height);
borderLayer.backgroundColor = self.borderColor.CGColor;
[backgroundLayer addSublayer: borderLayer];
}
}
/**
設置箭頭指示器
*/
- (void)setArrowFrame {
self.selectionIndicatorArrowLayer.frame = [self frameForSelectionIndicator];
self.selectionIndicatorArrowLayer.mask = nil;
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
CGPoint p1 = CGPointZero;
CGPoint p2 = CGPointZero;
CGPoint p3 = CGPointZero;
if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationDown) {
p1 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width / 2, 0);
p2 = CGPointMake(0, self.selectionIndicatorArrowLayer.bounds.size.height);
p3 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width, self.selectionIndicatorArrowLayer.bounds.size.height);
}
if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp) {
p1 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width / 2, self.selectionIndicatorArrowLayer.bounds.size.height);
p2 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width, 0);
p3 = CGPointMake(0, 0);
}
[arrowPath moveToPoint:p1];
[arrowPath addLineToPoint:p2];
[arrowPath addLineToPoint:p3];
[arrowPath closePath];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.selectionIndicatorArrowLayer.bounds;
maskLayer.path = arrowPath.CGPath;
self.selectionIndicatorArrowLayer.mask = maskLayer;
}
/**
計算選中指示器的rect
@return rect
*/
- (CGRect)frameForSelectionIndicator {
CGFloat indicatorYOffset = 0.0f;
// 類型是向下
if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationDown) {
indicatorYOffset = self.bounds.size.height - self.selectionIndicatorHeight + self.selectionIndicatorEdgeInsets.bottom;
}
// 類型是向上
if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp) {
indicatorYOffset = self.selectionIndicatorEdgeInsets.top;
}
CGFloat sectionWidth = 0.0f;
// 文字類型
if (self.type == HMSegmentedControlTypeText) {
CGFloat stringWidth = [self measureTitleAtIndex:self.selectedSegmentIndex].width;
sectionWidth = stringWidth;
} else if (self.type == HMSegmentedControlTypeImages) {
// 圖片類型
UIImage *sectionImage = [self.sectionImages objectAtIndex:self.selectedSegmentIndex];
CGFloat imageWidth = sectionImage.size.width;
sectionWidth = imageWidth;
} else if (self.type == HMSegmentedControlTypeTextImages) {
// 圖文類型
CGFloat stringWidth = [self measureTitleAtIndex:self.selectedSegmentIndex].width;
UIImage *sectionImage = [self.sectionImages objectAtIndex:self.selectedSegmentIndex];
CGFloat imageWidth = sectionImage.size.width;
sectionWidth = MAX(stringWidth, imageWidth);
}
if (self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
// 箭頭
CGFloat widthToEndOfSelectedSegment = (self.segmentWidth * self.selectedSegmentIndex) + self.segmentWidth;
CGFloat widthToStartOfSelectedIndex = (self.segmentWidth * self.selectedSegmentIndex);
CGFloat x = widthToStartOfSelectedIndex + ((widthToEndOfSelectedSegment - widthToStartOfSelectedIndex) / 2) - (self.selectionIndicatorHeight/2);
return CGRectMake(x - (self.selectionIndicatorHeight / 2), indicatorYOffset, self.selectionIndicatorHeight * 2, self.selectionIndicatorHeight);
} else {
if (self.selectionStyle == HMSegmentedControlSelectionStyleTextWidthStripe &&
sectionWidth <= self.segmentWidth &&
self.segmentWidthStyle != HMSegmentedControlSegmentWidthStyleDynamic) {
CGFloat widthToEndOfSelectedSegment = (self.segmentWidth * self.selectedSegmentIndex) + self.segmentWidth;
CGFloat widthToStartOfSelectedIndex = (self.segmentWidth * self.selectedSegmentIndex);
CGFloat x = ((widthToEndOfSelectedSegment - widthToStartOfSelectedIndex) / 2) + (widthToStartOfSelectedIndex - sectionWidth / 2);
return CGRectMake(x + self.selectionIndicatorEdgeInsets.left, indicatorYOffset, sectionWidth - self.selectionIndicatorEdgeInsets.right, self.selectionIndicatorHeight);
} else {
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
CGFloat selectedSegmentOffset = 0.0f;
NSInteger i = 0;
for (NSNumber *width in self.segmentWidthsArray) {
if (self.selectedSegmentIndex == i)
break;
selectedSegmentOffset = selectedSegmentOffset + [width floatValue];
i++;
}
return CGRectMake(selectedSegmentOffset + self.selectionIndicatorEdgeInsets.left, indicatorYOffset, [[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue] - self.selectionIndicatorEdgeInsets.right, self.selectionIndicatorHeight + self.selectionIndicatorEdgeInsets.bottom);
}
return CGRectMake((self.segmentWidth + self.selectionIndicatorEdgeInsets.left) * self.selectedSegmentIndex, indicatorYOffset, self.segmentWidth - self.selectionIndicatorEdgeInsets.right, self.selectionIndicatorHeight);
}
}
}
/**
根據寬度類型
@return rect
*/
- (CGRect)frameForFillerSelectionIndicator {
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
CGFloat selectedSegmentOffset = 0.0f;
NSInteger i = 0;
for (NSNumber *width in self.segmentWidthsArray) {
if (self.selectedSegmentIndex == i) {
break;
}
selectedSegmentOffset = selectedSegmentOffset + [width floatValue];
i++;
}
return CGRectMake(selectedSegmentOffset, 0, [[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue], CGRectGetHeight(self.frame));
}
return CGRectMake(self.segmentWidth * self.selectedSegmentIndex, 0, self.segmentWidth, CGRectGetHeight(self.frame));
}
/**
更新rect
*/
- (void)updateSegmentsRects {
self.scrollView.contentInset = UIEdgeInsetsZero;
self.scrollView.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
if ([self sectionCount] > 0) {
self.segmentWidth = self.frame.size.width / [self sectionCount];
}
if (self.type == HMSegmentedControlTypeText && self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
[self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
CGFloat stringWidth = [self measureTitleAtIndex:idx].width + self.segmentEdgeInset.left + self.segmentEdgeInset.right;
self.segmentWidth = MAX(stringWidth, self.segmentWidth);
}];
} else if (self.type == HMSegmentedControlTypeText && self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
NSMutableArray *mutableSegmentWidths = [NSMutableArray array];
[self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
CGFloat stringWidth = [self measureTitleAtIndex:idx].width + self.segmentEdgeInset.left + self.segmentEdgeInset.right;
[mutableSegmentWidths addObject:[NSNumber numberWithFloat:stringWidth]];
}];
self.segmentWidthsArray = [mutableSegmentWidths copy];
} else if (self.type == HMSegmentedControlTypeImages) {
for (UIImage *sectionImage in self.sectionImages) {
CGFloat imageWidth = sectionImage.size.width + self.segmentEdgeInset.left + self.segmentEdgeInset.right;
self.segmentWidth = MAX(imageWidth, self.segmentWidth);
}
} else if (self.type == HMSegmentedControlTypeTextImages && self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed){
//lets just use the title.. we will assume it is wider then images...
[self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
CGFloat stringWidth = [self measureTitleAtIndex:idx].width + self.segmentEdgeInset.left + self.segmentEdgeInset.right;
self.segmentWidth = MAX(stringWidth, self.segmentWidth);
}];
} else if (self.type == HMSegmentedControlTypeTextImages && self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
NSMutableArray *mutableSegmentWidths = [NSMutableArray array];
int i = 0;
[self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
CGFloat stringWidth = [self measureTitleAtIndex:idx].width + self.segmentEdgeInset.right;
UIImage *sectionImage = [self.sectionImages objectAtIndex:i];
CGFloat imageWidth = sectionImage.size.width + self.segmentEdgeInset.left;
CGFloat combinedWidth = MAX(imageWidth, stringWidth);
[mutableSegmentWidths addObject:[NSNumber numberWithFloat:combinedWidth]];
}];
self.segmentWidthsArray = [mutableSegmentWidths copy];
}
self.scrollView.scrollEnabled = self.isUserDraggable;
self.scrollView.contentSize = CGSizeMake([self totalSegmentedControlWidth], self.frame.size.height);
}
/**
section的個數
@return 個數
*/
- (NSUInteger)sectionCount {
if (self.type == HMSegmentedControlTypeText) {
return self.sectionTitles.count;
} else if (self.type == HMSegmentedControlTypeImages ||
self.type == HMSegmentedControlTypeTextImages) {
return self.sectionImages.count;
}
return 0;
}
/**
重寫view的時候可能用到方法
@param newSuperview 新view
*/
- (void)willMoveToSuperview:(UIView *)newSuperview {
// Control is being removed
if (newSuperview == nil)
return;
if (self.sectionTitles || self.sectionImages) {
[self updateSegmentsRects];
}
}
#pragma mark - Touch
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self];
CGRect enlargeRect = CGRectMake(self.bounds.origin.x - self.enlargeEdgeInset.left,
self.bounds.origin.y - self.enlargeEdgeInset.top,
self.bounds.size.width + self.enlargeEdgeInset.left + self.enlargeEdgeInset.right,
self.bounds.size.height + self.enlargeEdgeInset.top + self.enlargeEdgeInset.bottom);
if (CGRectContainsPoint(enlargeRect, touchLocation)) {
NSInteger segment = 0;
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
segment = (touchLocation.x + self.scrollView.contentOffset.x) / self.segmentWidth;
} else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
// To know which segment the user touched, we need to loop over the widths and substract it from the x position.
CGFloat widthLeft = (touchLocation.x + self.scrollView.contentOffset.x);
for (NSNumber *width in self.segmentWidthsArray) {
widthLeft = widthLeft - [width floatValue];
// When we don't have any width left to substract, we have the segment index.
if (widthLeft <= 0)
break;
segment++;
}
}
NSUInteger sectionsCount = 0;
if (self.type == HMSegmentedControlTypeImages) {
sectionsCount = [self.sectionImages count];
} else if (self.type == HMSegmentedControlTypeTextImages || self.type == HMSegmentedControlTypeText) {
sectionsCount = [self.sectionTitles count];
}
if (segment != self.selectedSegmentIndex && segment < sectionsCount) {
// Check if we have to do anything with the touch event
if (self.isTouchEnabled)
[self setSelectedSegmentIndex:segment animated:self.shouldAnimateUserSelection notify:YES];
}
}
}
#pragma mark - Scrolling
/**
可以滾動的范圍width
@return float
*/
- (CGFloat)totalSegmentedControlWidth {
if (self.type == HMSegmentedControlTypeText && self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
// 因為每個寬度一樣所以返回文字個數*segment寬度
return self.sectionTitles.count * self.segmentWidth;
} else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
// 返回所有文字寬度的和
return [[self.segmentWidthsArray valueForKeyPath:@"@sum.self"] floatValue];
} else {
return self.sectionImages.count * self.segmentWidth;
}
}
/**
滾動到選中的segment
@param animated 動畫
*/
- (void)scrollToSelectedSegmentIndex:(BOOL)animated {
CGRect rectForSelectedIndex = CGRectZero;
CGFloat selectedSegmentOffset = 0;
if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
rectForSelectedIndex = CGRectMake(self.segmentWidth * self.selectedSegmentIndex,
0,
self.segmentWidth,
self.frame.size.height);
selectedSegmentOffset = (CGRectGetWidth(self.frame) / 2) - (self.segmentWidth / 2);
} else {
NSInteger i = 0;
CGFloat offsetter = 0;
for (NSNumber *width in self.segmentWidthsArray) {
if (self.selectedSegmentIndex == i)
break;
offsetter = offsetter + [width floatValue];
i++;
}
rectForSelectedIndex = CGRectMake(offsetter,
0,
[[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue],
self.frame.size.height);
selectedSegmentOffset = (CGRectGetWidth(self.frame) / 2) - ([[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue] / 2);
}
CGRect rectToScrollTo = rectForSelectedIndex;
rectToScrollTo.origin.x -= selectedSegmentOffset;
rectToScrollTo.size.width += selectedSegmentOffset * 2;
[self.scrollView scrollRectToVisible:rectToScrollTo animated:animated];
}
#pragma mark - Index Change
- (void)setSelectedSegmentIndex:(NSInteger)index {
[self setSelectedSegmentIndex:index animated:NO notify:NO];
}
- (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated {
[self setSelectedSegmentIndex:index animated:animated notify:NO];
}
/**
設置選中的segment的位置
@param index 位置
@param animated 動畫
@param notify 是否回調
*/
- (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated notify:(BOOL)notify {
_selectedSegmentIndex = index;
[self setNeedsDisplay];
if (index == HMSegmentedControlNoSegment) {
// 當類型為無的時候移除 指示器的layer
[self.selectionIndicatorArrowLayer removeFromSuperlayer];
[self.selectionIndicatorStripLayer removeFromSuperlayer];
[self.selectionIndicatorBoxLayer removeFromSuperlayer];
} else {
[self scrollToSelectedSegmentIndex:animated];
if (animated) {
// If the selected segment layer is not added to the super layer, that means no
// index is currently selected, so add the layer then move it to the new
// segment index without animating.
if(self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
if ([self.selectionIndicatorArrowLayer superlayer] == nil) {
[self.scrollView.layer addSublayer:self.selectionIndicatorArrowLayer];
[self setSelectedSegmentIndex:index animated:NO notify:YES];
return;
}
}
else {
if ([self.selectionIndicatorStripLayer superlayer] == nil) {
[self.scrollView.layer addSublayer:self.selectionIndicatorStripLayer];
if (self.selectionStyle == HMSegmentedControlSelectionStyleBox && [self.selectionIndicatorBoxLayer superlayer] == nil)
[self.scrollView.layer insertSublayer:self.selectionIndicatorBoxLayer atIndex:0];
[self setSelectedSegmentIndex:index animated:NO notify:YES];
return;
}
}
if (notify)
[self notifyForSegmentChangeToIndex:index];
// Restore CALayer animations
// 恢復layer的動畫
self.selectionIndicatorArrowLayer.actions = nil;
self.selectionIndicatorStripLayer.actions = nil;
self.selectionIndicatorBoxLayer.actions = nil;
// Animate to new position
//移動到新的位置
[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];
} else {
// Disable CALayer animations
NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"position", [NSNull null], @"bounds", nil];
self.selectionIndicatorArrowLayer.actions = newActions;
[self setArrowFrame];
self.selectionIndicatorStripLayer.actions = newActions;
self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
self.selectionIndicatorBoxLayer.actions = newActions;
self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
if (notify)
[self notifyForSegmentChangeToIndex:index];
}
}
}
/**
回調與觸發UIControlEventValueChanged的通知
@param index index
*/
- (void)notifyForSegmentChangeToIndex:(NSInteger)index {
if (self.superview)
[self sendActionsForControlEvents:UIControlEventValueChanged];
if (self.indexChangeBlock)
self.indexChangeBlock(index);
}
#pragma mark - Styling Support
/**
title富文本
@return 字典
*/
- (NSDictionary *)resultingTitleTextAttributes {
//默認的富文本
NSDictionary *defaults = @{
NSFontAttributeName : [UIFont systemFontOfSize:19.0f],
NSForegroundColorAttributeName : [UIColor blackColor],
};
NSMutableDictionary *resultingAttrs = [NSMutableDictionary dictionaryWithDictionary:defaults];
if (self.titleTextAttributes) {
//拼接兩個字典
[resultingAttrs addEntriesFromDictionary:self.titleTextAttributes];
}
return [resultingAttrs copy];
}
/**
返回選中文字的富文本
@return 字典
*/
- (NSDictionary *)resultingSelectedTitleTextAttributes {
NSMutableDictionary *resultingAttrs = [NSMutableDictionary dictionaryWithDictionary:[self resultingTitleTextAttributes]];
if (self.selectedTitleTextAttributes) {
[resultingAttrs addEntriesFromDictionary:self.selectedTitleTextAttributes];
}
return [resultingAttrs copy];
}
@end