自定义滑动控制器

界面逻辑

  • 首页控制器--->scollerview ---> 5个tableVIew控制器-->管理5个title按钮对应的view

代码逻辑

  • 初始化子控制器
  • 首页控制器添加5个对应的子控制器
  • 首页控制器view添加scrollview
  • 设置scrollview的内容大小contentsize为子控制器的个数乘scrollview自身的宽度
  • 添加标题栏view
  • 标题栏上加标题按钮btn和下划线
  • 设置标题按钮btn的点击事件
  • 记录点击的按钮,取消记录点击按钮的选中状态,新点击的按钮设置为选中状态,把心点击的按钮赋值给记录选中的按钮
  • 点击按钮时,下划线滚动到相应的按钮下方,下划线的宽度为按钮的titllable的宽度,中心点为相应按钮的中心点
  • 按钮点击时,对应的scrollview偏移到按钮相对应的位置
  • 当用户点击对应的btn时,才去加载对用的控制器view

代码实现


#import "SHOneViewController.h"

#import "SHTopicOneTBController.h"

#import "SHTopicTwoViewController.h"

#import "SHTopicThreeViewController.h"

#import "SHTopicFourViewController.h"

#import "SHTopicFiveViewController.h"

@interface SHOneViewController ()<UIScrollViewDelegate>

/** 标题栏 */

@property (nonatomic, weak) UIView *titlesView;

/** 标题下划线 */

@property (nonatomic, weak) UIView *titleUnderline;

/** 上一次点击的标题按钮 */

@property (nonatomic, weak) SHTitleBtn *previousClickedTitleBtn;

/** 用来存放所有子控制器view的scrollView */

@property (nonatomic, weak) UIScrollView *scrollView;

@end

@implementation SHOneViewController

- (void)viewDidLoad {

    

    [super viewDidLoad];

    self.view.backgroundColor = kOrangeMainColor;

    // 初始化子控制器

    [self setupAllChildVcs];

    

    // 设置导航条

    [self setupNavBar];

    

    // scrollView

    [self setupScrollView];

    // 标题栏

    [self setupTitlesView];

    

    // 添加第0个子控制器的view

    [self addChildVcViewIntoScrollView:0];

    

}

#pragma mark - Private&Public Methods

/**

 *  设置导航条

 */

- (void)setupNavBar

{

    // 左边按钮

    // 把UIButton包装成UIBarButtonItem.就导致按钮点击区域扩大

    self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithimage:[UIImage imageNamed:@"MainTagSubIcon"] highImage:[UIImage imageNamed:@"MainTagSubIconClick"] target:self action:@selector(game)];

    

    // 右边按钮

    self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithimage:[UIImage imageNamed:@"friendsRecommentIcon"] highImage:[UIImage imageNamed:@"friendsRecommentIcon-click"] target:nil action:nil];

    

    // titleView,cellmorebtnclick,MainTitle

    self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cellmorebtnclick"]];

}

/**

 *  标题栏

 */

- (void)setupTitlesView

{

    

    [self setupTitleButtons];

    [self setupTitleUnderline];

    

}

/**

 *  标题栏按钮

 */

- (void)setupTitleButtons

{

    // 文字

    NSArray *titlesArr = @[@"第一个",@"第二个的",@"三个",@"四",@"第五个"];

    NSUInteger count = titlesArr.count;

    

    // 标题按钮的尺寸

    CGFloat titleBtnW = self.titlesView.sh_width / count;

    CGFloat titleBtnH = self.titlesView.sh_height;

    

    // 创建5个标题按钮

    for (NSInteger i = 0; i < count; i++) {

        SHTitleBtn *titleBtn = [[SHTitleBtn alloc] init];

        titleBtn.tag = i;

        [titleBtn addTarget:self action:@selector(titleBtnClick:) forControlEvents:UIControlEventTouchUpInside];

        [self.titlesView addSubview:titleBtn];

        titleBtn.frame = CGRectMake(i *titleBtnW, 0, titleBtnW, titleBtnH);

        [titleBtn setTitle:titlesArr[i] forState:UIControlStateNormal];

    }

    

}

/*

*  标题下划线

*/

- (void)setupTitleUnderline

{

    //标题按钮

    SHTitleBtn *firstTitleBtn = self.titlesView.subviews.firstObject;

    self.titleUnderline.backgroundColor = [firstTitleBtn titleColorForState:UIControlStateSelected];

 

    // 切换按钮状态

    firstTitleBtn.selected = YES;

    self.previousClickedTitleBtn = firstTitleBtn;

    [firstTitleBtn.titleLabel sizeToFit]; // 让label根据文字内容计算尺寸

    

    self.titleUnderline.sh_width = firstTitleBtn.titleLabel.sh_width + SHMarin;

    self.titleUnderline.sh_centerX = firstTitleBtn.sh_centerX;

}

//初始化子控制器

- (void)setupAllChildVcs

{

    

    [self addChildViewController:[[SHTopicOneTBController alloc] init]];

    [self addChildViewController:[[SHTopicTwoViewController alloc] init]];

    [self addChildViewController:[[SHTopicThreeViewController alloc] init]];

    [self addChildViewController:[[SHTopicFourViewController alloc] init]];

    [self addChildViewController:[[SHTopicFiveViewController alloc] init]];

    

}

// scrollView

- (void)setupScrollView

{

    // 不允许自动修改UIScrollView的内边距

    self.automaticallyAdjustsScrollViewInsets = NO;

    NSUInteger count = self.childViewControllers.count;

    CGFloat scrollViewW = self.scrollView.sh_width;

    self.scrollView.contentSize = CGSizeMake(scrollViewW *count, 0);

    

}

/**

 *  添加第index个子控制器的view到scrollView中

 */

- (void)addChildVcViewIntoScrollView:(NSUInteger)index

{

    UIViewController *childVc = self.childViewControllers[index];

    // 如果view已经被加载过,就直接返回

    if (childVc.isViewLoaded) return;

    // 取出index位置对应的子控制器view

    UIView *childVcView = childVc.view;

    

    //设置子控制器view的frame

    CGFloat scroollViewW = self.scrollView.sh_width;

    childVcView.frame = CGRectMake(index *scroollViewW, 0, scroollViewW, self.scrollView.sh_height);

    //添加子控制器的view到scrollview中

    [self.scrollView addSubview:childVcView];

}

#pragma mark - 按钮点击

/**

 *  点击标题按钮

 */

- (void)titleBtnClick:(SHTitleBtn *)titleButton

{

    // 重复点击了标题按钮

    if (self.previousClickedTitleBtn == titleButton) {

        [[NSNotificationCenter defaultCenter] postNotificationName:SHTitleButtonDidRepeatClickNotification object:nil];

    }

    

    

    // 处理标题按钮点击

    [self dealTitleButtonClick:titleButton];

}

- (void)dealTitleButtonClick:(SHTitleBtn *)titleButton

{

    // 切换按钮状态

    self.previousClickedTitleBtn.selected = NO;

    titleButton.selected = YES;

    self.previousClickedTitleBtn = titleButton;

    

    NSUInteger index = titleButton.tag;

    [UIView animateWithDuration:0.25 animations:^{

       

        //处理下划线

        self.titleUnderline.sh_width = titleButton.titleLabel.sh_width + SHMarin;

        self.titleUnderline.sh_centerX = titleButton.sh_centerX;

        

        //滚蛋scrollview

        CGFloat offsetX = self.scrollView.sh_width *index;

        self.scrollView.contentOffset = CGPointMake(offsetX, self.scrollView.contentOffset.y);

        

    } completion:^(BOOL finished) {

        // 添加子控制器的view

        [self addChildVcViewIntoScrollView:index];

    }];

    

    // 设置index位置对应的tableView.scrollsToTop = YES, 其他都设置为NO

    for (NSUInteger i = 0; i < self.childViewControllers.count; i++) {

        UIViewController *childVc = self.childViewControllers[i];

        // 如果view还没有被创建,就不用去处理

        if (!childVc.isViewLoaded) continue;

        

        UIScrollView *scrollView = (UIScrollView *)childVc.view;

        if (![scrollView isKindOfClass:[UIScrollView class]]) continue;

        

        scrollView.scrollsToTop = (i == index);

    }

    

}

- (void)game

{

    SHFunc;

}

#pragma mark - <UIScrollViewDelegate>

/**

 *  当用户松开scrollView并且滑动结束时调用这个代理方法(scrollView停止滚动的时候)

 */

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

{

    //求出标题按钮的索引

    NSUInteger index = scrollView.contentOffset.x / scrollView.sh_width;

    //点击对应的标题按钮

    SHTitleBtn *titleBtn = self.titlesView.subviews[index];

    [self dealTitleButtonClick:titleBtn];

    

}

#pragma mark - Getters

- (UIScrollView *)scrollView

{

    if (!_scrollView) {

        UIScrollView *scrollView = [[UIScrollView alloc] init];

        scrollView.backgroundColor = [UIColor blueColor];

        scrollView.frame = self.view.bounds;

        scrollView.delegate = self;

        scrollView.showsHorizontalScrollIndicator = NO;

        scrollView.showsVerticalScrollIndicator = NO;

        scrollView.pagingEnabled = YES;

        scrollView.scrollsToTop = NO; // 点击状态栏的时候,这个scrollView不会滚动到最顶部

        [self.view addSubview:scrollView];

        _scrollView = scrollView;

    }

    return _scrollView;

}

- (UIView *)titlesView

{

    if (!_titlesView) {

        UIView *titlesView = [[UIView alloc] init];

        titlesView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];

        titlesView.frame = CGRectMake(0, SHNavMaxY, self.view.sh_width, SHTitlesViewH);

        [self.view addSubview:titlesView];

        _titlesView = titlesView;

    }

    return _titlesView;

}

- (UIView *)titleUnderline

{

    if (!_titleUnderline) {

        

        UIView *titleUnderLine = [[UIView alloc] init];

        titleUnderLine.sh_height = 2;

        titleUnderLine.sh_y = self.titlesView.sh_height - titleUnderLine.sh_height;

        [self.titlesView addSubview:titleUnderLine];

        _titleUnderline = titleUnderLine;

        

    }

    return _titleUnderline;

}

@end


#import "SHTopicBaseTableViewController.h"

@interface SHTopicBaseTableViewController ()

@property (nonatomic, strong) NSMutableArray *topicArr;

@end

@implementation SHTopicBaseTableViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = SHRandomColor;

    self.tableView.contentInset = UIEdgeInsetsMake(SHNavMaxY + SHTitlesViewH, 0, SHTabBarH, 0);

    self.tableView.scrollIndicatorInsets = self.tableView.contentInset;

    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;

    

    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:NSStringFromClass([SHTopicBaseTableViewController class])];

    

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(titleButtonDidRepeatClick) name:SHTitleButtonDidRepeatClickNotification object:nil];

}

/*

 [[SHVideoViewController alloc] init]

 1.SHVideoViewController.xib

 2.SHVideoView.xib

 

 报错信息:-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "SHVideoView" nib but the view outlet was not set.

 错误原因:在使用xib创建控制器view时,并没有通过File's Owner设置控制器的view属性

 解决方案:通过File's Owner设置控制器的view属性为某一个view

 

 报错信息:-[UITableViewController loadView] loaded the "SHVideoView" nib but didn't get a UITableView.

 错误原因:在使用xib创建UITableViewController的view时,并没有设置控制器的view为一个UITableView

 解决方案:通过File's Owner设置控制器的view属性为一个UITableView

 */

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return 15;

 //   return self.topicArr.count;

}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SHTopicBaseTableViewController class]) forIndexPath:indexPath];

    cell.textLabel.text = kFormat(@"%ld", indexPath.row);

    return cell;

}

#pragma mark - 监听

/**

 *  监听titleButton重复点击

 */

- (void)titleButtonDidRepeatClick

{

    [self tabBarButtonDidRepeatClick];

}

/**

 *  监听tabBarButton重复点击

 */

- (void)tabBarButtonDidRepeatClick

{

    // 重复点击的不是首页按钮

    if (self.view.window == nil) return;

    

    // 显示在正中间的不是VideoViewController

    if (self.tableView.scrollsToTop == NO) return;

    

    // 进入下拉刷新

    [self.tableView.mj_header beginRefreshing];

}

- (void)dealloc

{

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

#pragma mark - Getters

- (NSMutableArray *)topicArr

{

    if (!_topicArr) {

        _topicArr = [NSMutableArray array];

    }

    return _topicArr;

}

@end

效果图

图片.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354

推荐阅读更多精彩内容