同一个界面多个子控制器切换视图

先看示例:

EssenceViewController为父控制器。

AllViewController =》全部

VideoViewController =》视频

VoiceViewController =》声音

PictureViewController =》图片

WordViewController =》段子

一、分析

1.顶部菜单栏

大的UIView里包含 一个子UIView(菜单选中的底部指示器)和5个菜单UIButton。

2.中间内容区域是UIScrollView。点击不同菜单切换子控制器,滚动scrollView也要切换,并且菜单栏也跟着切换。

二、详细看代码

//
//  EssenceViewController.m

#import "EssenceViewController.h"
#import "RecommendTagsViewController.h"
#import "AllViewController.h"
#import "VideoViewController.h"
#import "VoiceViewController.h"
#import "PictureViewController.h"
#import "WordViewController.h"

@interface EssenceViewController ()<UIScrollViewDelegate>
/**
 *  标签底部红色指示器
 */
@property(nonatomic,weak)UIView *indicatorView;
/**
 *  当前选中的顶部标签内部的按钮
 */
@property(nonatomic,weak)UIButton *selectedButton;

/**
 *  顶部所有标签的view
 */
@property(nonatomic,weak)UIView *titlesView;

/**
 *  内容视图
 */
@property(nonatomic,weak)UIScrollView *contentView;

@end

@implementation EssenceViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 设置导航栏
    [self setupNav];

    // 初始化所有子控制器
    [self setupChildVces];

    // 设置顶部的标签栏
    [self setupTitlesView];

    // 底部cententView
    [self setupContentView];
}

/**
 *  初始化所有子控制器
 */
- (void)setupChildVces
{
    AllViewController *all = [[AllViewController alloc] init];
    [self addChildViewController:all];

    VideoViewController *video = [[VideoViewController alloc]init];
    [self addChildViewController:video];

    VoiceViewController *voice = [[VoiceViewController alloc] init];
    [self addChildViewController:voice];

    PictureViewController *picture = [[PictureViewController alloc] init];
    [self addChildViewController:picture];

    WordViewController *word = [[WordViewController alloc] init];
    [self addChildViewController:word];
}

/**
 *  底部cententView
 */
- (void)setupContentView
{
    // 不要自动调整inset
    self.automaticallyAdjustsScrollViewInsets = NO;

    UIScrollView *contentView = [[UIScrollView alloc] init];
    contentView.frame = self.view.bounds;
    contentView.delegate = self;
    contentView.pagingEnabled = YES;
    [self.view insertSubview:contentView atIndex:0];
    contentView.contentSize = CGSizeMake(contentView.width * self.childViewControllers.count, 0);
    self.contentView = contentView;

    // 添加第一个控制器的view
    [self scrollViewDidEndScrollingAnimation:contentView];
}

/**
 *  设置顶部的标签栏
 */
- (void)setupTitlesView
{
    // 标签栏整体
    UIView *titlesView = [[UIView alloc] init];
    titlesView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
    titlesView.width = self.view.width;
    titlesView.height = 35;
    titlesView.y = 64;
    [self.view addSubview:titlesView];
    self.titlesView = titlesView;

    // 底部红色指示器
    UIView *indicatorView = [[UIView alloc] init];
    indicatorView.backgroundColor = [UIColor redColor];
    indicatorView.height = 2;
    indicatorView.tag = -1;
    indicatorView.y = titlesView.height - indicatorView.height;
    self.indicatorView = indicatorView;

    // 内部子标签
    NSArray *titles = @[@"全部 ",@"视频",@"声音",@"图片",@"段子"];
    CGFloat height = titlesView.height;
    CGFloat width = titlesView.width / titles.count;

    for (NSInteger i=0; i<titles.count; i++) {
        UIButton *button = [[UIButton alloc] init];
        button.tag = i;
        button.height = height;
        button.width = width;
        button.x = i * button.width;
        [button setTitle:titles[i] forState:UIControlStateNormal];
        [button layoutIfNeeded]; // 强制布局(强制更新子控件的frame)
        [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor redColor] forState:UIControlStateDisabled];
        button.titleLabel.font = [UIFont systemFontOfSize:14];
        [button addTarget:self action:@selector(titleClick:) forControlEvents:UIControlEventTouchUpInside];
        [titlesView addSubview:button];

        // 默认点击了第一个按钮
        if (i == 0) {
            button.enabled = NO;
            self.selectedButton = button;

            // 让按钮内部的label根据文字内容计算尺寸
            [button.titleLabel sizeToFit];
            self.indicatorView.width = button.titleLabel.width;
            self.indicatorView.centerX = button.centerX;
        }
    }

    // indicatorView最后才添加到titlesView里
    // 为了后面从titlesView取button方便
    [titlesView addSubview:indicatorView];
}

/**
 *  点击了标签栏里的按钮
 */
- (void)titleClick:(UIButton *)button
{
    // 修改按钮的状态
    self.selectedButton.enabled = YES;
    button.enabled = NO;
    self.selectedButton = button;

    // 让标签执行动画
    [UIView animateWithDuration:.025 animations:^{
        self.indicatorView.width = self.selectedButton.titleLabel.width;
        self.indicatorView.centerX = self.selectedButton.centerX;
    }];

    // 滚动contentView
    CGPoint offset = self.contentView.contentOffset;
    offset.x = button.tag * self.contentView.width;
    [self.contentView setContentOffset:offset animated:YES];
}

/**
 *  设置导航栏
 */
- (void)setupNav
{
    // 设置导航栏标题
    self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MainTitle"]];

    // 设置导航栏左边的按钮
    self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImage:@"MainTagSubIcon" highImage:@"MainTagSubIconClick" target:self action:@selector(tagButtonClick)];

    // 设置背景色
    self.view.backgroundColor = GlobalBgColor;
}

/**
 *  点击了导航栏左边的按钮
 */
- (void)tagButtonClick
{
    RecommendTagsViewController *vc = [[RecommendTagsViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

#pragma mark - <UIScrollViewDelegate>
/**
 *  滚动完毕就会调用(如果不是人为拖拽scrollView导致滚动完毕,才会调用这个方法
 */
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
    // 当前的索引
    NSInteger index = scrollView.contentOffset.x / scrollView.width;

    // 取出子控制器
    UITableViewController *vc = self.childViewControllers[index];
    vc.view.x = scrollView.contentOffset.x;
    vc.view.y = 0; //设置控制器view的y值为0(默认是20)
    vc.view.height = scrollView.height; //设置控制器view的height值为整个屏幕的高度(默认是比屏幕高度少20)

    // 设置内边距
    CGFloat top = CGRectGetMaxY(self.titlesView.frame);
    CGFloat bottom = self.tabBarController.tabBar.height;
    vc.tableView.contentInset = UIEdgeInsetsMake(top, 0, bottom, 0);
    // 设置滚动条的内边距
    vc.tableView.scrollIndicatorInsets = vc.tableView.contentInset;
    [scrollView addSubview:vc.view];
}

/**
 *  在scrollview停止滑动的时候执行
 */
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    [self scrollViewDidEndScrollingAnimation:scrollView];

    // 点击菜单按钮
    NSInteger index = scrollView.contentOffset.x / scrollView.width;
    [self titleClick:self.titlesView.subviews[index]];
}
@end

三、其他

上面代码还用到一个UIView分类:

//
//  UIView+Extension.h

//  封装frame的修改

#import <UIKit/UIKit.h>

@interface UIView (Extension)

@property(nonatomic,assign)CGSize size;
@property(nonatomic,assign)CGFloat width;
@property(nonatomic,assign)CGFloat height;
@property(nonatomic,assign)CGFloat x;
@property(nonatomic,assign)CGFloat y;
@property(nonatomic,assign)CGFloat centerX;
@property(nonatomic,assign)CGFloat centerY;
/*
 在分类中声明@property,只会生成方法的声明,不会生成方法的实现和带有_下划线的成员变量
 */
@end
//
//  UIView+Extension.m

#import "UIView+Extension.h"

@implementation UIView (Extension)

- (void)setSize:(CGSize)size {
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}
- (CGSize)size {
    return self.frame.size;
}

- (void)setWidth:(CGFloat)width {
    CGRect frame = self.frame;
    frame.size.width = width;
    self.frame = frame;
}
- (CGFloat)width {
    return  self.frame.size.width;
}

- (void)setHeight:(CGFloat)height {
    CGRect frame = self.frame;
    frame.size.height = height;
    self.frame = frame;
}
- (CGFloat)height {
    return self.frame.size.height;
}

- (void)setX:(CGFloat)x {
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}
- (CGFloat)x {
    return self.frame.origin.x;
}

- (void)setY:(CGFloat)y {
    CGRect frame = self.frame;
    frame.origin.y = y;
    self.frame = frame;
}
- (CGFloat)y {
    return  self.frame.origin.y;
}

- (void)setCenterX:(CGFloat)centerX
{
    CGPoint center = self.center;
    center.x = centerX;
    self.center = center;
}

- (CGFloat)centerX
{
    return self.center.x;
}

- (void)setCenterY:(CGFloat)centerY
{
    CGPoint center = self.center;
    center.y = centerY;
    self.center = center;
}

- (CGFloat)centerY
{
    return self.center.y;
}
@end
时间: 2024-10-25 20:56:56

同一个界面多个子控制器切换视图的相关文章

学习方法和阶段介绍 、 iOS界面开发引入 、 构造第一个App 、 视图控制器和视图 、 控件与事件 、 InterfaceBuilder

1 创建并运行第一个App 1.1 问题 使用Xcode创建一个App项目,该应用实现功能在界面上显示Hello World标签,在模拟器中的运行结果如图-1所示: 图-1 1.2 方案 分析图-1,首先使用Xcode创建一个Single ViewApplicaton应用,起名为MyFirstApp,如图-2所示: 图-2 然后删除Xcode的导航栏里只保留TRAppDelegate.h文件和TRAppDelageat.m文件,其他代码文件.storyboard文件以及xib文件删除,如图-3所

自定义视图控制器切换(iOS)

在iOS开发过程中,通常我们会使用UINavigationController,UITabbarController等苹果提供的视图控制器来切换我们的视图.在iOS5之前,如果要自定义容器视图控制器很麻烦,比如你要考虑到子视图的生命周期,当设备旋转时的情况等,好在iOS5中苹果提供了添加视图控制器(addChildViewController)等管理视图控制器的API,这样我们就能使用此API来自定义自己的视图控制器了,这篇文章只要介绍如何使用此API实现UITabbarController的基

003-多视图控制器切换

多视图控制器切换 1.容器的概念 • 一个iOS的app很少只由一个ViewController组成,除非这个app极其简单.当app中有多个ViewController时,就需要对这些ViewController进行管理 • 容器的概念:负责展示一个或者多个ViewController,并管理这些 ViewController的生命周期 • ?部分容器本身也是一个ViewController,被容器管理的控制器称为容器的?控制器(childViewController),?容器被称为父控制器(

iOS_16_控制器切换_modal_代码方式

最终效果图: main.storyboard BeyondViewController.h // // BeyondViewController.h // 16_控制器切换方式1_Modal_通过代码方式 // // Created by beyond on 14-7-30. // Copyright (c) 2014年 com.beyond. All rights reserved. // #import <UIKit/UIKit.h> @interface BeyondViewContro

1.自定义控制器切换&lt;一&gt;

一.自定义控制器切换:在同一个控制器上,展示不同的控制器,类似于tabbar一样 二.怎么做?(问题解决步骤) 1.创建若干控制器:OneViewController TwoViewController ..... 2.定义一个现实的控制器: //定义: @property (nonatomic, weak) UIViewController *showingVc; self.childViewControllers= @[ [[ZSOneViewController alloc] init],

IOS-Storyboard控制器切换之Modal(1)

Modal模式是指模态切换,新开的界面会挡住之前的界面,使之不能获取焦点. 创建一个singleView模板的程序,打开storyboard文件,拖动2个UIViewController到界面中,按住control,从按钮处直接拖动到第2个vc如图: 然后放开,选择modal模式:  意思就是只要点击按钮 就能从下到上弹出第2个界面 对于每个uiviewController,都可以设置其所对应的文件, 其头部显示的文字可在右边面板中设置: IOS-Storyboard控制器切换之Modal(1)

IOS-Storyboard控制器切换之Push(2)

Push是指头部为导航,底部为内容的控制器,点击顶部返回跳转于各个界面之间,如图正在跳转中的页面 从first>second页面 至于如何建立项目,storyboard不在赘述,Push比Modal多了一个控制器,各个页面的跳转(代码)实际上都是通过控制器跳转,该控制器为 UINavigatorViewController或其子类. 并且 设置了UINavigatorViewController后 还要设置其rootViewController.这相当于该UINavigatorViewContr

【Asp.Net Core】二、添加控制器和视图

控制器Controller 在添加控制器前,我们先看下它为我们自动生成的一些Controller,我们看下AccountController.cs 来看下登录验证方法Login !!!跟以前的写法好像很多地方不一样?async这个应该是异步 干什么用的呢 ? Task<IActionResult> 是什么? var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.Remem

ios开发级联菜单(利用父子控制器--两个菜单封装为两个子控制器来实现)

一:1:级联菜单可以使用两个tableView来实现,也可以利用父子控制器,两个控制器来实现,根视图控制器作为两个控制器的父控制器,来管理两个子控制器.2:将左右菜单分别交给两个控制器去管理,对于一些复杂的业务逻辑,涉及大量回调操作,业务逻辑也要相对复杂,则不建议采取封装成view去处理,最好还是利用一个控制器去管理其内部复杂的业务逻辑,具体做法就是:利用父子控制器,将子控制器交由父控制器去管理,将子控制器的view添加到父控制器的view上.效果如图: 二:代码 1:根控制器代码:添加两个子控