WyhPageControl
A customizable pageControl携龟,support many styles including custom image蒸健、tintcolor 头朱,etc
Github
https://github.com/XiaoWuTongZhi/WyhPageControl
CocoaPods Support
pod search WyhPageControl
pod 'WyhPageControl', '~> 1.0.0'
前段時間項目整體UI及交互大改运悲,需要準備封裝很多UI組件,借著這個機會封裝了不少實用組件项钮,這里給大家介紹一款支持自定義的pageControl
吧(其實我就是來騙star的班眯,github上很少有人去封裝pageControl希停,有一個上千star的pageControl也已經(jīng)好多年沒維護了,因為太簡單了署隘,但是今天介紹的不僅僅是一個第三方組件脖苏,更多的教大家如何去封裝一個自定義UI的方式方法)。
傳統(tǒng)意義的UIPageControl
想必根本滿足不了廣大開發(fā)同胞的使用了定踱,項目越來越遠離Native
頁面棍潘,也著實讓我們很頭疼!
PageControl
封裝起來很簡單崖媚,因為它的功能也很簡單亦歉,無非是多一些系統(tǒng)沒有的自定義小點點的功能罷了,不過封裝思想很重要畅哑。從工作至今肴楷,封裝過很多組件,其實思想都大同小異荠呐,下面我們來分析一波代碼H琛(敲黑板了奧)
封裝思想
這里僅談?wù)?code>UI組件的封裝,日后我還會出一些針對業(yè)務(wù)模塊的封裝思想泥张。
UI組件封裝都大同小異呵恢,像Native原生
的tableView
就是一個很好的例子,支持自定義最大化的組件往往并不是暴露很多的自定義屬性媚创,而是直接用代理回調(diào)的方式渗钉,讓使用者去自定義這個組件的樣式,而不是已定的樣式钞钙。這一點是很重要的鳄橘,你要清楚你所暴露的自定義屬性永遠沒有辦法滿足所有人的需求,因此代理回調(diào)很重要芒炼。讓我們通過分析WyhPageControl
來理解如何通過代理回調(diào)來自定義UI組件:
WyhPageControl代碼分析
WyhPageControl
設(shè)計之初就是想自定義pageControl的小圓點樣式瘫怜、間距、圓點尺寸等本刽,那么完全可以仿照tableView
的代理模式鲸湃,將小圓點作為cell
,通過代理回調(diào)的方式盅安,讓用戶去自定義唤锉,當然還是要暴露一些自定義屬性的世囊,最好維持UIPageControl
的屬性不變别瞭,起碼使用起來更舒服。
WyhPageControl
作為主體View株憾,WyhPageControlDot
作為cell蝙寨,內(nèi)部實現(xiàn)一點要分清楚哪些是支持reload
的方法:
初始化方法晒衩,采用block回調(diào)自定義配置使代碼塊更聚合,block內(nèi)無需考慮循環(huán)引用墙歪,dataSource
和delegate
一定要分清听系,參考UITableView
。
- (instancetype)initWithDataSource:(id<WyhPageControlDataSource>)dataSource
Delegate:(id<WyhPageControlDelegate>)delegate
WithConfiguration:(void (^)(WyhPageControl *))configuration {
if (self = [self init]) {
if(configuration) configuration(self);
_dataSource = dataSource;
_delegate = delegate;
[self reloadUI];
}
return self;
}
創(chuàng)建協(xié)議代理虹菲,來高度自定義你的dot
靠胜,dataSource
和delegate
一定要分清并分開,結(jié)構(gòu)一定要嚴格規(guī)范毕源,為了可拓展性和便于維護:
@class WyhPageControl;
@protocol WyhPageControlDataSource <NSObject>
@optional
- (WyhPageControlDot *)pageControl:(WyhPageControl *)pageControl dotForIndex:(NSInteger)index;
@end
@protocol WyhPageControlDelegate <NSObject>
@optional
- (void)pageControl:(WyhPageControl *)pageControl didClickForIndex:(NSInteger)index;
@end
初始化一些屬性浪漠,確保所有屬性都有默認值。
- (void)initializeConfig {
self.clipsToBounds = YES;
_numberOfPages = 0;
_currentPage = 0;
_hidesForSinglePage = NO;
_pageIndicatorTintColor = [UIColor lightGrayColor];
_currentPageIndicatorTintColor = [UIColor darkGrayColor];
_backgroundColor = [UIColor clearColor];
_borderWidth = 0.f;
_cornerRadius = 0.f;
_borderColor = [UIColor darkGrayColor];
_backgroundImage = nil;
_showReloadActivityIndicator = YES;
// const
_dotLeftMargin = 15.f;
_dotTopMargin = 8.f;
_dotSpace = 8.f;
// ui
_coverView = [[UIView alloc]init];
_coverImageView = [[UIImageView alloc]init];
_indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
[_indicator sizeToFit];
[self addSubview:_coverView];
[self addSubview:_coverImageView];
[self addSubview:_indicator];
}
并重寫這些屬性的setter
方法霎褐,使其重新set的時候會發(fā)生樣式的變化址愿。
#pragma mark - Setter
- (void)setNumberOfPages:(NSUInteger)numberOfPages {
_numberOfPages = numberOfPages;
}
- (void)setHidesForSinglePage:(BOOL)hidesForSinglePage {
_hidesForSinglePage = hidesForSinglePage;
}
- (void)setBackgroundColor:(UIColor *)backgroundColor {
_backgroundColor = backgroundColor;
_coverView.backgroundColor = backgroundColor;
}
- (void)setPageIndicatorTintColor:(UIColor *)pageIndicatorTintColor {
_pageIndicatorTintColor = pageIndicatorTintColor;
}
- (void)setCurrentPageIndicatorTintColor:(UIColor *)currentPageIndicatorTintColor {
_currentPageIndicatorTintColor = currentPageIndicatorTintColor;
}
- (void)setDotLeftMargin:(CGFloat)dotLeftMargin {
_dotLeftMargin = dotLeftMargin;
}
- (void)setDotTopMargin:(CGFloat)dotTopMargin {
_dotTopMargin = dotTopMargin;
}
- (void)setDotSpace:(CGFloat)dotSpace {
_dotSpace = dotSpace;
}
- (void)setBorderWidth:(CGFloat)borderWidth {
_borderWidth = borderWidth;
self.layer.borderWidth = borderWidth;
}
- (void)setBorderColor:(UIColor *)borderColor {
_borderColor = borderColor;
self.layer.borderColor = borderColor.CGColor;
}
- (void)setBackgroundImage:(UIImage *)backgroundImage {
_backgroundImage = backgroundImage;
_coverImageView.image = backgroundImage;
}
- (void)setCornerRadius:(CGFloat)cornerRadius {
_cornerRadius = cornerRadius;
self.layer.cornerRadius = cornerRadius;
}
通過dataSource
指定的樣式來創(chuàng)建dot
,visibleDots
是用來存放所有dot
的數(shù)組冻璃,這里一定要判斷代理人是否給回調(diào)了dot
响谓,如果沒有自定創(chuàng)建一個默認的dot
,并通過用戶設(shè)置的間距等屬性省艳,設(shè)置dot
的位置娘纷,并添加點擊手勢。(這里要注意的是跋炕,這個initDots方法一定是一個支持reload的失驶,使用者可能會根據(jù)不同情況返回不同的dot
,這點必須清楚)
- (void)initDots {
[self.visibleDots makeObjectsPerformSelector:@selector(removeFromSuperview)];
self.visibleDots = [NSMutableArray new];
WyhPageControlDot *lastDot ;
for (int i = 0; i < _numberOfPages; i++) {
WyhPageControlDot *dot = nil;
if (![self.dataSource respondsToSelector:@selector(pageControl:dotForIndex:)]) {
dot = [[WyhPageControlDot alloc]init];
dot.unSelectTintColor = _pageIndicatorTintColor;
dot.selectTintColor = _currentPageIndicatorTintColor;
}else {
dot = [self.dataSource pageControl:self dotForIndex:i];
}
dot.hidden = _isReloading;
// frame
CGFloat dotX = (!lastDot)?_dotLeftMargin:CGRectGetMaxX(lastDot.frame)+_dotSpace;
dot.frame = CGRectMake(dotX, 0, dot.size.width, dot.size.height);
// gesture
UITapGestureRecognizer *tapges = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(pageControlDotTapAction:)];
[dot addGestureRecognizer:tapges];
[self addSubview:dot];
[self.visibleDots addObject:dot];
lastDot = dot;
}
[self bringSubviewToFront:self.indicator];
[self configDotsUI];
[self autoConfigBounds];
[self configAllDotsCenterY]; // must after autoConfigBounds.
}
增加與之對應(yīng)的reload
方法拋給用戶枣购,同tableView一樣嬉探,這個reload
方法執(zhí)行后,會重新調(diào)用所有代理回調(diào)及自定義屬性棉圈,保證更新機制涩堤,這也是整個UI自定義組件封裝最重要的環(huán)節(jié)!(WyhPageControl增加了一個轉(zhuǎn)圈圈的菊花分瘾,用戶可以定義顯示與隱藏當在reload時)
- (void)reloadData {
[self reloadUI];
}
- (void)reloadUI {
[self showActivity:YES];
[self checkHiddenIfNeeded];
[self configPageControlUI];
[self initDots];
[self showActivity:NO];
}
最后就是當點擊dot
時胎围,回調(diào)代理方法:
- (void)pageControlDotTapAction:(UITapGestureRecognizer *)tapGes {
WyhPageControlDot *dot = (WyhPageControlDot *)tapGes.view;
NSInteger index = [self.visibleDots indexOfObject:dot];
if (index == NSNotFound) {
NSAssert(NO, @"Can't found this tap dot !");
return;
}
[self moveToIndex:index];
// call back
if ([self.delegate respondsToSelector:@selector(pageControl:didClickForIndex:)]) {
[self.delegate pageControl:self didClickForIndex:index];
}
}
每一個dot
有兩種狀態(tài)對應(yīng)兩種UI樣式,選中和未選中德召,目前僅支持自定義 選中/未選中 顏色白魂、背景圖片。
@interface WyhPageControlDot : UIView
@property(nonatomic, strong) UIColor *unSelectTintColor;
@property(nonatomic, strong) UIColor *selectTintColor;
@property (nonatomic, strong) UIImage *unselectImage;
@property (nonatomic, strong) UIImage *selectImage;
@property (nonatomic, assign) CGSize size; // default is (20,20)
@property (nonatomic, strong) UIColor *borderColor; //defult is nil;
@property (nonatomic, assign) CGFloat borderWidth; // default is 0.f;
@property (nonatomic, assign) CGFloat conerRadius; //default is 10.f
- (void)setSelected:(BOOL)selected;
@end
dot
如果不滿足你的需求上岗,同cell一樣福荸,你也可以自定義繼承這個dot
的Base類,來自定義你的圓點肴掷,這里就不舉例子了敬锐。
使用方法請大家去demo
中自行查看背传,很簡單,同tableView
類似台夺。
總結(jié)
通過分析這個簡單的組件径玖,希望朋友們對于UI組件封裝思想能更加理解,最后希望喜歡的朋友們到GitHub
幫點個star
颤介,歡迎各種好朋友梳星,一起來探討、研究滚朵,接下來我會出一些其他方面的丰泊,不只是UI層次的,簡書這個平臺挺好始绍,(但就是有時太懶)瞳购,大家共勉吧。
開啟傳送門:WyhPageControl