iOS初学历程

自动转屏,UIPopoverController与模态视图控制器

2019-08-02  本文已影响0人  水无月之痕

UIPopoverController请介绍新版

如果需要修改默认支持方向,则必须在相应的UIViewController中覆盖supportedInterfaceOrientations方法。

在许多应用中,UINavigationController和UITabViewController是出现频率最高的两种视图控制器。UINavigationController使用继承自UIViewController的supportedInterfaceOrientations。如果需要由UINavigationController当前显示的视图控制器来决定所支持的界面方向,则可以创建UINavigationController的子类并覆盖supportedInterfaceOrientations方法。

UITabViewController则会依次检查每个标签项所支持的界面方向,然后在自身的supportedInterfaceOrientations方法中返回所有标签项都支持的界面方向。

-(NSUInteger)supportedInterfaceOrientations 
{
    return self.topViewController.supportedInterfaceOrientations;  
}

如果需要在界面方向发生变化时执行某些操作,则可以在UIViewController中覆盖willAnimateRotationToInterfaceOrientation:duration:方法。在界面方向发生改变后,UIViewController会收到willAnimateRotationToInterfaceOrientation: duration:消息,消息的第一个参数是新的界面方向。如果在应用转屏时不需要对视图做处理,或者不需要使用属性变换的动画效果,也可以将该方法替换为willRotateToInterfaceOrientation:duration:。两个方法将会在转屏时同时调用,参数的含义也都是相同的。但是,willRotateToInterfaceOrientation:duration:方法中不会自动添加任何动画效果。

如果需要在转屏完成之后执行一些操作,则可以在UIViewController中覆盖didRotateFromInterfaceOrientation:方法。该方法的参数是发生转屏之前的界面方向。最后,UIViewController对象有一个interfaceOrientation属性,表示该对象的当前界面方向。

UIPopoverController

为了有效利用充足的屏幕空间,Apple针对iPad应用提供了UIPopoverController。在iPhone应用中,如果要让用户做一个选择(例如在照片库中选择一张照片),或者针对屏幕上的某些元素显示相关摘要信息(例如向用户解释某一项数据的具体含义),则可能会使用模态视图控制器或警告视图;而在iPad应用中,这些场景更适合使用UIPopoverController。

UIPopoverController能够在一个带边框的窗口中显示一个指定的视图控制器的视图。此外,这个窗口会“悬浮”在其他界面的前面。创建UIPopoverController对象时需要设置contentViewController属性,指向需要显示的视图控制器。

模态视图控制器

要关闭某个以模态形式显示的视图控制器,必须向负责显示该对象的视图控制器发送dismissViewControllerAnimated:completion:
  UIViewController对象有一个名为presentingViewController的属性,当某个UIViewController对象以模态形式显示时,该属性会指向显示该对象的那个UIViewController对象。
  在iPhone或iPodtouch中以模态形式显示视图控制器时,视图控制器的视图会占据整个窗口。对iPhone系设备,这是默认的样式,也是唯一的选择。对iPad则有两个额外的选项:表单样式(formsheet)和页单样式(pagesheet)。修改视图控制器的modalPresentationStyle属性,可以改变其在模态形式下的外观。该属性的类型是UIModalPresentationStyle,其值可以是UIModalPresentationFormSheet或UIModalPresentationPageSheet两个常量中的一个。
修改模态样式后,UINavigationController对象不会占据整个屏幕,底下的对象的视图也不会消失。关闭模态视图控制器后,底下对象不会收到viewWillAppear:消息和viewDidAppear:消息,因此也没有机会刷新底下对象。为了能够在模态视图控制器被关闭后立刻执行这行代码,可以使用视图控制器的dismissViewControllerAnimated:completion:方法。

//类似C函数,Block对象也有返回值和一组实参,必须在声明Block对象时一并列出。以dismissBlock属性所指向的Block对象为例,其返回值是void,并且没有任何实参。
@property(nonatomic,copy)void(^dismissBlock)(void);

视图控制器有一个名为modalTransitionStyle的属性,该属性的类型是UIModalTransitionStyle:
UIModalTransitionStyleCoverVertical从底部滑入  UIModalTransitionStyleCrossDissolve淡入  UIModalTransitionStyleFlipHorizontal以3D效果翻转  UIModalTransitionStylePartialCurl模拟书页卷角

线程安全的单例

为了确保在多线程应用中只创建一次对象,可以使用dispatch_once()创建线程安全的单例(thread-safe singleton)。

static dispatch_once_t onceToken;  
dispatch_once(&onceToken,^{
.......
 });
位掩码

如何使用单一值描述多种可能值?答案是位掩码(bitmasks)
使用位掩码可以避免为保存每一种可能值而创建大量的属性.
 二进制数字中的列称为二进制位(bit)。可以将二进制位想象成开关,1代表“开”,0代表“关”。这样就可以将int类型的整数(至少会占用32个二进制位)想成是一组开关。数字的每个位代表一个“开关”:1代表“开(真)”,0代表“关(假)”。这等于是将很多布尔值塞进了一个整数。

视图控制器之间的关系

视图控制器之间的关系可以分为两类:父子关系和显示被显示关系。

当使用视图控制器容器(viewcontrollercontainer)时,就会产生拥有父子关系的视图控制器。
UINavigationController对象、UITabBarController对象和UISplitViewController对象都是视图控制器容器。这些容器的共性是都有一个类型为数组对象的viewControllers属性,用于保存一组视图控制器。

无论哪种视图控制器容器,都是UIViewController的子类对象,因此也有一个名为view的属性。视图控制器容器的特性是:容器对象会将viewControllers中的视图作为子视图加入自己的视图。此外,容器对象通常都会有自己的默认外观。以UINavigationController对象为例,它会在其视图顶部显示一个UINavigationBar对象,然后在余下的空间中显示topViewController的视图。

视图控制器族系示例

任何容器对象都可以通过viewControllers访问其子对象,而子对象也可以通过UIViewController对象的四个特定属性来访问其容器对象。
先介绍这四个特定属性的前三个,这三个属性分别是:navigationController、?

tabBarController和splitViewController。当某个视图控制器收到navigationController消息、tabBarController消息或splitViewController消息后,就会沿着族系向上查找,直到找到类型匹配的视图控制器容器。如果没有找到,相应的方法就会返回nil。

然后介绍第四个属性。UIViewController有一个名为parentViewController的属性。该属性会指向族系中“最近”的那个容器对象。因此,根据族系的形成方式,parentViewController可能会指向UINavigationController对象、UITabBarController对象或UISplitViewController对象。

视图控制器的另一类关系是显示被显示关系(presentingpresenterrelationship)。当某个视图控制器以模态形式显示另一个视图控制器时,就会产生拥有这种关系的视图控制器。当某个视图控制器(A)以模态形式显示另一个视图控制器(B)时,B的视图会覆盖A的视图。此外,任何一个UIViewController对象都可以以模态的形式显示另一个视图控制器

通过UIViewController对象的presentingViewController属性和presentedViewController属性,可以得到指向相应视图控制器的指针。当某个视图控制器(A)以模态形式显示另一个视图控制器(B)时,A的presentedViewController会指向B,而B的presentingViewController属性会指向A:


显示-被显示关系
显示被显示关系

在显示被显示关系中,位于关系两头的视图控制器不会处于同一个族系中。被显示的视图控制器会有自己的族系,这个族系可以只有一个UIViewController对象,也可以由多个UIViewController对象组成。


视图控制器的层次结构示例

凡是针对父子关系的属性,其指向的对象都会在当前族系的范围内。因此,向族系2中的视图控制器发送tabBarController消息,并不会返回族系1中的UITabBarController对象,而会返回nil。
不同族系中的视图控制器的关系稍微复杂一些。当应用以模态形式显示某个视图控制器时,负责显示该视图控制器的将是相关族系中的顶部视图控制器(或者可以说“最老”的那个)。
上图中的对象为例,族系2中的视图控制器的presentingViewController属性指向的都是UITabBarController对象。无论应用是向族系1中的哪个视图控制器发送presentViewController:animated:completion:消息,负责显示的对象始终是UITabBarController对象。

对某个族系中的所有视图控制器,其presentingViewController属性和presentedViewController属性都是有效的,并且总会指向另一个族系中的顶部对象。
 通过编写代码,可以改变这种“顶部对象负责以模态形式显示其他视图控制器”的行为(只能在iPad中使用),这样就可以限定视图的显示位置。

可以要求包含了该对象的UINavigationController对象显示在UITableView对象上,从而避免覆盖UINavigationBar。

为此,UIViewController提供了definesPresentationContext属性,其默认值是NO。当某个视图控制器的definesPresentationContext是NO时,会将“显示权(presentationoff)”传递给父视图控制器,并沿着族系依次向上传递,直到最顶层视图控制器。也就是说,最后会由最顶层视图控制器负责显示新的视图控制器;相反,在传递过程中,如果某个视图控制器的definesPresentationContext是YES,该视图控制器就不会再将“显示权”传递给父视图控制器,而是由自己负责显示新的视图控制器(见下图)。此外,对后面这种情况(视图应该不会覆盖UINavigationBar对象),必须将需要显示的视图控制器的modalPresentationStyle 属性设置为UIModalPresentationCurrentContext。


definesPresentationContext属性为YES的示例
上一篇下一篇

猜你喜欢

热点阅读