美文网首页iPadiOS学习iPad 资料
iPad开发之自定义实现分屏控制器的功能

iPad开发之自定义实现分屏控制器的功能

作者: passionHan | 来源:发表于2016-05-24 16:33 被阅读1612次

    前言

    最近公司需要开发iPad版的应用程序,项目中要实现分屏控制器的功能,之前有了解到使用UISplitViewController可以实现分屏的功能,当时查了查资料,感觉挺简单的,但是随着研究的深入,发现并不是那么容易的,由于网上关于UISplitViewController的使用教程并不多,自定义实现分屏功能的教程就更少了,所以接下来我将把这几天对UISplitViewController的研究和自定义实现分屏控制器的功能的Demo分享给大家,希望能帮助到有这方面困惑的朋友。

    使用系统的UISplitViewController

    Demo中的第一个target是使用的UISplitViewController,通过storyboard实现,系统的UISplitViewController挺简单的,实现步骤:

    1. 在storyboard中添加一个UISplitViewController控制器,给DetailViewController包装一个导航控制器,这里在连线的时候要注意,要和splitViewController建立关系,选择detail view controller。
    Paste_Image.png

    2.新建一个控制器MainViewController继承自UISplitViewController,MasterTableViewController继承自UITableViewController,DetailViewController继承自UIViewController,并把相关控制器和storyboard中的相关联。

    3.在MasterTableViewController中编写一个协议,主要思路就是MainViewController成为MasterTableViewController的代理,实现协议方法,从而和DetailViewController交互。

    @protocol masterTableViewControllerDelegate <NSObject>
    
    - (void)masterTableViewController:(MasterTableViewController *)masterVC didSelectedRow:(SingleModel *)singleModel;
    
    @end
    

    在MasterTableViewController中的tableView行点击事件中,调用代理方法,传递数据

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        
        if ([self.delegate respondsToSelector:@selector(masterTableViewController:didSelectedRow:)]) {    
            GroupModel *groupModel = self.groupModel[indexPath.section];
            [self.delegate masterTableViewController:self didSelectedRow:groupModel.typeList[indexPath.row]];
        }
    }
    

    在MainViewController中,设置当前控制器为MasterTableViewController的代理,实现协议方法

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        //获取到导航控制器对象
        UINavigationController *masterNav = [self.childViewControllers firstObject];
        
        //获取到MasterTableViewController的对象
        MasterTableViewController *master = [masterNav.childViewControllers firstObject];
        
        master.delegate = self;
    }
    /**
     *  masterTableViewController的代理方法
     */
    - (void)masterTableViewController:(MasterTableViewController *)masterVC didSelectedRow:(SingleModel *)singleModel{
        
        UINavigationController *detailNav = [self.childViewControllers lastObject];
        DetailViewController *detail = [detailNav.childViewControllers firstObject];
        
        detail.singleModel = singleModel;
        
        [detailNav popToRootViewControllerAnimated:YES];
    }
    

    重写DetailViewController的属性singleModel的setter方法就能实现和MasterTableViewController交互了

    - (void)setSingleModel:(SingleModel *)singleModel{
        
        _singleModel = singleModel;
        
        self.nameView.text = singleModel.subjectName;
    }
    

    通常情况下,详情界面也会是一个tableView,在重写的singleModel中获取到上一界面传来的值,让当前控制器的tableView reloadData就可以了。

    自定义实现分屏的功能

    这个是今天要介绍的重点,因为有的时候系统的UISplitViewController并不能满足项目的需求,UISplitViewController只能做为程序窗口的根视图,当程序中需要使用UITabBarController或者UINavigationController来切换到分屏控制器的时候,并不能到达我们的目的。
    可以看一下官网对UISplitViewController的介绍

    主要的一个截图

    Paste_Image.png

    大体的意思就是分屏控制器不能进入导航的栈中(也就是不能通过导航控制器跳转),不推荐将分屏控制器做为某个控制器的子控制器,通常是做为程序窗口的根视图。

    那如果需求是: 在主界面需要跳转到分屏控制器改怎么办呢?

    这里有一种思路就是在主界面放一个按钮,在按钮的点击方法里面切换window的根视图。这个不是今天介绍的重点,就不在这里讨论了。

    重点是---怎么自定义控制器具有分屏显示的功能(结合UITabBarController)

    思路是新建三个控制器,分别是主控制器、左侧显示的列表控制器和右侧显示的详情控制器,将列表控制器和详情控制器的View添加到主控制器的View上,让主控制器成为列表控制器的代理,实现相应的协议方法从而和详情控制器就行交互。大体的思路和上面提到的使用系统的UISplitViewController差不多,主要的不同就是没有使用UISplitViewController,而是自定义的UIViewController,主要看一下自定义控制器中的代码。

    添加两个导航控制器的属性

    @property (nonatomic, strong) UINavigationController *masterNav;
    @property (nonatomic, strong) UINavigationController *detailNav;
    

    在viewDidLoad中初始化列表控制器和详情控制器,并添加到主控制界面上。

    - (void)viewDidLoad {
        [super viewDidLoad];
    
       // self.navigationController.navigationBarHidden = YES;
        
        HZYMasterViewController *masterVC = [HZYMasterViewController new];
        self.masterNav = [[UINavigationController alloc] initWithRootViewController:masterVC];
        [self addChildViewController:self.masterNav];
        [self.view addSubview:self.masterNav.view];
        
        HZYDetailViewController *detailVC = [HZYDetailViewController new];
        self.detailNav = [[UINavigationController alloc] initWithRootViewController:detailVC];
        [self addChildViewController:self.detailNav];
        [self.view addSubview:self.detailNav.view];
        
        masterVC.delegate = self;
    }
    

    实现协议方法

    - (void)masterViewController:(HZYMasterViewController *)masterVC didSelectedRowInSection:(NSInteger)section{
        
        HZYDetailViewController *detailVC = [self.detailNav.childViewControllers firstObject];
        
        [self.detailNav popToRootViewControllerAnimated:YES];
        
        //向detailVC传递点击的Section用来区分detailVC中tableViewCell的显示样式
        [detailVC putSection:section];
    }
    

    核心的方法,当控制器的View的子视图重新布局时调用,用来布局子视图。

    - (void)viewWillLayoutSubviews{
            [_masterNav.view mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.top.equalTo(@64);
                make.left.equalTo(@70);
                make.width.equalTo(kMasterWidth);
                make.bottom.equalTo(@0);
            }];
            
            [_detailNav.view mas_remakeConstraints:^(MASConstraintMaker *make) {
                make.top.bottom.equalTo(_masterNav.view);
                make.right.equalTo(self.view.mas_right);
                make.left.equalTo(_masterNav.view.mas_right);
            }];
    }
    

    DetailViewController在putSection方法的实现中获得index,工具类通过index获得相应模型数据,刷新tableView

    - (void)putSection:(NSInteger)section{
        
        _section = section;
        
        __weak typeof (self) weakSelf = self;
        
        //获取点击Section的模型数据,为了方便这里每个Section中的行都是一个模型数据,如果获取网络数据的话要更改工具类中的方法,视情况而定!
        [Tool getDataWithSection:section successBlock:^(NSMutableArray *modelArray) {
            
            weakSelf.modelArray = modelArray;
            
            [weakSelf.tableView reloadData];
        }];
    }
    
    Demo介绍

    Demo分为两个target,一个是通过系统UISplitViewController结合storyboard实现的,一个是自定义控制器纯代码实现的。

    Paste_Image.png
    工程中添加两个target的遇到的坑

    之前并没有在一个工程中添加过两个target,这次在两个target下coding遇到最多的问题就是

    Paste_Image.png

    一般这种问题就是编译的问题,找不到编译的源文件,解决方法就是在工程的target->Build Phases->Compile Sources,添加报错的.m文件,重新编译就OK了!
    为什么会产生这种错误呢?主要就是在新建类的时候没有选中相应的target

    Paste_Image.png

    还有一种解决方案,选中报错的.m文件,展开实用工具(配合IB实用的那个栏目),点击第一个(file inspector),找到下面的Target Membership,勾选上相应的target。

    Paste_Image.png
    结语:

    第一次在简书上面发表文章,希望我这几天的研究能够帮助到有这方面困惑的朋友,谢谢大家的支持。

    最近很欣赏薛之谦说的一句话:在这个时代根本就没有怀才不遇, 关键是你真的必须具备才华 所以请你一定要强大自己!对于我们iOS开发来说,市场已经进入饱和期了(甚至有人调侃为iOS烂大街),很多人抱怨工作不好找,现在的市场需要的不再是只会写写界面,只会上网复制粘贴代码的开发者,所以你一定要强大自己,等你足够强大了,好的工作自然就来了!

    最后献上我的Demo

    相关文章

      网友评论

      • EI_Rey:UISplitViewController是可以作为UITabBarController的自控制器的,不能作为UINavigationController的自控制器,开发过程中我遇到了一个莫名其妙的问题,我是通过纯代码实现的,UISplitViewController的主视图是UIviewcontroller,自定义的按钮实现切换详细视图,问题就出现在详细视图控制器上,详细视图如果是通过storyboard来写的在详细视图中能100%显示,但如果详细视图是用纯代码写的就会显示不完整,这个问题要怎么解决啊,再解决不了准不自定义分屏控制器了。
      • 夜空Star:谢谢楼主的分享,楼主可以留个联系方式吗(比如QQ等)?刚要做一个iPad项目,以前没做过心里没底气。
        passionHan:@夜空Star 忘了有验证了,我姓韩
        夜空Star:@passionHan 哥们贵姓啊?添加你的QQ需要:smile:
        passionHan:@夜空Star 可以,QQ1186941188,其实iPad开发和iPhone差不多,别有压力

      本文标题:iPad开发之自定义实现分屏控制器的功能

      本文链接:https://www.haomeiwen.com/subject/ygnarttx.html