VTMagicView.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. //
  2. // VTMagicView.h
  3. // VTMagicView
  4. //
  5. // Created by tianzhuo on 14-11-11.
  6. // Copyright (c) 2014-2016 tianzhuo. All rights reserved.
  7. // https://github.com/tianzhuo112/VTMagic.git
  8. //
  9. #import <UIKit/UIKit.h>
  10. #import "VTMagicProtocol.h"
  11. #import "VTMagicMacros.h"
  12. #import "VTEnumType.h"
  13. NS_ASSUME_NONNULL_BEGIN
  14. @class VTMagicView;
  15. /****************************************data source****************************************/
  16. @protocol VTMagicViewDataSource <NSObject>
  17. @required
  18. /**
  19. * 获取所有菜单名,数组中存放字符串类型对象
  20. *
  21. * @param magicView self
  22. *
  23. * @return header数组
  24. */
  25. - (NSArray<__kindof NSString *> *)menuTitlesForMagicView:(VTMagicView *)magicView;
  26. /**
  27. * 根据itemIndex加载对应的menuItem
  28. *
  29. * @param magicView self
  30. * @param itemIndex 需要加载的菜单索引
  31. *
  32. * @return 当前索引对应的菜单按钮
  33. */
  34. - (UIButton *)magicView:(VTMagicView *)magicView menuItemAtIndex:(NSUInteger)itemIndex;
  35. /**
  36. * 根据pageIndex加载对应的页面控制器
  37. *
  38. * @param magicView self
  39. * @param pageIndex 需要加载的页面索引
  40. *
  41. * @return 页面控制器
  42. */
  43. - (UIViewController *)magicView:(VTMagicView *)magicView viewControllerAtPage:(NSUInteger)pageIndex;
  44. @end
  45. /****************************************delegate****************************************/
  46. @protocol VTMagicViewDelegate <NSObject>
  47. @optional
  48. /**
  49. * 视图控制器显示到当前屏幕上时触发
  50. *
  51. * @param magicView self
  52. * @param viewController 当前页面展示的控制器
  53. * @param pageIndex 当前控控制器对应的索引
  54. */
  55. - (void)magicView:(VTMagicView *)magicView viewDidAppear:(__kindof UIViewController *)viewController atPage:(NSUInteger)pageIndex;
  56. /**
  57. * 视图控制器从屏幕上消失时触发
  58. *
  59. * @param magicView self
  60. * @param viewController 消失的视图控制器
  61. * @param pageIndex 消失的控制器对应的索引
  62. */
  63. - (void)magicView:(VTMagicView *)magicView viewDidDisappear:(__kindof UIViewController *)viewController atPage:(NSUInteger)pageIndex;
  64. /**
  65. * 选中导航菜单item时触发
  66. *
  67. * @param magicView self
  68. * @param itemIndex menuItem对应的索引
  69. */
  70. - (void)magicView:(VTMagicView *)magicView didSelectItemAtIndex:(NSUInteger)itemIndex;
  71. /**
  72. * 根据itemIndex获取对应menuItem的宽度,若返回结果为0,内部将自动计算其宽度
  73. * 通常情况下只需设置itemSpacing或itemWidth即可
  74. *
  75. * @param magicView self
  76. * @param itemIndex menuItem对应的索引
  77. *
  78. * @return menuItem的宽度
  79. */
  80. - (CGFloat)magicView:(VTMagicView *)magicView itemWidthAtIndex:(NSUInteger)itemIndex;
  81. /**
  82. * 根据itemIndex获取对应slider的宽度,若返回结果为0,内部将自动计算其宽度
  83. * 通常情况下只需设置sliderWidth、sliderExtension或bubbleInset即可
  84. *
  85. * @param magicView self
  86. * @param itemIndex slider对应的索引
  87. *
  88. * @return slider的宽度
  89. */
  90. - (CGFloat)magicView:(VTMagicView *)magicView sliderWidthAtIndex:(NSUInteger)itemIndex;
  91. @end
  92. @interface VTMagicView : UIView
  93. #pragma mark - basic configurations
  94. /****************************************basic configurations****************************************/
  95. /**
  96. * 数据源
  97. */
  98. @property (nonatomic, weak, nullable) id<VTMagicViewDataSource> dataSource;
  99. /**
  100. * 代理
  101. */
  102. @property (nonatomic, weak, nullable) id<VTMagicViewDelegate> delegate;
  103. /**
  104. * 主控制器,若delegate遵循协议VTMagicProtocol,则默认与其相同
  105. *
  106. * @warning 若继承或直接实例化VTMagicController,则不需要设置该属性
  107. */
  108. @property (nonatomic, weak, nullable) UIViewController<VTMagicProtocol> *magicController;
  109. /**
  110. * 切换样式,默认是VTSwitchStyleDefault
  111. */
  112. @property (nonatomic, assign) VTSwitchStyle switchStyle;
  113. /**
  114. * 导航菜单的布局样式
  115. */
  116. @property (nonatomic, assign) VTLayoutStyle layoutStyle;
  117. /**
  118. * 导航栏滑块样式,默认显示下划线
  119. */
  120. @property (nonatomic, assign) VTSliderStyle sliderStyle;
  121. /**
  122. * 导航菜单item的预览数,默认为1
  123. *
  124. * @warning displayCentered为YES时,该属性无效
  125. */
  126. @property (nonatomic, assign) NSUInteger previewItems;
  127. #pragma mark - subviews
  128. /****************************************subviews****************************************/
  129. /**
  130. * 最顶部的头部组件,默认隐藏
  131. * 若需显示请通过属性headerHidden设置
  132. */
  133. @property (nonatomic, strong, readonly) UIView *headerView;
  134. /**
  135. * 顶部导航视图
  136. */
  137. @property (nonatomic, strong, readonly) UIView *navigationView;
  138. /**
  139. * 顶部导航栏左侧视图项
  140. */
  141. @property (nonatomic, strong, nullable) UIView *leftNavigatoinItem;
  142. /**
  143. * 顶部导航栏右侧视图项
  144. */
  145. @property (nonatomic, strong, nullable) UIView *rightNavigatoinItem;
  146. /**
  147. * 当前屏幕上已加载的控制器
  148. */
  149. @property (nonatomic, strong, readonly) NSArray<__kindof UIViewController *> *viewControllers;
  150. /**
  151. * 自定义滑块视图
  152. */
  153. - (void)setSliderView:(UIView *)sliderView;
  154. /**
  155. * 自定义导航分割线视图
  156. */
  157. - (void)setSeparatorView:(UIView *)separatorView;
  158. #pragma mark - bool configurations
  159. /****************************************bool configurations****************************************/
  160. /**
  161. * 是否允许页面左右滑动,默认YES
  162. */
  163. @property (nonatomic, assign, getter=isScrollEnabled) BOOL scrollEnabled;
  164. /**
  165. * 是否允许导航菜单左右滑动,默认YES
  166. */
  167. @property (nonatomic, assign, getter=isMenuScrollEnabled) BOOL menuScrollEnabled;
  168. /**
  169. * 是否允许切换,包括左右滑动和点击切换,默认YES
  170. * 若禁止,则所有切换事件全部无响应,非特殊情况不应修改本属性
  171. */
  172. @property (nonatomic, assign, getter=isSwitchEnabled) BOOL switchEnabled;
  173. /**
  174. * 点击导航菜单切换页面时是否需要动画,默认YES
  175. */
  176. @property (nonatomic, assign, getter=isSwitchAnimated) BOOL switchAnimated;
  177. /**
  178. * 隐藏滑块
  179. */
  180. @property (nonatomic, assign, getter=isSliderHidden) BOOL sliderHidden;
  181. /**
  182. * 隐藏导航分割线
  183. */
  184. @property (nonatomic, assign, getter=isSeparatorHidden) BOOL separatorHidden;
  185. /**
  186. * 导航栏item的选中状态是否已被取消,默认NO
  187. */
  188. @property (nonatomic, assign, readonly, getter=isDeselected) BOOL deselected;
  189. /**
  190. * 顶部导航栏是否紧贴系统状态栏,即是否需要为状态栏留出20个点的区域,默认NO
  191. */
  192. @property (nonatomic, assign, getter=isAgainstStatusBar) BOOL againstStatusBar;
  193. /**
  194. * 是否隐藏头部组件,默认YES
  195. */
  196. @property (nonatomic, assign, getter=isHeaderHidden) BOOL headerHidden;
  197. /**
  198. * 显示或隐藏头部组件
  199. *
  200. * @param headerHidden 是否隐藏
  201. * @param duration 动画时长
  202. */
  203. - (void)setHeaderHidden:(BOOL)headerHidden duration:(CGFloat)duration;
  204. /**
  205. * 是否需要预加载下一页,默认YES,
  206. * 若为NO,则点击导航菜单和调用switchToPage:animated:方法切换页面时均无动画,
  207. * 其切换效果与属性switchAnimated为NO时相同
  208. */
  209. @property (nonatomic, assign) BOOL needPreloading;
  210. /**
  211. * 是否正在切换中,仅动画切换时为YES
  212. */
  213. @property (nonatomic, assign, readonly, getter=isSwitching) BOOL switching;
  214. /**
  215. * 被选中的menuItem是否居中显示,默认NO
  216. */
  217. @property (nonatomic, assign) BOOL displayCentered;
  218. /**
  219. * 页面滑到两侧边缘时是否需要反弹效果,默认NO
  220. */
  221. @property (nonatomic, assign) BOOL bounces;
  222. /**
  223. * 底部是否需要扩展一个tabbar的高度,设置毛玻璃效果时或许有用,默认NO
  224. */
  225. @property (nonatomic, assign) BOOL needExtendBottom VT_DEPRECATED_IN("1.2.5");
  226. #pragma mark - color & size configurations
  227. /**************************************color & size**************************************/
  228. /**
  229. * 导航菜单栏的inset,对leftNavigatoinItem和rightNavigatoinItem无效
  230. */
  231. @property (nonatomic, assign) UIEdgeInsets navigationInset;
  232. /**
  233. * 顶部导航栏背景色
  234. */
  235. @property (nonatomic, strong, nullable) UIColor *navigationColor;
  236. /**
  237. * 顶部导航条的高度,默认是44
  238. */
  239. @property (nonatomic, assign) CGFloat navigationHeight;
  240. /**
  241. * 顶部导航栏底部分割线颜色
  242. */
  243. @property (nonatomic, strong, nullable) UIColor *separatorColor;
  244. /**
  245. * 导航栏分割线高度,默认0.5个点
  246. */
  247. @property (nonatomic, assign) CGFloat separatorHeight;
  248. /**
  249. * 顶部导航栏滑块颜色
  250. */
  251. @property (nonatomic, strong, nullable) UIColor *sliderColor;
  252. /**
  253. * 顶部导航栏滑块高度,默认2
  254. *
  255. * @warning 非VTSliderStyleDefault样式,该属性无效
  256. */
  257. @property (nonatomic, assign) CGFloat sliderHeight;
  258. /**
  259. * 顶部导航栏滑块宽度,VTSliderStyleDefault样式下默认与item宽度一致
  260. *
  261. * @warning 非VTSliderStyleDefault样式,该属性无效
  262. */
  263. @property (nonatomic, assign) CGFloat sliderWidth;
  264. /**
  265. * 滑块宽度延长量,0表示滑块宽度与文本宽度一致,该属性优先级低于sliderWidth
  266. *
  267. * @warning 非VTSliderStyleDefault样式或sliderWidth有效时,该属性无效
  268. */
  269. @property (nonatomic, assign) CGFloat sliderExtension;
  270. /**
  271. * 顶部导航栏滑块相对导航底部的偏移量,默认0,上偏为负
  272. *
  273. * @warning 非VTSliderStyleDefault样式,该属性无效
  274. */
  275. @property (nonatomic, assign) CGFloat sliderOffset;
  276. /**
  277. * 气泡相对menuItem文本的edgeInsets,默认(2, 5, 2, 5)
  278. *
  279. * @warning 该属性用于VTSliderStyleBubble样式下
  280. */
  281. @property (nonatomic, assign) UIEdgeInsets bubbleInset;
  282. /**
  283. * 滑块的圆角半径,默认10
  284. *
  285. * @warning 该属性用于VTSliderStyleBubble样式下
  286. */
  287. @property (nonatomic, assign) CGFloat bubbleRadius;
  288. /**
  289. * 头部组件的高度默认64
  290. */
  291. @property (nonatomic, assign) CGFloat headerHeight;
  292. /**
  293. * item之间的实际间距
  294. */
  295. @property (nonatomic, assign) CGFloat acturalSpacing;
  296. /**
  297. * 两个导航菜单item文本之间的间距,默认是25,其优先级低于itemWidth
  298. * 如果菜单item包含图片,则实际间距可能会更小
  299. *
  300. * @warning 该属性在VTLayoutStyleDivide样式下无效
  301. */
  302. @property (nonatomic, assign) CGFloat itemSpacing;
  303. /**
  304. * menuItem被选中时文本的放大倍数,默认1.0
  305. * 可根据需要设置合适的数值,通常不宜超过1.5
  306. */
  307. @property (nonatomic, assign) CGFloat itemScale;
  308. /**
  309. * 自定义item宽度,默认0,当设置改属性时,itemSpacing的设置无效
  310. *
  311. * @warning 该属性在VTLayoutStyleDivide样式下无效
  312. */
  313. @property (nonatomic, assign) CGFloat itemWidth;
  314. #pragma mark - other properties
  315. /**************************************other properties**************************************/
  316. /**
  317. * 页面切换事件,用于行为统计
  318. */
  319. @property (nonatomic, assign, readonly) VTSwitchEvent switchEvent;
  320. #pragma mark - public method
  321. /**************************************public method**************************************/
  322. /**
  323. * 重新加载所有数据
  324. */
  325. - (void)reloadData;
  326. /**
  327. * 重新加载所有数据,同时定位到指定页面,若page越界,则自动修正为0
  328. *
  329. * @param pageIndex 被定位的页面
  330. */
  331. - (void)reloadDataToPage:(NSUInteger)pageIndex;
  332. /**
  333. * 更新菜单标题,但不重新加载页面
  334. *
  335. * @warning 仅限于菜单顺序和页数不改变的情况下,一般情况下建议使用reloadData方法
  336. */
  337. - (void)reloadMenuTitles;
  338. /**
  339. * 查询可重用menuItem
  340. *
  341. * @param identifier 重用标识
  342. *
  343. * @return 可重用的menuItem
  344. */
  345. - (nullable __kindof UIButton *)dequeueReusableItemWithIdentifier:(NSString *)identifier;
  346. /**
  347. * 根据缓存标识获取可重用的UIViewController
  348. *
  349. * @param identifier 缓存重用标识
  350. *
  351. * @return 可重用的UIViewController
  352. */
  353. - (nullable __kindof UIViewController *)dequeueReusablePageWithIdentifier:(NSString *)identifier;
  354. /**
  355. * 根据控制器获取对应的页面索引,仅当前显示的和预加载的控制器有相应索引,
  356. * 若没有找到相应索引则返回NSNotFound
  357. *
  358. * @param viewController 页面控制器
  359. *
  360. * @return 页面索引
  361. */
  362. - (NSInteger)pageIndexForViewController:(UIViewController *)viewController;
  363. /**
  364. * 获取索引对应的ViewController
  365. * 若index超出范围或对应控制器不可见,则返回nil
  366. *
  367. * @param pageIndex 索引
  368. *
  369. * @return UIViewController对象
  370. */
  371. - (nullable __kindof UIViewController *)viewControllerAtPage:(NSUInteger)pageIndex;
  372. /**
  373. * 根据索引获取当前页面显示的menuItem,不在窗口上显示的则为nil
  374. *
  375. * @param index 索引
  376. *
  377. * @return 当前索引对应的menuItem
  378. */
  379. - (nullable __kindof UIButton *)menuItemAtIndex:(NSUInteger)index;
  380. /**
  381. * 切换到指定页面
  382. *
  383. * @param pageIndex 页面索引
  384. * @param animated 是否需要动画执行
  385. */
  386. - (void)switchToPage:(NSUInteger)pageIndex animated:(BOOL)animated;
  387. /**
  388. * 处理UIPanGestureRecognizer手势,用于解决页面内嵌webView时无法响应手势问题
  389. *
  390. * @param recognizer 手势
  391. */
  392. - (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer;
  393. /**
  394. * 取消菜单item的选中状态,可通过属性deselected获取当前状态
  395. * 取消选中后须调用方法reselectMenuItem以恢复
  396. */
  397. - (void)deselectMenuItem;
  398. /**
  399. * 恢复菜单menuItem的选中状态
  400. */
  401. - (void)reselectMenuItem;
  402. /**
  403. * 清除所有缓存的页面
  404. */
  405. - (void)clearMemoryCache;
  406. NS_ASSUME_NONNULL_END
  407. @end