級別: ★★☆☆☆
標籤:「iOS」「分頁」「QiPageMenuView」
做者: 沐靈洛
審校: QiShare團隊php
項目中咱們常常會遇到滾動分頁的設計效果,被用來對不一樣數據界面的展現進行分類。咱們先能夠來預覽一下實現效果:git
根據動圖進行實現分析:這個效果的實現分爲兩部分頂部的QiPageMenuView和內容展現部分QiPageContentView:github
QiPageMenuView是基於UIScrollView實現的,咱們能夠按照本身的項目需求,定製本身須要實現的效果。QiPageMenuView提供了可設置的屬性有:菜單每一項是否根據文字的大小自適應寬度仍是設置固定寬度、菜單的首項和最後一項距離父視圖的間距、每一項之間的間距、包括了每一項QiPageItem的展現效果自定義等。也實現了菜單項超出一屏幕時自動滑動顯示的效果:數組
QiPageContentView是基於UIPageViewController實現的封裝,在項目中可能有多處這樣的界面效果。單純的使用UIPageViewController寫在相應的控制器中,添加相應的子控制器,經過實現UIPageViewController的數據源和代理協議也能夠達到這種效果。可是UIPageViewController嵌套在主控制器中,耦合度比較高,代碼量也比較大,如果多處須要使用這種效果,每次都寫一遍UIPageViewController,效率和可移植性不高。 QiPageMenuView和QiPageContentView之間是解耦合的,彼此均可以做爲單獨的控件去使用。在設計構思時,菜單視圖的樣式有多是QiPageMenuView樣式以外的視圖,如果二者耦合度過高,就變成了QiPageContentView + QiPageMenuView組合,能展示的效果就被限制了。bash
@interface QiPageMenuView : UIScrollView<QiPageControllerDelegate>
/**
菜單欄點擊事件
*/
@property (nonatomic,copy)void(^pageItemClicked)(NSInteger clickedIndex,QiPageMenuView *menu);
/**
常態item的字體顏色
*/
@property (nonatomic,strong)UIColor *normalTitleColor;
/**
選中item的字體顏色
*/
@property (nonatomic,strong)UIColor *selectedTitleColor;
/**
常態item的字體
*/
@property (nonatomic,strong)UIFont *titleFont;
/**
選中Item的字體
*/
@property (nonatomic,strong)UIFont *selectedTitleFont;
/**
字體距離item兩邊的間距,itemsAutoResizing = YES時 設置有效
*/
@property (nonatomic,assign)CGFloat itemTitlePadding;
/**
item距上的間距。itemIsVerticalCentred = NO的時候設置有效
*/
@property (nonatomic,assign)CGFloat itemTopPadding;
/**
items的左邊縮進
*/
@property (nonatomic,assign)CGFloat leftMargin;
/**
items的右邊縮進
*/
@property (nonatomic,assign)CGFloat rightMargin;
/**
是否根據文字的長度自動計算item的width default YES
*/
@property (nonatomic,assign)BOOL itemsAutoResizing;
/**
item是否垂直居中顯示,默認yes; itemTopPadding 與 lineTopPadding 不會生效;設置NO itemHeight會自適應高
*/
@property (nonatomic,assign)BOOL itemIsVerticalCentred;
/**
item之間的間距
*/
@property (nonatomic,assign)CGFloat itemSpace;
/**
每一個item的高度
*/
@property (nonatomic,assign)CGFloat itemHeight;
/**
每一個item的寬度。itemsAutoResizing = YES沒必要賦值也可。反之必須給值。
*/
@property (nonatomic,assign)CGFloat itemWidth;
/**
是否顯示下劃線 default YES
*/
@property (nonatomic,assign)BOOL hasUnderLine;
/**
下劃線顏色
*/
@property (nonatomic,strong)UIColor *lineColor;
/**
下劃線到item的間距
*/
@property (nonatomic,assign)CGFloat lineTopPadding;
/**
下劃線的高度
*/
@property (nonatomic,assign)CGFloat lineHeight;
/**
下劃線的寬度
*/
@property (nonatomic,assign)CGFloat lineWitdh;
/**
pageController滑動完成
*/
@property (nonatomic,assign)NSInteger pageScrolledIndex;
/**
初始化方法
*/
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray*)titles dataSource:(NSDictionary<QiPageMenuViewDataSourceKey, id> *)dataSource;
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray*)titles;
/**
滑動到某一項
@param pageItem item
*/
- (void)scrollToPageItem:(QiPageItem*)pageItem;
/*!
@brief 更新標題數組
@param items selectedIndex重置選中的item
*/
- (void)updateMenuViewWithNewItemArray:(NSArray *)items selectedIndex:(NSInteger)selectedIndex;
@end
複製代碼
- (void)scrollToPageItem:(QiPageItem*)pageItem {
[self refreshUnderLineViewPosition:pageItem];
if (self.contentSize.width <= self.width) {
return;
}
CGRect originalRect = pageItem.frame;
CGRect convertRect = [self convertRect:originalRect toView:self.superview];
CGFloat targetX;
CGFloat realMidX = CGRectGetMinX(originalRect)+CGRectGetWidth(originalRect)/2;
if (CGRectGetMidX(convertRect) < CGRectGetMidX(self.frame)) {
//是否須要右滑
if (realMidX> CGRectGetMidX(self.frame)) {
targetX = realMidX-CGRectGetMidX(self.frame);
}else {
targetX = 0;
}
[self setContentOffset:CGPointMake(targetX, 0) animated:YES];
} else if (CGRectGetMidX(convertRect) > CGRectGetMidX(self.frame)) {
if (realMidX+CGRectGetMidX(self.frame)<self.contentSize.width) {
targetX = realMidX-CGRectGetMidX(self.frame);
} else {
targetX = self.contentSize.width - CGRectGetMaxX(self.frame);
}
[self setContentOffset:CGPointMake(targetX, 0) animated:YES];
}
}
複製代碼
//定製樣式
NSDictionary *dataSource = @{
QiPageMenuViewNormalTitleColor : [UIColor blackColor],
QiPageMenuViewSelectedTitleColor : [UIColor redColor],
QiPageMenuViewTitleFont : [UIFont systemFontOfSize:14],
QiPageMenuViewSelectedTitleFont : [UIFont systemFontOfSize:14],
QiPageMenuViewItemIsVerticalCentred : @(YES),
QiPageMenuViewItemTitlePadding : @(10.0),
QiPageMenuViewItemTopPadding : @(20.0),
QiPageMenuViewItemPadding : @(10.0),
QiPageMenuViewLeftMargin : @(20.0),
QiPageMenuViewRightMargin : @(20.0),
QiPageMenuViewItemsAutoResizing : @(YES),
QiPageMenuViewItemWidth : @(90.0),
QiPageMenuViewItemHeight : @(40.0),
QiPageMenuViewHasUnderLine :@(YES),
QiPageMenuViewLineColor : [UIColor greenColor],
QiPageMenuViewLineWidth : @(30.0),
QiPageMenuViewLineHeight : @(4.0),
QiPageMenuViewLineTopPadding : @(10.0)
};
QiPageMenuView *menuView = [[QiPageMenuView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 50) titles:@[@"消息",@"節日消息",@"廣播通知",@"QISHARE",@"奇舞團"] dataSource:dataSource];
menuView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:menuView];
複製代碼
QiPageMenuView *menuView = [[QiPageMenuView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 50) titles:@[@"系統消息",@"節日消息",@"廣播通知"]];
menuView.backgroundColor = [UIColor orangeColor];
//定製樣式
menuView.normalTitleColor = [UIColor blackColor];
menuView.selectedTitleColor = [UIColor redColor];
menuView.titleFont = [UIFont systemFontOfSize:14];
menuView.selectedTitleFont = [UIFont systemFontOfSize:14];
menuView.itemIsVerticalCentred = YES;
menuView.itemTitlePadding = 10.0;
menuView.itemTopPadding = 20.0;
menuView.itemSpace = 10.0;
menuView.leftMargin = 20.0;
menuView.rightMargin = 20.0;
menuView.itemsAutoResizing = YES;
menuView.itemWidth = 90;
menuView.itemHeight = 40;
menuView.hasUnderLine = YES;
menuView.lineColor = [UIColor greenColor];
menuView.lineWitdh = 30;
menuView.lineHeight = 4.0;
menuView.lineTopPadding = 10;
[self.view addSubview:menuView];
複製代碼
@interface QiPageContentView : UIView<UIPageViewControllerDelegate, UIPageViewControllerDataSource,UIScrollViewDelegate>
@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *controllerArray; //!< 控制器數組
/**
滑動結束:block回調
*/
@property (nonatomic,copy)void(^pageContentViewDidScroll)(NSInteger currentIndex,NSInteger beforeIndex,QiPageContentView *pageView);
/**
滑動結束:代理回調 若實現block代理不會走
*/
@property (nonatomic, weak) id<QiPageContentViewDelegate> contentViewDelgate;
/**
設置滑動至某一個控制器
@param index index
@param beforeIndex 控制方向
*/
- (void)setPageContentShouldScrollToIndex:(NSInteger)index beforIndex:(NSInteger)beforeIndex;
/**
初始化方法
@param frame frame
@param childViewControllers childViewControllers
@return 實例
*/
- (instancetype)initWithFrame:(CGRect)frame childViewController:(NSArray*)childViewControllers;
@end
複製代碼
QiPageContentView *contenView = [[QiPageContentView alloc]initWithFrame:CGRectMake(0, 10, self.view.width, self.view.height - 88-10) childViewController:@[ctrl,ctrl1,ctrl2,ctrl3]];
[self.view addSubview:contenView];
複製代碼
QiPageContentView與QiPageMenuView使用各自頭文件中定義的協議或者block屬性實現二者之間事件交互,從而達到分頁聯動效果;二者的解耦,使得它們的使用更加靈活。微信
@protocol QiPageMenuViewDelegate <NSObject>
/**
菜單點擊了某個item
@param index 點擊了index
*/
- (void)pageMenuViewDidClickedIndex:(NSInteger)index beforeIndex:(NSInteger)beforeIndex;
@end
@interface QiPageMenuView : UIScrollView
/**
菜單欄點擊事件:block回調
*/
@property (nonatomic,copy)void(^pageItemClicked)(NSInteger clickedIndex,NSInteger beforeIndex,QiPageMenuView *menu);
/**
菜單欄點擊事件:代理回調 若實現block代理不會走
*/
@property (nonatomic, weak) id<QiPageMenuViewDelegate> menuViewDelgate;
複製代碼
@protocol QiPageContentViewDelegate <NSObject>
/**
滑動完成回調
@param index 滑動至index
*/
- (void)pageContentViewDidScrollToIndex:(NSInteger)index beforeIndex:(NSInteger)beforeIndex;
@end
@interface QiPageContentView : UIView<UIPageViewControllerDelegate, UIPageViewControllerDataSource,UIScrollViewDelegate>
@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *controllerArray; //!< 控制器數組
/**
滑動結束:block回調
*/
@property (nonatomic,copy)void(^pageContentViewDidScroll)(NSInteger currentIndex,NSInteger beforeIndex,QiPageContentView *pageView);
/**
滑動結束:代理回調 若實現block代理不會走
*/
@property (nonatomic, weak) id<QiPageContentViewDelegate> contentViewDelgate;
複製代碼
QiPageMenuView *menuView = [[QiPageMenuView alloc]initWithFrame:CGRectMake(0, 0, self.view.width, 50) titles:@[@"系統消息",@"節日消息",@"廣播通知",@"最新",@"最熱"] dataSource:dataSource];
menuView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:menuView];
QiPageContentView *contenView = [[QiPageContentView alloc]initWithFrame:CGRectMake(0, menuView.bottom+10, self.view.width, self.view.height - menuView.bottom - 10 - 88-10) childViewController:@[ctrl,ctrl1,ctrl2,ctrl3,ctrl4]];
[self.view addSubview:contenView];
menuView.pageItemClicked = ^(NSInteger clickedIndex, NSInteger beforeIndex, QiPageMenuView *menu) {
NSLog(@"點擊了:以前:%ld 如今:%ld",beforeIndex,clickedIndex);
[contenView setPageContentShouldScrollToIndex:clickedIndex beforIndex:beforeIndex];
};
contenView.pageContentViewDidScroll = ^(NSInteger currentIndex, NSInteger beforeIndex, QiPageContentView * _Nonnull pageView) {
menuView.pageScrolledIndex = currentIndex;
NSLog(@"滾動了:以前:%ld 如今:%ld",beforeIndex,currentIndex);
};
複製代碼
小編微信:可加並拉入《QiShare技術交流羣》。字體
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)ui
推薦文章:
iOS 中的界面旋轉
iOS 經常使用佈局方式之Frame
iOS 經常使用佈局方式之Autoresizing
iOS 經常使用佈局方式之Constraint
iOS 經常使用佈局方式之StackView
iOS 經常使用佈局方式之Masonry
iOS UIButton根據內容自動佈局
奇舞週刊atom