react-native-navigation 7.21.0 → 7.22.0-snapshot.1649

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/ReactNativeNavigation.podspec +1 -0
  2. package/lib/android/app/src/main/java/com/reactnativenavigation/NavigationActivity.java +1 -2
  3. package/lib/android/app/src/main/java/com/reactnativenavigation/options/BackButton.java +5 -4
  4. package/lib/android/app/src/main/java/com/reactnativenavigation/options/ElementTransitionOptions.kt +0 -1
  5. package/lib/android/app/src/main/java/com/reactnativenavigation/options/HardwareBackButtonOptions.kt +2 -5
  6. package/lib/android/app/src/main/java/com/reactnativenavigation/options/LayoutFactory.java +120 -120
  7. package/lib/android/app/src/main/java/com/reactnativenavigation/options/ValueAnimationOptions.kt +3 -3
  8. package/lib/android/app/src/main/java/com/reactnativenavigation/options/interpolators/SpringInterpolator.kt +16 -16
  9. package/lib/android/app/src/main/java/com/reactnativenavigation/options/parsers/TypefaceLoader.kt +0 -1
  10. package/lib/android/app/src/main/java/com/reactnativenavigation/react/CommandListenerAdapter.java +0 -2
  11. package/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java +7 -6
  12. package/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.kt +27 -0
  13. package/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactInitializer.java +50 -50
  14. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/Events.kt +34 -0
  15. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalContentLayout.kt +81 -0
  16. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalFrameLayout.kt +19 -0
  17. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalHostLayout.kt +78 -0
  18. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalLayoutController.kt +51 -0
  19. package/lib/android/app/src/main/java/com/reactnativenavigation/react/modal/ModalViewManager.kt +131 -0
  20. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/CoordinatorLayoutUtils.java +1 -1
  21. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/OutlineProvider.kt +0 -1
  22. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java +1 -1
  23. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/RenderChecker.java +1 -1
  24. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/StatusBarUtils.java +0 -2
  25. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/UiUtils.java +5 -6
  26. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewParent.kt +0 -3
  27. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java +4 -5
  28. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenter.java +6 -8
  29. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsAnimator.kt +0 -1
  30. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +3 -3
  31. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/BottomTabsAttacher.java +1 -1
  32. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachMode.java +3 -3
  33. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/OnSwitchToTab.java +2 -2
  34. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildController.java +1 -1
  35. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistry.java +5 -5
  36. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentPresenterBase.java +3 -0
  37. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +1 -1
  38. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenter.java +6 -6
  39. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/modal/ModalStack.java +18 -18
  40. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/navigator/Navigator.java +12 -12
  41. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/parent/ParentController.java +22 -22
  42. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuController.java +16 -16
  43. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuPresenter.java +4 -4
  44. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/FabPresenter.java +8 -8
  45. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/IdStack.java +14 -14
  46. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackController.java +29 -29
  47. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerBuilder.java +3 -3
  48. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenter.java +29 -28
  49. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarAnimator.kt +1 -0
  50. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarBackgroundViewController.java +0 -1
  51. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/TopBarController.kt +1 -1
  52. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/BackButtonHelper.java +2 -2
  53. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/ButtonPresenter.kt +1 -1
  54. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/ButtonSpan.kt +0 -1
  55. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/topbar/button/IconResolver.java +0 -1
  56. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsAdapter.java +5 -4
  57. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java +8 -8
  58. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/BottomTabsContainer.kt +1 -4
  59. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/BottomTabsLayout.java +0 -1
  60. package/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/PropertyAnimatorCreator.kt +2 -0
  61. package/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ReactImageBoundsAnimator.kt +0 -1
  62. package/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ReactImageMatrixAnimator.kt +2 -2
  63. package/lib/android/app/src/main/java/com/reactnativenavigation/views/element/animators/ReactViewRotationAnimator.kt +0 -5
  64. package/lib/android/app/src/main/java/com/reactnativenavigation/views/toptabs/TopTabsLayoutCreator.java +2 -2
  65. package/lib/android/app/src/main/java/com/reactnativenavigation/views/toptabs/TopTabsViewPager.java +6 -6
  66. package/lib/android/app/src/reactNative63/java/com/reactnativenavigation/react/NavigationReactNativeHost.java +0 -1
  67. package/lib/android/app/src/test/java/com/reactnativenavigation/BaseTest.java +23 -28
  68. package/lib/android/app/src/test/java/com/reactnativenavigation/TestUtils.java +4 -2
  69. package/lib/android/app/src/test/java/com/reactnativenavigation/mocks/TestComponentLayout.java +3 -1
  70. package/lib/android/app/src/test/java/com/reactnativenavigation/options/OptionsTest.java +9 -1
  71. package/lib/android/app/src/test/java/com/reactnativenavigation/options/TopBarButtonsTest.kt +70 -0
  72. package/lib/android/app/src/test/java/com/reactnativenavigation/options/parsers/ColorParseTest.java +0 -3
  73. package/lib/android/app/src/test/java/com/reactnativenavigation/presentation/RenderCheckerTest.java +6 -6
  74. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabPresenterTest.java +3 -4
  75. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsAttacherTest.java +1 -1
  76. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsControllerTest.java +13 -15
  77. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/bottomtabs/attacher/modes/AttachModeTest.java +5 -5
  78. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllerTest.java +2 -2
  79. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/child/ChildControllersRegistryTest.java +2 -2
  80. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalPresenterTest.java +4 -4
  81. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/modal/ModalStackTest.java +10 -10
  82. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/NavigatorTest.java +25 -26
  83. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/navigator/RootPresenterTest.kt +2 -2
  84. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/parent/ParentControllerTest.java +15 -15
  85. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/sidemenu/SideMenuControllerTest.java +11 -11
  86. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/BackButtonHelperTest.java +2 -2
  87. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimatorTest.kt +0 -4
  88. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackControllerTest.kt +15 -15
  89. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/StackPresenterTest.kt +17 -17
  90. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/stack/TopBarControllerTest.kt +3 -3
  91. package/lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsViewControllerTest.java +9 -9
  92. package/lib/dist/Navigation.d.ts +1 -1
  93. package/lib/dist/Navigation.js +2 -2
  94. package/lib/dist/NavigationDelegate.d.ts +1 -1
  95. package/lib/dist/NavigationDelegate.js +2 -2
  96. package/lib/dist/adapters/TouchablePreview.js +1 -0
  97. package/lib/dist/commands/Commands.d.ts +1 -1
  98. package/lib/dist/commands/Commands.js +2 -2
  99. package/lib/dist/commands/OptionsProcessor.js +12 -6
  100. package/lib/dist/components/ComponentWrapper.d.ts +1 -1
  101. package/lib/dist/components/ComponentWrapper.js +2 -2
  102. package/lib/dist/components/Modal.d.ts +20 -0
  103. package/lib/dist/components/Modal.js +93 -0
  104. package/lib/dist/components/Store.d.ts +1 -1
  105. package/lib/dist/components/Store.js +2 -2
  106. package/lib/dist/index.d.ts +1 -0
  107. package/lib/dist/index.js +1 -0
  108. package/lib/dist/interfaces/Options.d.ts +15 -0
  109. package/lib/ios/BottomTabPresenter.h +4 -1
  110. package/lib/ios/BottomTabPresenter.m +11 -3
  111. package/lib/ios/BottomTabPresenterCreator.m +11 -4
  112. package/lib/ios/BottomTabsAppearancePresenter.m +29 -4
  113. package/lib/ios/RNNBackButtonOptions.h +1 -0
  114. package/lib/ios/RNNBackButtonOptions.m +4 -1
  115. package/lib/ios/RNNBottomTabOptions.h +2 -0
  116. package/lib/ios/RNNBottomTabOptions.m +7 -1
  117. package/lib/ios/RNNBottomTabsController.m +5 -0
  118. package/lib/ios/RNNDotIndicatorPresenter.m +12 -6
  119. package/lib/ios/RNNSegmentedControl.h +1 -1
  120. package/lib/ios/RNNTabBarItemCreator.h +4 -4
  121. package/lib/ios/RNNTabBarItemCreator.m +17 -7
  122. package/lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj +8 -24
  123. package/lib/ios/TabBarItemAppearanceCreator.m +3 -3
  124. package/lib/ios/TabBarItemIOS15Creator.h +6 -0
  125. package/lib/ios/TabBarItemIOS15Creator.m +37 -0
  126. package/lib/ios/TopBarPresenter.m +13 -3
  127. package/lib/ios/UIViewController+RNNOptions.m +7 -0
  128. package/lib/src/Navigation.ts +2 -2
  129. package/lib/src/NavigationDelegate.ts +2 -2
  130. package/lib/src/adapters/TouchablePreview.tsx +1 -1
  131. package/lib/src/commands/Commands.ts +2 -2
  132. package/lib/src/commands/OptionsProcessor.ts +12 -7
  133. package/lib/src/components/ComponentWrapper.tsx +11 -8
  134. package/lib/src/components/Modal.tsx +109 -0
  135. package/lib/src/components/Store.ts +2 -2
  136. package/lib/src/index.ts +1 -1
  137. package/lib/src/interfaces/Options.ts +15 -0
  138. package/package.json +1 -1
  139. package/lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationPackage.java +0 -41
  140. package/lib/ios/BottomTabAppearancePresenter.h +0 -6
  141. package/lib/ios/BottomTabAppearancePresenter.m +0 -12
  142. package/lib/ios/HMSegmentedControl.h +0 -287
  143. package/lib/ios/HMSegmentedControl.m +0 -1063
@@ -1,1063 +0,0 @@
1
- //
2
- // HMSegmentedControl.m
3
- // HMSegmentedControl
4
- //
5
- // Created by Hesham Abd-Elmegid on 23/12/12.
6
- // Copyright (c) 2012-2015 Hesham Abd-Elmegid. All rights reserved.
7
- //
8
-
9
- #import "HMSegmentedControl.h"
10
- #import <QuartzCore/QuartzCore.h>
11
- #import <math.h>
12
-
13
- @interface HMScrollView : UIScrollView
14
- @end
15
-
16
- @interface HMSegmentedControl ()
17
-
18
- @property(nonatomic, strong) CALayer *selectionIndicatorStripLayer;
19
- @property(nonatomic, strong) CALayer *selectionIndicatorBoxLayer;
20
- @property(nonatomic, strong) CALayer *selectionIndicatorArrowLayer;
21
- @property(nonatomic, readwrite) CGFloat segmentWidth;
22
- @property(nonatomic, readwrite) NSArray<NSNumber *> *segmentWidthsArray;
23
- @property(nonatomic, strong) HMScrollView *scrollView;
24
-
25
- @end
26
-
27
- @implementation HMScrollView
28
-
29
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
30
- if (!self.dragging) {
31
- [self.nextResponder touchesBegan:touches withEvent:event];
32
- } else {
33
- [super touchesBegan:touches withEvent:event];
34
- }
35
- }
36
-
37
- - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
38
- if (!self.dragging) {
39
- [self.nextResponder touchesMoved:touches withEvent:event];
40
- } else {
41
- [super touchesMoved:touches withEvent:event];
42
- }
43
- }
44
-
45
- - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
46
- if (!self.dragging) {
47
- [self.nextResponder touchesEnded:touches withEvent:event];
48
- } else {
49
- [super touchesEnded:touches withEvent:event];
50
- }
51
- }
52
-
53
- @end
54
-
55
- @implementation HMSegmentedControl
56
-
57
- - (id)initWithCoder:(NSCoder *)aDecoder {
58
- self = [super initWithCoder:aDecoder];
59
- if (self) {
60
- [self commonInit];
61
- }
62
- return self;
63
- }
64
-
65
- - (id)initWithFrame:(CGRect)frame {
66
- self = [super initWithFrame:frame];
67
-
68
- if (self) {
69
- [self commonInit];
70
- }
71
-
72
- return self;
73
- }
74
-
75
- - (id)initWithSectionTitles:(NSArray<NSString *> *)sectiontitles {
76
- self = [super initWithFrame:CGRectZero];
77
-
78
- if (self) {
79
- [self commonInit];
80
- self.sectionTitles = sectiontitles;
81
- self.type = HMSegmentedControlTypeText;
82
- }
83
-
84
- return self;
85
- }
86
-
87
- - (id)initWithSectionImages:(NSArray<UIImage *> *)sectionImages
88
- sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages {
89
- self = [super initWithFrame:CGRectZero];
90
-
91
- if (self) {
92
- [self commonInit];
93
- self.sectionImages = sectionImages;
94
- self.sectionSelectedImages = sectionSelectedImages;
95
- self.type = HMSegmentedControlTypeImages;
96
- }
97
-
98
- return self;
99
- }
100
-
101
- - (instancetype)initWithSectionImages:(NSArray<UIImage *> *)sectionImages
102
- sectionSelectedImages:(NSArray<UIImage *> *)sectionSelectedImages
103
- titlesForSections:(NSArray<NSString *> *)sectiontitles {
104
- self = [super initWithFrame:CGRectZero];
105
-
106
- if (self) {
107
- [self commonInit];
108
-
109
- if (sectionImages.count != sectiontitles.count) {
110
- [NSException raise:NSRangeException
111
- format:@"***%s: Images bounds (%ld) Don't match Title bounds "
112
- @"(%ld)",
113
- sel_getName(_cmd), (unsigned long)sectionImages.count,
114
- (unsigned long)sectiontitles.count];
115
- }
116
-
117
- self.sectionImages = sectionImages;
118
- self.sectionSelectedImages = sectionSelectedImages;
119
- self.sectionTitles = sectiontitles;
120
- self.type = HMSegmentedControlTypeTextImages;
121
- }
122
-
123
- return self;
124
- }
125
-
126
- - (void)awakeFromNib {
127
- [super awakeFromNib];
128
-
129
- self.segmentWidth = 0.0f;
130
- }
131
-
132
- - (void)commonInit {
133
- self.scrollView = [[HMScrollView alloc] init];
134
- self.scrollView.scrollsToTop = NO;
135
- self.scrollView.showsVerticalScrollIndicator = NO;
136
- self.scrollView.showsHorizontalScrollIndicator = NO;
137
- [self addSubview:self.scrollView];
138
-
139
- _backgroundColor = [UIColor whiteColor];
140
- self.opaque = NO;
141
- _selectionIndicatorColor = [UIColor colorWithRed:52.0f / 255.0f
142
- green:181.0f / 255.0f
143
- blue:229.0f / 255.0f
144
- alpha:1.0f];
145
- _selectionIndicatorBoxColor = _selectionIndicatorColor;
146
-
147
- self.selectedSegmentIndex = 0;
148
- self.segmentEdgeInset = UIEdgeInsetsMake(0, 5, 0, 5);
149
- self.selectionIndicatorHeight = 5.0f;
150
- self.selectionIndicatorEdgeInsets = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
151
- self.selectionStyle = HMSegmentedControlSelectionStyleTextWidthStripe;
152
- self.selectionIndicatorLocation = HMSegmentedControlSelectionIndicatorLocationUp;
153
- self.segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;
154
- self.userDraggable = YES;
155
- self.touchEnabled = YES;
156
- self.verticalDividerEnabled = NO;
157
- self.type = HMSegmentedControlTypeText;
158
- self.verticalDividerWidth = 1.0f;
159
- _verticalDividerColor = [UIColor blackColor];
160
- self.borderColor = [UIColor blackColor];
161
- self.borderWidth = 1.0f;
162
-
163
- self.shouldAnimateUserSelection = YES;
164
-
165
- self.selectionIndicatorArrowLayer = [CALayer layer];
166
- self.selectionIndicatorStripLayer = [CALayer layer];
167
- self.selectionIndicatorBoxLayer = [CALayer layer];
168
- self.selectionIndicatorBoxLayer.opacity = self.selectionIndicatorBoxOpacity;
169
- self.selectionIndicatorBoxLayer.borderWidth = 1.0f;
170
- self.selectionIndicatorBoxOpacity = 0.2;
171
-
172
- self.contentMode = UIViewContentModeRedraw;
173
- }
174
-
175
- - (void)layoutSubviews {
176
- [super layoutSubviews];
177
-
178
- [self updateSegmentsRects];
179
- }
180
-
181
- - (void)setFrame:(CGRect)frame {
182
- [super setFrame:frame];
183
-
184
- [self updateSegmentsRects];
185
- }
186
-
187
- - (void)setSectionTitles:(NSArray<NSString *> *)sectionTitles {
188
- _sectionTitles = sectionTitles;
189
-
190
- [self setNeedsLayout];
191
- [self setNeedsDisplay];
192
- }
193
-
194
- - (void)setSectionImages:(NSArray<UIImage *> *)sectionImages {
195
- _sectionImages = sectionImages;
196
-
197
- [self setNeedsLayout];
198
- [self setNeedsDisplay];
199
- }
200
-
201
- - (void)setSelectionIndicatorLocation:
202
- (HMSegmentedControlSelectionIndicatorLocation)selectionIndicatorLocation {
203
- _selectionIndicatorLocation = selectionIndicatorLocation;
204
-
205
- if (selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationNone) {
206
- self.selectionIndicatorHeight = 0.0f;
207
- }
208
- }
209
-
210
- - (void)setSelectionIndicatorBoxOpacity:(CGFloat)selectionIndicatorBoxOpacity {
211
- _selectionIndicatorBoxOpacity = selectionIndicatorBoxOpacity;
212
-
213
- self.selectionIndicatorBoxLayer.opacity = _selectionIndicatorBoxOpacity;
214
- }
215
-
216
- - (void)setSegmentWidthStyle:(HMSegmentedControlSegmentWidthStyle)segmentWidthStyle {
217
- // Force HMSegmentedControlSegmentWidthStyleFixed when type is
218
- // HMSegmentedControlTypeImages.
219
- if (self.type == HMSegmentedControlTypeImages) {
220
- _segmentWidthStyle = HMSegmentedControlSegmentWidthStyleFixed;
221
- } else {
222
- _segmentWidthStyle = segmentWidthStyle;
223
- }
224
- }
225
-
226
- - (void)setBorderType:(HMSegmentedControlBorderType)borderType {
227
- _borderType = borderType;
228
- [self setNeedsDisplay];
229
- }
230
-
231
- #pragma mark - Drawing
232
-
233
- - (CGSize)measureTitleAtIndex:(NSUInteger)index {
234
- if (index >= self.sectionTitles.count) {
235
- return CGSizeZero;
236
- }
237
-
238
- id title = self.sectionTitles[index];
239
- CGSize size = CGSizeZero;
240
- BOOL selected = (index == self.selectedSegmentIndex) ? YES : NO;
241
- if ([title isKindOfClass:[NSString class]] && !self.titleFormatter) {
242
- NSDictionary *titleAttrs = selected ? [self resultingSelectedTitleTextAttributes]
243
- : [self resultingTitleTextAttributes];
244
- size = [(NSString *)title sizeWithAttributes:titleAttrs];
245
- } else if ([title isKindOfClass:[NSString class]] && self.titleFormatter) {
246
- size = [self.titleFormatter(self, title, index, selected) size];
247
- } else if ([title isKindOfClass:[NSAttributedString class]]) {
248
- size = [(NSAttributedString *)title size];
249
- } else {
250
- NSAssert(title == nil, @"Unexpected type of segment title: %@", [title class]);
251
- size = CGSizeZero;
252
- }
253
- return CGRectIntegral((CGRect){CGPointZero, size}).size;
254
- }
255
-
256
- - (NSAttributedString *)attributedTitleAtIndex:(NSUInteger)index {
257
- id title = self.sectionTitles[index];
258
- BOOL selected = (index == self.selectedSegmentIndex) ? YES : NO;
259
-
260
- if ([title isKindOfClass:[NSAttributedString class]]) {
261
- return (NSAttributedString *)title;
262
- } else if (!self.titleFormatter) {
263
- NSDictionary *titleAttrs = selected ? [self resultingSelectedTitleTextAttributes]
264
- : [self resultingTitleTextAttributes];
265
-
266
- // the color should be cast to CGColor in order to avoid invalid context
267
- // on iOS7
268
- UIColor *titleColor = titleAttrs[NSForegroundColorAttributeName];
269
-
270
- if (titleColor) {
271
- NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:titleAttrs];
272
-
273
- dict[NSForegroundColorAttributeName] = (id)titleColor.CGColor;
274
-
275
- titleAttrs = [NSDictionary dictionaryWithDictionary:dict];
276
- }
277
-
278
- return [[NSAttributedString alloc] initWithString:(NSString *)title attributes:titleAttrs];
279
- } else {
280
- return self.titleFormatter(self, title, index, selected);
281
- }
282
- }
283
-
284
- - (void)drawRect:(CGRect)rect {
285
- [self.backgroundColor setFill];
286
- UIRectFill([self bounds]);
287
-
288
- self.selectionIndicatorArrowLayer.backgroundColor = self.selectionIndicatorColor.CGColor;
289
-
290
- self.selectionIndicatorStripLayer.backgroundColor = self.selectionIndicatorColor.CGColor;
291
-
292
- self.selectionIndicatorBoxLayer.backgroundColor = self.selectionIndicatorBoxColor.CGColor;
293
- self.selectionIndicatorBoxLayer.borderColor = self.selectionIndicatorBoxColor.CGColor;
294
-
295
- // Remove all sublayers to avoid drawing images over existing ones
296
- self.scrollView.layer.sublayers = nil;
297
-
298
- CGRect oldRect = rect;
299
-
300
- if (self.type == HMSegmentedControlTypeText) {
301
- [self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx,
302
- BOOL *stop) {
303
- CGFloat stringWidth = 0;
304
- CGFloat stringHeight = 0;
305
- CGSize size = [self measureTitleAtIndex:idx];
306
- stringWidth = size.width;
307
- stringHeight = size.height;
308
- CGRect rectDiv = CGRectZero;
309
- CGRect fullRect = CGRectZero;
310
-
311
- // Text inside the CATextLayer will appear blurry unless the rect
312
- // values are rounded
313
- BOOL locationUp =
314
- (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp);
315
- BOOL selectionStyleNotBox = (self.selectionStyle != HMSegmentedControlSelectionStyleBox);
316
-
317
- CGFloat y = roundf(
318
- (CGRectGetHeight(self.frame) - selectionStyleNotBox * self.selectionIndicatorHeight) /
319
- 2 -
320
- stringHeight / 2 + self.selectionIndicatorHeight * locationUp);
321
- CGRect rect;
322
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
323
- rect = CGRectMake((self.segmentWidth * idx) + (self.segmentWidth - stringWidth) / 2,
324
- y, stringWidth, stringHeight);
325
- rectDiv = CGRectMake((self.segmentWidth * idx) - (self.verticalDividerWidth / 2),
326
- self.selectionIndicatorHeight * 2, self.verticalDividerWidth,
327
- self.frame.size.height - (self.selectionIndicatorHeight * 4));
328
- fullRect =
329
- CGRectMake(self.segmentWidth * idx, 0, self.segmentWidth, oldRect.size.height);
330
- } else {
331
- // When we are drawing dynamic widths, we need to loop the widths
332
- // array to calculate the xOffset
333
- CGFloat xOffset = 0;
334
- NSInteger i = 0;
335
- for (NSNumber *width in self.segmentWidthsArray) {
336
- if (idx == i)
337
- break;
338
- xOffset = xOffset + [width floatValue];
339
- i++;
340
- }
341
-
342
- CGFloat widthForIndex = [[self.segmentWidthsArray objectAtIndex:idx] floatValue];
343
- rect = CGRectMake(xOffset, y, widthForIndex, stringHeight);
344
- fullRect = CGRectMake(self.segmentWidth * idx, 0, widthForIndex, oldRect.size.height);
345
- rectDiv = CGRectMake(xOffset - (self.verticalDividerWidth / 2),
346
- self.selectionIndicatorHeight * 2, self.verticalDividerWidth,
347
- self.frame.size.height - (self.selectionIndicatorHeight * 4));
348
- }
349
-
350
- // Fix rect position/size to avoid blurry labels
351
- rect = CGRectMake(ceilf(rect.origin.x), ceilf(rect.origin.y), ceilf(rect.size.width),
352
- ceilf(rect.size.height));
353
-
354
- CATextLayer *titleLayer = [CATextLayer layer];
355
- titleLayer.frame = rect;
356
- titleLayer.alignmentMode = kCAAlignmentCenter;
357
- if ([UIDevice currentDevice].systemVersion.floatValue < 10.0) {
358
- titleLayer.truncationMode = kCATruncationEnd;
359
- }
360
- titleLayer.string = [self attributedTitleAtIndex:idx];
361
- titleLayer.contentsScale = [[UIScreen mainScreen] scale];
362
-
363
- [self.scrollView.layer addSublayer:titleLayer];
364
-
365
- // Vertical Divider
366
- if (self.isVerticalDividerEnabled && idx > 0) {
367
- CALayer *verticalDividerLayer = [CALayer layer];
368
- verticalDividerLayer.frame = rectDiv;
369
- verticalDividerLayer.backgroundColor = self.verticalDividerColor.CGColor;
370
-
371
- [self.scrollView.layer addSublayer:verticalDividerLayer];
372
- }
373
-
374
- [self addBackgroundAndBorderLayerWithRect:fullRect];
375
- }];
376
- } else if (self.type == HMSegmentedControlTypeImages) {
377
- [self.sectionImages enumerateObjectsUsingBlock:^(id iconImage, NSUInteger idx, BOOL *stop) {
378
- UIImage *icon = iconImage;
379
- CGFloat imageWidth = icon.size.width;
380
- CGFloat imageHeight = icon.size.height;
381
- CGFloat y =
382
- roundf(CGRectGetHeight(self.frame) - self.selectionIndicatorHeight) / 2 -
383
- imageHeight / 2 +
384
- ((self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp)
385
- ? self.selectionIndicatorHeight
386
- : 0);
387
- CGFloat x = self.segmentWidth * idx + (self.segmentWidth - imageWidth) / 2.0f;
388
- CGRect rect = CGRectMake(x, y, imageWidth, imageHeight);
389
-
390
- CALayer *imageLayer = [CALayer layer];
391
- imageLayer.frame = rect;
392
-
393
- if (self.selectedSegmentIndex == idx) {
394
- if (self.sectionSelectedImages) {
395
- UIImage *highlightIcon = [self.sectionSelectedImages objectAtIndex:idx];
396
- imageLayer.contents = (id)highlightIcon.CGImage;
397
- } else {
398
- imageLayer.contents = (id)icon.CGImage;
399
- }
400
- } else {
401
- imageLayer.contents = (id)icon.CGImage;
402
- }
403
-
404
- [self.scrollView.layer addSublayer:imageLayer];
405
- // Vertical Divider
406
- if (self.isVerticalDividerEnabled && idx > 0) {
407
- CALayer *verticalDividerLayer = [CALayer layer];
408
- verticalDividerLayer.frame =
409
- CGRectMake((self.segmentWidth * idx) - (self.verticalDividerWidth / 2),
410
- self.selectionIndicatorHeight * 2, self.verticalDividerWidth,
411
- self.frame.size.height - (self.selectionIndicatorHeight * 4));
412
- verticalDividerLayer.backgroundColor = self.verticalDividerColor.CGColor;
413
-
414
- [self.scrollView.layer addSublayer:verticalDividerLayer];
415
- }
416
-
417
- [self addBackgroundAndBorderLayerWithRect:rect];
418
- }];
419
- } else if (self.type == HMSegmentedControlTypeTextImages) {
420
- [self.sectionImages enumerateObjectsUsingBlock:^(id iconImage, NSUInteger idx, BOOL *stop) {
421
- UIImage *icon = iconImage;
422
- CGFloat imageWidth = icon.size.width;
423
- CGFloat imageHeight = icon.size.height;
424
-
425
- CGSize stringSize = [self measureTitleAtIndex:idx];
426
- CGFloat stringHeight = stringSize.height;
427
- CGFloat stringWidth = stringSize.width;
428
-
429
- CGFloat imageXOffset = self.segmentWidth * idx; // Start with edge inset
430
- CGFloat textXOffset = self.segmentWidth * idx;
431
- CGFloat imageYOffset =
432
- ceilf((self.frame.size.height - imageHeight) / 2.0); // Start in center
433
- CGFloat textYOffset = ceilf((self.frame.size.height - stringHeight) / 2.0);
434
-
435
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
436
- BOOL isImageInLineWidthText =
437
- self.imagePosition == HMSegmentedControlImagePositionLeftOfText ||
438
- self.imagePosition == HMSegmentedControlImagePositionRightOfText;
439
- if (isImageInLineWidthText) {
440
- CGFloat whitespace =
441
- self.segmentWidth - stringSize.width - imageWidth - self.textImageSpacing;
442
- if (self.imagePosition == HMSegmentedControlImagePositionLeftOfText) {
443
- imageXOffset += whitespace / 2.0;
444
- textXOffset = imageXOffset + imageWidth + self.textImageSpacing;
445
- } else {
446
- textXOffset += whitespace / 2.0;
447
- imageXOffset = textXOffset + stringWidth + self.textImageSpacing;
448
- }
449
- } else {
450
- imageXOffset = self.segmentWidth * idx +
451
- (self.segmentWidth - imageWidth) / 2.0f; // Start with edge inset
452
- textXOffset = self.segmentWidth * idx + (self.segmentWidth - stringWidth) / 2.0f;
453
-
454
- CGFloat whitespace = CGRectGetHeight(self.frame) - imageHeight - stringHeight -
455
- self.textImageSpacing;
456
- if (self.imagePosition == HMSegmentedControlImagePositionAboveText) {
457
- imageYOffset = ceilf(whitespace / 2.0);
458
- textYOffset = imageYOffset + imageHeight + self.textImageSpacing;
459
- } else if (self.imagePosition == HMSegmentedControlImagePositionBelowText) {
460
- textYOffset = ceilf(whitespace / 2.0);
461
- imageYOffset = textYOffset + stringHeight + self.textImageSpacing;
462
- }
463
- }
464
- } else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
465
- // When we are drawing dynamic widths, we need to loop the widths
466
- // array to calculate the xOffset
467
- CGFloat xOffset = 0;
468
- NSInteger i = 0;
469
-
470
- for (NSNumber *width in self.segmentWidthsArray) {
471
- if (idx == i) {
472
- break;
473
- }
474
-
475
- xOffset = xOffset + [width floatValue];
476
- i++;
477
- }
478
-
479
- BOOL isImageInLineWidthText =
480
- self.imagePosition == HMSegmentedControlImagePositionLeftOfText ||
481
- self.imagePosition == HMSegmentedControlImagePositionRightOfText;
482
- if (isImageInLineWidthText) {
483
- if (self.imagePosition == HMSegmentedControlImagePositionLeftOfText) {
484
- imageXOffset = xOffset;
485
- textXOffset = imageXOffset + imageWidth + self.textImageSpacing;
486
- } else {
487
- textXOffset = xOffset;
488
- imageXOffset = textXOffset + stringWidth + self.textImageSpacing;
489
- }
490
- } else {
491
- imageXOffset = xOffset + ([self.segmentWidthsArray[i] floatValue] - imageWidth) /
492
- 2.0f; // Start with edge inset
493
- textXOffset =
494
- xOffset + ([self.segmentWidthsArray[i] floatValue] - stringWidth) / 2.0f;
495
-
496
- CGFloat whitespace = CGRectGetHeight(self.frame) - imageHeight - stringHeight -
497
- self.textImageSpacing;
498
- if (self.imagePosition == HMSegmentedControlImagePositionAboveText) {
499
- imageYOffset = ceilf(whitespace / 2.0);
500
- textYOffset = imageYOffset + imageHeight + self.textImageSpacing;
501
- } else if (self.imagePosition == HMSegmentedControlImagePositionBelowText) {
502
- textYOffset = ceilf(whitespace / 2.0);
503
- imageYOffset = textYOffset + stringHeight + self.textImageSpacing;
504
- }
505
- }
506
- }
507
-
508
- CGRect imageRect = CGRectMake(imageXOffset, imageYOffset, imageWidth, imageHeight);
509
- CGRect textRect = CGRectMake(ceilf(textXOffset), ceilf(textYOffset), ceilf(stringWidth),
510
- ceilf(stringHeight));
511
-
512
- CATextLayer *titleLayer = [CATextLayer layer];
513
- titleLayer.frame = textRect;
514
- titleLayer.alignmentMode = kCAAlignmentCenter;
515
- titleLayer.string = [self attributedTitleAtIndex:idx];
516
- if ([UIDevice currentDevice].systemVersion.floatValue < 10.0) {
517
- titleLayer.truncationMode = kCATruncationEnd;
518
- }
519
- CALayer *imageLayer = [CALayer layer];
520
- imageLayer.frame = imageRect;
521
-
522
- if (self.selectedSegmentIndex == idx) {
523
- if (self.sectionSelectedImages) {
524
- UIImage *highlightIcon = [self.sectionSelectedImages objectAtIndex:idx];
525
- imageLayer.contents = (id)highlightIcon.CGImage;
526
- } else {
527
- imageLayer.contents = (id)icon.CGImage;
528
- }
529
- } else {
530
- imageLayer.contents = (id)icon.CGImage;
531
- }
532
-
533
- [self.scrollView.layer addSublayer:imageLayer];
534
- titleLayer.contentsScale = [[UIScreen mainScreen] scale];
535
- [self.scrollView.layer addSublayer:titleLayer];
536
-
537
- [self addBackgroundAndBorderLayerWithRect:imageRect];
538
- }];
539
- }
540
-
541
- // Add the selection indicators
542
- if (self.selectedSegmentIndex != HMSegmentedControlNoSegment) {
543
- if (self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
544
- if (!self.selectionIndicatorArrowLayer.superlayer) {
545
- [self setArrowFrame];
546
- [self.scrollView.layer addSublayer:self.selectionIndicatorArrowLayer];
547
- }
548
- } else {
549
- if (!self.selectionIndicatorStripLayer.superlayer) {
550
- self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
551
- [self.scrollView.layer addSublayer:self.selectionIndicatorStripLayer];
552
-
553
- if (self.selectionStyle == HMSegmentedControlSelectionStyleBox &&
554
- !self.selectionIndicatorBoxLayer.superlayer) {
555
- self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
556
- [self.scrollView.layer insertSublayer:self.selectionIndicatorBoxLayer
557
- atIndex:0];
558
- }
559
- }
560
- }
561
- }
562
- }
563
-
564
- - (void)addBackgroundAndBorderLayerWithRect:(CGRect)fullRect {
565
- // Background layer
566
- CALayer *backgroundLayer = [CALayer layer];
567
- backgroundLayer.frame = fullRect;
568
- [self.layer insertSublayer:backgroundLayer atIndex:0];
569
-
570
- // Border layer
571
- if (self.borderType & HMSegmentedControlBorderTypeTop) {
572
- CALayer *borderLayer = [CALayer layer];
573
- borderLayer.frame = CGRectMake(0, 0, fullRect.size.width, self.borderWidth);
574
- borderLayer.backgroundColor = self.borderColor.CGColor;
575
- [backgroundLayer addSublayer:borderLayer];
576
- }
577
- if (self.borderType & HMSegmentedControlBorderTypeLeft) {
578
- CALayer *borderLayer = [CALayer layer];
579
- borderLayer.frame = CGRectMake(0, 0, self.borderWidth, fullRect.size.height);
580
- borderLayer.backgroundColor = self.borderColor.CGColor;
581
- [backgroundLayer addSublayer:borderLayer];
582
- }
583
- if (self.borderType & HMSegmentedControlBorderTypeBottom) {
584
- CALayer *borderLayer = [CALayer layer];
585
- borderLayer.frame = CGRectMake(0, fullRect.size.height - self.borderWidth,
586
- fullRect.size.width, self.borderWidth);
587
- borderLayer.backgroundColor = self.borderColor.CGColor;
588
- [backgroundLayer addSublayer:borderLayer];
589
- }
590
- if (self.borderType & HMSegmentedControlBorderTypeRight) {
591
- CALayer *borderLayer = [CALayer layer];
592
- borderLayer.frame = CGRectMake(fullRect.size.width - self.borderWidth, 0, self.borderWidth,
593
- fullRect.size.height);
594
- borderLayer.backgroundColor = self.borderColor.CGColor;
595
- [backgroundLayer addSublayer:borderLayer];
596
- }
597
- }
598
-
599
- - (void)setArrowFrame {
600
- self.selectionIndicatorArrowLayer.frame = [self frameForSelectionIndicator];
601
-
602
- self.selectionIndicatorArrowLayer.mask = nil;
603
-
604
- UIBezierPath *arrowPath = [UIBezierPath bezierPath];
605
-
606
- CGPoint p1 = CGPointZero;
607
- CGPoint p2 = CGPointZero;
608
- CGPoint p3 = CGPointZero;
609
-
610
- if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationDown) {
611
- p1 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width / 2, 0);
612
- p2 = CGPointMake(0, self.selectionIndicatorArrowLayer.bounds.size.height);
613
- p3 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width,
614
- self.selectionIndicatorArrowLayer.bounds.size.height);
615
- }
616
-
617
- if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp) {
618
- p1 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width / 2,
619
- self.selectionIndicatorArrowLayer.bounds.size.height);
620
- p2 = CGPointMake(self.selectionIndicatorArrowLayer.bounds.size.width, 0);
621
- p3 = CGPointMake(0, 0);
622
- }
623
-
624
- [arrowPath moveToPoint:p1];
625
- [arrowPath addLineToPoint:p2];
626
- [arrowPath addLineToPoint:p3];
627
- [arrowPath closePath];
628
-
629
- CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
630
- maskLayer.frame = self.selectionIndicatorArrowLayer.bounds;
631
- maskLayer.path = arrowPath.CGPath;
632
- self.selectionIndicatorArrowLayer.mask = maskLayer;
633
- }
634
-
635
- - (CGRect)frameForSelectionIndicator {
636
- CGFloat indicatorYOffset = 0.0f;
637
-
638
- if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationDown) {
639
- indicatorYOffset = self.bounds.size.height - self.selectionIndicatorHeight +
640
- self.selectionIndicatorEdgeInsets.bottom;
641
- }
642
-
643
- if (self.selectionIndicatorLocation == HMSegmentedControlSelectionIndicatorLocationUp) {
644
- indicatorYOffset = self.selectionIndicatorEdgeInsets.top;
645
- }
646
-
647
- CGFloat sectionWidth = 0.0f;
648
-
649
- if (self.type == HMSegmentedControlTypeText) {
650
- CGFloat stringWidth = [self measureTitleAtIndex:self.selectedSegmentIndex].width;
651
- sectionWidth = stringWidth;
652
- } else if (self.type == HMSegmentedControlTypeImages) {
653
- UIImage *sectionImage = [self.sectionImages objectAtIndex:self.selectedSegmentIndex];
654
- CGFloat imageWidth = sectionImage.size.width;
655
- sectionWidth = imageWidth;
656
- } else if (self.type == HMSegmentedControlTypeTextImages) {
657
- CGFloat stringWidth = [self measureTitleAtIndex:self.selectedSegmentIndex].width;
658
- UIImage *sectionImage = [self.sectionImages objectAtIndex:self.selectedSegmentIndex];
659
- CGFloat imageWidth = sectionImage.size.width;
660
- sectionWidth = MAX(stringWidth, imageWidth);
661
- }
662
-
663
- if (self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
664
- CGFloat widthToEndOfSelectedSegment =
665
- (self.segmentWidth * self.selectedSegmentIndex) + self.segmentWidth;
666
- CGFloat widthToStartOfSelectedIndex = (self.segmentWidth * self.selectedSegmentIndex);
667
-
668
- CGFloat x = widthToStartOfSelectedIndex +
669
- ((widthToEndOfSelectedSegment - widthToStartOfSelectedIndex) / 2) -
670
- (self.selectionIndicatorHeight / 2);
671
- return CGRectMake(x - (self.selectionIndicatorHeight / 2), indicatorYOffset,
672
- self.selectionIndicatorHeight * 2, self.selectionIndicatorHeight);
673
- } else {
674
- if (self.selectionStyle == HMSegmentedControlSelectionStyleTextWidthStripe &&
675
- sectionWidth <= self.segmentWidth &&
676
- self.segmentWidthStyle != HMSegmentedControlSegmentWidthStyleDynamic) {
677
- CGFloat widthToEndOfSelectedSegment =
678
- (self.segmentWidth * self.selectedSegmentIndex) + self.segmentWidth;
679
- CGFloat widthToStartOfSelectedIndex = (self.segmentWidth * self.selectedSegmentIndex);
680
-
681
- CGFloat x = ((widthToEndOfSelectedSegment - widthToStartOfSelectedIndex) / 2) +
682
- (widthToStartOfSelectedIndex - sectionWidth / 2);
683
- return CGRectMake(x + self.selectionIndicatorEdgeInsets.left, indicatorYOffset,
684
- sectionWidth - self.selectionIndicatorEdgeInsets.right,
685
- self.selectionIndicatorHeight);
686
- } else {
687
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
688
- CGFloat selectedSegmentOffset = 0.0f;
689
-
690
- NSInteger i = 0;
691
- for (NSNumber *width in self.segmentWidthsArray) {
692
- if (self.selectedSegmentIndex == i)
693
- break;
694
- selectedSegmentOffset = selectedSegmentOffset + [width floatValue];
695
- i++;
696
- }
697
- return CGRectMake(
698
- selectedSegmentOffset + self.selectionIndicatorEdgeInsets.left,
699
- indicatorYOffset,
700
- [[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue] -
701
- self.selectionIndicatorEdgeInsets.right,
702
- self.selectionIndicatorHeight + self.selectionIndicatorEdgeInsets.bottom);
703
- }
704
-
705
- return CGRectMake((self.segmentWidth + self.selectionIndicatorEdgeInsets.left) *
706
- self.selectedSegmentIndex,
707
- indicatorYOffset,
708
- self.segmentWidth - self.selectionIndicatorEdgeInsets.right,
709
- self.selectionIndicatorHeight);
710
- }
711
- }
712
- }
713
-
714
- - (CGRect)frameForFillerSelectionIndicator {
715
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
716
- CGFloat selectedSegmentOffset = 0.0f;
717
-
718
- NSInteger i = 0;
719
- for (NSNumber *width in self.segmentWidthsArray) {
720
- if (self.selectedSegmentIndex == i) {
721
- break;
722
- }
723
- selectedSegmentOffset = selectedSegmentOffset + [width floatValue];
724
-
725
- i++;
726
- }
727
-
728
- return CGRectMake(
729
- selectedSegmentOffset, 0,
730
- [[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue],
731
- CGRectGetHeight(self.frame));
732
- }
733
- return CGRectMake(self.segmentWidth * self.selectedSegmentIndex, 0, self.segmentWidth,
734
- CGRectGetHeight(self.frame));
735
- }
736
-
737
- - (void)updateSegmentsRects {
738
- self.scrollView.contentInset = UIEdgeInsetsZero;
739
- self.scrollView.frame =
740
- CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
741
-
742
- if ([self sectionCount] > 0) {
743
- self.segmentWidth = self.frame.size.width / [self sectionCount];
744
- }
745
-
746
- if (self.type == HMSegmentedControlTypeText &&
747
- self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
748
- [self.sectionTitles
749
- enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
750
- CGFloat stringWidth = [self measureTitleAtIndex:idx].width +
751
- self.segmentEdgeInset.left + self.segmentEdgeInset.right;
752
- self.segmentWidth = MAX(stringWidth, self.segmentWidth);
753
- }];
754
- } else if (self.type == HMSegmentedControlTypeText &&
755
- self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
756
- NSMutableArray *mutableSegmentWidths = [NSMutableArray array];
757
-
758
- [self.sectionTitles
759
- enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
760
- CGFloat stringWidth = [self measureTitleAtIndex:idx].width +
761
- self.segmentEdgeInset.left + self.segmentEdgeInset.right;
762
- [mutableSegmentWidths addObject:[NSNumber numberWithFloat:stringWidth]];
763
- }];
764
- self.segmentWidthsArray = [mutableSegmentWidths copy];
765
- } else if (self.type == HMSegmentedControlTypeImages) {
766
- for (UIImage *sectionImage in self.sectionImages) {
767
- CGFloat imageWidth =
768
- sectionImage.size.width + self.segmentEdgeInset.left + self.segmentEdgeInset.right;
769
- self.segmentWidth = MAX(imageWidth, self.segmentWidth);
770
- }
771
- } else if (self.type == HMSegmentedControlTypeTextImages &&
772
- self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
773
- // lets just use the title.. we will assume it is wider then images...
774
- [self.sectionTitles
775
- enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx, BOOL *stop) {
776
- CGFloat stringWidth = [self measureTitleAtIndex:idx].width +
777
- self.segmentEdgeInset.left + self.segmentEdgeInset.right;
778
- self.segmentWidth = MAX(stringWidth, self.segmentWidth);
779
- }];
780
- } else if (self.type == HMSegmentedControlTypeTextImages &&
781
- self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
782
- NSMutableArray *mutableSegmentWidths = [NSMutableArray array];
783
- __block CGFloat totalWidth = 0.0;
784
-
785
- int i = 0;
786
- [self.sectionTitles enumerateObjectsUsingBlock:^(id titleString, NSUInteger idx,
787
- BOOL *stop) {
788
- CGFloat stringWidth = [self measureTitleAtIndex:idx].width + self.segmentEdgeInset.right;
789
- UIImage *sectionImage = [self.sectionImages objectAtIndex:i];
790
- CGFloat imageWidth = sectionImage.size.width + self.segmentEdgeInset.left;
791
-
792
- CGFloat combinedWidth = 0.0;
793
- if (self.imagePosition == HMSegmentedControlImagePositionLeftOfText ||
794
- self.imagePosition == HMSegmentedControlImagePositionRightOfText) {
795
- combinedWidth = imageWidth + stringWidth + self.textImageSpacing;
796
- } else {
797
- combinedWidth = MAX(imageWidth, stringWidth);
798
- }
799
-
800
- totalWidth += combinedWidth;
801
-
802
- [mutableSegmentWidths addObject:[NSNumber numberWithFloat:combinedWidth]];
803
- }];
804
-
805
- if (self.shouldStretchSegmentsToScreenSize && totalWidth < self.bounds.size.width) {
806
- CGFloat whitespace = self.bounds.size.width - totalWidth;
807
- CGFloat whitespaceForSegment = whitespace / [mutableSegmentWidths count];
808
- [mutableSegmentWidths enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx,
809
- BOOL *_Nonnull stop) {
810
- CGFloat extendedWidth = whitespaceForSegment + [obj floatValue];
811
- [mutableSegmentWidths replaceObjectAtIndex:idx
812
- withObject:[NSNumber numberWithFloat:extendedWidth]];
813
- }];
814
- }
815
-
816
- self.segmentWidthsArray = [mutableSegmentWidths copy];
817
- }
818
-
819
- self.scrollView.scrollEnabled = self.isUserDraggable;
820
- self.scrollView.contentSize =
821
- CGSizeMake([self totalSegmentedControlWidth], self.frame.size.height);
822
- }
823
-
824
- - (NSUInteger)sectionCount {
825
- if (self.type == HMSegmentedControlTypeText) {
826
- return self.sectionTitles.count;
827
- } else if (self.type == HMSegmentedControlTypeImages ||
828
- self.type == HMSegmentedControlTypeTextImages) {
829
- return self.sectionImages.count;
830
- }
831
-
832
- return 0;
833
- }
834
-
835
- - (void)willMoveToSuperview:(UIView *)newSuperview {
836
- // Control is being removed
837
- if (newSuperview == nil)
838
- return;
839
-
840
- if (self.sectionTitles || self.sectionImages) {
841
- [self updateSegmentsRects];
842
- }
843
- }
844
-
845
- #pragma mark - Touch
846
-
847
- - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
848
- UITouch *touch = [touches anyObject];
849
- CGPoint touchLocation = [touch locationInView:self];
850
-
851
- CGRect enlargeRect = CGRectMake(
852
- self.bounds.origin.x - self.enlargeEdgeInset.left,
853
- self.bounds.origin.y - self.enlargeEdgeInset.top,
854
- self.bounds.size.width + self.enlargeEdgeInset.left + self.enlargeEdgeInset.right,
855
- self.bounds.size.height + self.enlargeEdgeInset.top + self.enlargeEdgeInset.bottom);
856
-
857
- if (CGRectContainsPoint(enlargeRect, touchLocation)) {
858
- NSInteger segment = 0;
859
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
860
- segment = (touchLocation.x + self.scrollView.contentOffset.x) / self.segmentWidth;
861
- } else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
862
- // To know which segment the user touched, we need to loop over the
863
- // widths and substract it from the x position.
864
- CGFloat widthLeft = (touchLocation.x + self.scrollView.contentOffset.x);
865
- for (NSNumber *width in self.segmentWidthsArray) {
866
- widthLeft = widthLeft - [width floatValue];
867
-
868
- // When we don't have any width left to substract, we have the
869
- // segment index.
870
- if (widthLeft <= 0)
871
- break;
872
-
873
- segment++;
874
- }
875
- }
876
-
877
- NSUInteger sectionsCount = 0;
878
-
879
- if (self.type == HMSegmentedControlTypeImages) {
880
- sectionsCount = [self.sectionImages count];
881
- } else if (self.type == HMSegmentedControlTypeTextImages ||
882
- self.type == HMSegmentedControlTypeText) {
883
- sectionsCount = [self.sectionTitles count];
884
- }
885
-
886
- if (segment != self.selectedSegmentIndex && segment < sectionsCount) {
887
- // Check if we have to do anything with the touch event
888
- if (self.isTouchEnabled)
889
- [self setSelectedSegmentIndex:segment
890
- animated:self.shouldAnimateUserSelection
891
- notify:YES];
892
- }
893
- }
894
- }
895
-
896
- #pragma mark - Scrolling
897
-
898
- - (CGFloat)totalSegmentedControlWidth {
899
- if (self.type == HMSegmentedControlTypeText &&
900
- self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
901
- return self.sectionTitles.count * self.segmentWidth;
902
- } else if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleDynamic) {
903
- return [[self.segmentWidthsArray valueForKeyPath:@"@sum.self"] floatValue];
904
- } else {
905
- return self.sectionImages.count * self.segmentWidth;
906
- }
907
- }
908
-
909
- - (void)scrollToSelectedSegmentIndex:(BOOL)animated {
910
- CGRect rectForSelectedIndex = CGRectZero;
911
- CGFloat selectedSegmentOffset = 0;
912
- if (self.segmentWidthStyle == HMSegmentedControlSegmentWidthStyleFixed) {
913
- rectForSelectedIndex = CGRectMake(self.segmentWidth * self.selectedSegmentIndex, 0,
914
- self.segmentWidth, self.frame.size.height);
915
-
916
- selectedSegmentOffset = (CGRectGetWidth(self.frame) / 2) - (self.segmentWidth / 2);
917
- } else {
918
- NSInteger i = 0;
919
- CGFloat offsetter = 0;
920
- for (NSNumber *width in self.segmentWidthsArray) {
921
- if (self.selectedSegmentIndex == i)
922
- break;
923
- offsetter = offsetter + [width floatValue];
924
- i++;
925
- }
926
-
927
- rectForSelectedIndex = CGRectMake(
928
- offsetter, 0,
929
- [[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue],
930
- self.frame.size.height);
931
-
932
- selectedSegmentOffset =
933
- (CGRectGetWidth(self.frame) / 2) -
934
- ([[self.segmentWidthsArray objectAtIndex:self.selectedSegmentIndex] floatValue] / 2);
935
- }
936
-
937
- CGRect rectToScrollTo = rectForSelectedIndex;
938
- rectToScrollTo.origin.x -= selectedSegmentOffset;
939
- rectToScrollTo.size.width += selectedSegmentOffset * 2;
940
- [self.scrollView scrollRectToVisible:rectToScrollTo animated:animated];
941
- }
942
-
943
- #pragma mark - Index Change
944
-
945
- - (void)setSelectedSegmentIndex:(NSInteger)index {
946
- [self setSelectedSegmentIndex:index animated:NO notify:NO];
947
- }
948
-
949
- - (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated {
950
- [self setSelectedSegmentIndex:index animated:animated notify:NO];
951
- }
952
-
953
- - (void)setSelectedSegmentIndex:(NSUInteger)index animated:(BOOL)animated notify:(BOOL)notify {
954
- _selectedSegmentIndex = index;
955
- [self setNeedsDisplay];
956
-
957
- if (index == HMSegmentedControlNoSegment) {
958
- [self.selectionIndicatorArrowLayer removeFromSuperlayer];
959
- [self.selectionIndicatorStripLayer removeFromSuperlayer];
960
- [self.selectionIndicatorBoxLayer removeFromSuperlayer];
961
- } else {
962
- [self scrollToSelectedSegmentIndex:animated];
963
-
964
- if (animated) {
965
- // If the selected segment layer is not added to the super layer,
966
- // that means no index is currently selected, so add the layer then
967
- // move it to the new segment index without animating.
968
- if (self.selectionStyle == HMSegmentedControlSelectionStyleArrow) {
969
- if ([self.selectionIndicatorArrowLayer superlayer] == nil) {
970
- [self.scrollView.layer addSublayer:self.selectionIndicatorArrowLayer];
971
-
972
- [self setSelectedSegmentIndex:index animated:NO notify:YES];
973
- return;
974
- }
975
- } else {
976
- if ([self.selectionIndicatorStripLayer superlayer] == nil) {
977
- [self.scrollView.layer addSublayer:self.selectionIndicatorStripLayer];
978
-
979
- if (self.selectionStyle == HMSegmentedControlSelectionStyleBox &&
980
- [self.selectionIndicatorBoxLayer superlayer] == nil)
981
- [self.scrollView.layer insertSublayer:self.selectionIndicatorBoxLayer
982
- atIndex:0];
983
-
984
- [self setSelectedSegmentIndex:index animated:NO notify:YES];
985
- return;
986
- }
987
- }
988
-
989
- if (notify)
990
- [self notifyForSegmentChangeToIndex:index];
991
-
992
- // Restore CALayer animations
993
- self.selectionIndicatorArrowLayer.actions = nil;
994
- self.selectionIndicatorStripLayer.actions = nil;
995
- self.selectionIndicatorBoxLayer.actions = nil;
996
-
997
- // Animate to new position
998
- [CATransaction begin];
999
- [CATransaction setAnimationDuration:0.15f];
1000
- [CATransaction
1001
- setAnimationTimingFunction:[CAMediaTimingFunction
1002
- functionWithName:kCAMediaTimingFunctionLinear]];
1003
- [self setArrowFrame];
1004
- self.selectionIndicatorBoxLayer.frame = [self frameForSelectionIndicator];
1005
- self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
1006
- self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
1007
- [CATransaction commit];
1008
- } else {
1009
- // Disable CALayer animations
1010
- NSMutableDictionary *newActions = [[NSMutableDictionary alloc]
1011
- initWithObjectsAndKeys:[NSNull null], @"position", [NSNull null], @"bounds", nil];
1012
- self.selectionIndicatorArrowLayer.actions = newActions;
1013
- [self setArrowFrame];
1014
-
1015
- self.selectionIndicatorStripLayer.actions = newActions;
1016
- self.selectionIndicatorStripLayer.frame = [self frameForSelectionIndicator];
1017
-
1018
- self.selectionIndicatorBoxLayer.actions = newActions;
1019
- self.selectionIndicatorBoxLayer.frame = [self frameForFillerSelectionIndicator];
1020
-
1021
- if (notify)
1022
- [self notifyForSegmentChangeToIndex:index];
1023
- }
1024
- }
1025
- }
1026
-
1027
- - (void)notifyForSegmentChangeToIndex:(NSInteger)index {
1028
- if (self.superview)
1029
- [self sendActionsForControlEvents:UIControlEventValueChanged];
1030
-
1031
- if (self.indexChangeBlock)
1032
- self.indexChangeBlock(index);
1033
- }
1034
-
1035
- #pragma mark - Styling Support
1036
-
1037
- - (NSDictionary *)resultingTitleTextAttributes {
1038
- NSDictionary *defaults = @{
1039
- NSFontAttributeName : [UIFont systemFontOfSize:19.0f],
1040
- NSForegroundColorAttributeName : [UIColor blackColor],
1041
- };
1042
-
1043
- NSMutableDictionary *resultingAttrs = [NSMutableDictionary dictionaryWithDictionary:defaults];
1044
-
1045
- if (self.titleTextAttributes) {
1046
- [resultingAttrs addEntriesFromDictionary:self.titleTextAttributes];
1047
- }
1048
-
1049
- return [resultingAttrs copy];
1050
- }
1051
-
1052
- - (NSDictionary *)resultingSelectedTitleTextAttributes {
1053
- NSMutableDictionary *resultingAttrs =
1054
- [NSMutableDictionary dictionaryWithDictionary:[self resultingTitleTextAttributes]];
1055
-
1056
- if (self.selectedTitleTextAttributes) {
1057
- [resultingAttrs addEntriesFromDictionary:self.selectedTitleTextAttributes];
1058
- }
1059
-
1060
- return [resultingAttrs copy];
1061
- }
1062
-
1063
- @end