平時開發APP中關於此功能仍是比較常常碰到,本實例借用三個開源的插件,並對其中一個進行修改調整實現出想要的效果;本文重點介紹修改的內容跟三個插件的運用,這三個插件還能夠各自擴展到其它項目的運用;git
效果圖:github
![]() |
![]() |
![]() |
![]() |
本實例實現的效果:頂部的滾動菜單顯示出全部的類型,每一個類型都對應一種展現,能夠在頂部的菜單進行滾動,內容區域也會跟着改變,或者是內容區域左右滑動,則頂部的滾動菜單也會跟着更改,頂部菜單的最右邊有一個展現更多菜單的效果,用於彈出一個帶箭頭的窗;(源代碼下載)atom
帶箭頭的彈出視圖插件 :https://github.com/xiekw2010/DXPopoverspa
內容區域滑動插件:https://github.com/nicklockwood/iCarousel.net
及Codint.Net開源項目中的XTSegmentControl菜單滾動效果,此實例對它進行的修改插件
1:插件及頁面的初始化code
#import "ViewController.h" #import "oldChildVewController.h" #import "ChildViewController.h" #import "newChildVewController.h" #import "XTSegmentControl.h" #import "iCarousel.h" #import "Masonry.h" #import "menuCollectionViewCell.h" #import "DXPopover.h" #define kScreen_Height [UIScreen mainScreen].bounds.size.height #define kScreen_Width [UIScreen mainScreen].bounds.size.width #define kMySegmentControl_Height 44.0 @interface ViewController ()<UICollectionViewDataSource, UICollectionViewDelegate,iCarouselDataSource, iCarouselDelegate> @property (strong, nonatomic) XTSegmentControl *mySegmentControl; @property (strong, nonatomic) NSArray *titlesArray; @property (strong, nonatomic) iCarousel *myCarousel; @property(assign,nonatomic)NSInteger curSelectIndex; @property (nonatomic, strong) DXPopover *popover; @property(assign,nonatomic)CGFloat popoverWidth; @property (strong, nonatomic) UICollectionView *myCollectionView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor=[UIColor whiteColor]; //初始化一個popover 用於彈窗效果的展現 self.popover = [DXPopover new]; _popoverWidth = kScreen_Width-20; __weak typeof(self) weakSelf = self; CGRect frame=self.view.bounds; //內容區滾動效果插件 self.myCarousel = ({ iCarousel *icarousel = [[iCarousel alloc] initWithFrame:frame]; icarousel.dataSource = self; icarousel.delegate = self; icarousel.decelerationRate = 1.0; icarousel.scrollSpeed = 1.0; icarousel.type = iCarouselTypeLinear; icarousel.pagingEnabled = YES; icarousel.clipsToBounds = YES; icarousel.bounceDistance = 0.2; [self.view addSubview:icarousel]; [icarousel mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(64, 0, 0, 0)); }]; icarousel; }); //添加滑塊 __weak typeof(_myCarousel) weakCarousel = _myCarousel; self.mySegmentControl = [[XTSegmentControl alloc] initWithFrame:CGRectMake(0, 20, kScreen_Width, 44) Items:self.titlesArray showRightButton:YES selectedBlock:^(NSInteger index) { weakSelf.curSelectIndex=index; weakCarousel.currentItemIndex=index; [weakSelf.myCollectionView reloadData]; }]; //當有右邊鍵時 其響應的事件 self.mySegmentControl.rightButtonBlock= ^(CGRect rightButtomRect) { //彈出插件的運用 [weakSelf updateMyViewFrame]; CGPoint startPoint = CGPointMake(CGRectGetMidX(rightButtomRect), CGRectGetMaxY(rightButtomRect) + 25); [weakSelf.popover showAtPoint:startPoint popoverPostion:DXPopoverPositionDown withContentView:weakSelf.myCollectionView inView:weakSelf.view]; }; [self.view addSubview:self.mySegmentControl]; //用於展現彈出效果裏面的列表 if (!_myCollectionView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; self.myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,50,kScreen_Width-40, 200) collectionViewLayout:layout]; self.myCollectionView.backgroundColor=[UIColor whiteColor]; self.myCollectionView.showsHorizontalScrollIndicator=NO; self.myCollectionView.showsVerticalScrollIndicator=NO; [self.myCollectionView registerClass:[menuCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([menuCollectionViewCell class])]; self.myCollectionView.dataSource = self; self.myCollectionView.delegate = self; } }
其中XTSegmentControl爲頂部菜單的建立,其中showRightButton是爲了擴展是否顯示右邊更多菜單的事件,並把事件的響應Block到頁面進行實現,此事例就是響應彈出窗的效果展示,iCarousel爲內容區域的滑動效果,DXPopover彈出窗的效果,UICollectionView則用於彈出窗裏面的菜單列表blog
//popver一些屬性的設置 -(void)updateMyViewFrame { CGRect tableViewFrame = self.myCollectionView.frame; tableViewFrame.size.width = _popoverWidth; self.myCollectionView.frame = tableViewFrame; self.popover.contentInset = UIEdgeInsetsZero; self.popover.backgroundColor = [UIColor whiteColor]; } #pragma mark - Getter/Setter - (NSArray*)titlesArray { if (nil == _titlesArray) { _titlesArray = @[@"所有", @"互動", @"開源控件", @"文檔", @"代碼", @"高爾夫",@"主題",@"軟件",@"股票"]; } return _titlesArray; }
2插件iCarouselDataSource, iCarouselDelegate代碼實現事件
#pragma mark iCarousel M - (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel{ return [self.titlesArray count]; } //滾動時內容視圖的加載 - (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view{ [_mySegmentControl setScrollOffset:index]; UIViewController *childContrll=[[ChildViewController alloc]init]; UIView *my=childContrll.view; switch (index) { case 0: { my.backgroundColor=[UIColor blackColor]; break; } case 1: { my.backgroundColor=[UIColor redColor]; break; } default: childContrll=[[newChildVewController alloc]init]; break; } return childContrll.view; } //滾動時 下劃線的位置更新 - (void)carouselDidScroll:(iCarousel *)carousel{ if (_mySegmentControl) { [_mySegmentControl moveIndexWithProgress]; } } //更新滾動其它兩個控件的位置 - (void)carouselCurrentItemIndexDidChange:(iCarousel *)carousel{ self.curSelectIndex=carousel.currentItemIndex; [self.myCollectionView reloadData]; if (_mySegmentControl) { _mySegmentControl.currentIndex = carousel.currentItemIndex; } }
注意:內容區域的視圖加載,及其滑動所響應的事件處理,原來的XTSegmentControl對於菜單字數不一樣時下劃線會出現一些異常,本實例對它進行修改了;ip
3:列表UICollectionViewDataSource, UICollectionViewDelegate功能的實現
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return self.titlesArray.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ menuCollectionViewCell *ccell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([menuCollectionViewCell class]) forIndexPath:indexPath]; NSString *model=[self.titlesArray objectAtIndex:indexPath.row]; ccell.curMenuModel=model; if (self.curSelectIndex==indexPath.row) { ccell.backgroundColor=[UIColor blueColor]; } else { ccell.backgroundColor=[UIColor whiteColor]; } return ccell; } - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ return CGSizeMake((kScreen_Width-40)/3, 40); } - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{ return UIEdgeInsetsZero; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{ return 5; } - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{ return 5; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ self.curSelectIndex=indexPath.row; //兩個滾動的位置更新 _myCarousel.currentItemIndex=self.curSelectIndex; [_mySegmentControl selectIndex:self.curSelectIndex]; //隱藏彈出窗 [self.popover dismiss]; }
注意:主要是在實現點擊時滾動位置跟內容的區域要進行調整,並把彈出窗進行收縮的操做;
4:XTSegmentControl下劃線調整
- (void)moveIndexWithProgress { CGRect origionRect = [_itemFrames[_currentIndex] CGRectValue]; CGRect origionLineRect = CGRectMake(CGRectGetMinX(origionRect) + XTSegmentControlHspace, CGRectGetHeight(origionRect) - XTSegmentControlLineHeight, CGRectGetWidth(origionRect) - 2 * XTSegmentControlHspace, XTSegmentControlLineHeight); //增長下劃線滾動的效果 [UIView animateWithDuration:0.5 animations:^{ _lineView.frame = origionLineRect; } completion:^(BOOL finished) { }]; }
5:擴展XTSegmentControl沒有右邊更多菜單的效果
self.mySegmentControl = [[XTSegmentControl alloc] initWithFrame:CGRectMake(0, 20, kScreen_Width, 44) Items:self.titlesArray showRightButton:NO selectedBlock:^(NSInteger index) { weakSelf.curSelectIndex=index; weakCarousel.currentItemIndex=index; [weakSelf.myCollectionView reloadData]; }];
效果圖:
![]() |
![]() |
6:補充關於popover這個插件的若是有模態時,它會出現整個屏幕,若是不想要這種效果,能夠自個設置一個背景視圖效果,把popover模態效果關掉(self.popover.maskType=DXPopoverMaskTypeNone; //設置默認是否有模態);下面是寫的一個實例:
- (void)updateTableViewFrame { CGRect tableViewFrame = self.tableView.frame; tableViewFrame.size.width = _popoverWidth; self.tableView.frame = tableViewFrame; self.popover.contentInset = UIEdgeInsetsZero; self.popover.maskType=DXPopoverMaskTypeNone; //設置默認是否有模態 self.popover.backgroundColor = [UIColor whiteColor]; } - (void)showPopover { [self updateTableViewFrame]; [self changeShowing]; CGPoint startPoint = CGPointMake(CGRectGetMidX(self.btn.frame), CGRectGetMaxY(self.btn.frame) + 5); [self.popover showAtPoint:startPoint popoverPostion:DXPopoverPositionDown withContentView:self.tableView inView:self.tabBarController.view]; __weak typeof(self) weakSelf = self; self.popover.didDismissHandler = ^{ [weakSelf bounceTargetView:weakSelf.btn]; }; } //自行增長一個背影層 - (UIView *)myTapBackgroundView{ if (!_myTapBackgroundView) { _myTapBackgroundView = ({ UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 64, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height-64)]; view.backgroundColor = [UIColor clearColor]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(changeShowing)]; [view addGestureRecognizer:tap]; view; }); } return _myTapBackgroundView; } - (void)changeShowing{ if (self.isShowing) {//隱藏 [UIView animateWithDuration:0.3 animations:^{ self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0]; } completion:^(BOOL finished) { [self.popover dismiss]; [self.myTapBackgroundView removeFromSuperview]; self.isShowing = NO; }]; }else{//顯示 [self.view addSubview:self.myTapBackgroundView]; [UIView animateWithDuration:0.3 animations:^{ self.myTapBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2]; } completion:^(BOOL finished) { self.isShowing = YES; }]; } }