8p适配无效 ios

2014-09-23 15:36:11 wangLongBlog 阅读数 860

简介

先来看一下我们的新伙伴:Size Classes。在 iOS8 中,我们不用再像以前那样,一个页面新建多个 xib 文件来适配不同类型的屏幕,现在我们可以把各种尺寸屏幕的适配工作放在一个文件中完成,然后可以通过不同类别的 Size 来定制各种尺寸的界面。换句话说,你眼前的 Storyboard 不是一个普通的 Storyboard ,而是一个九合一的 Storyboard ,可以管理九种类型的屏幕。

对于宽度和高度而言,都有三种情况:紧凑 (Compact) 、任意 (Any) 、 正常 (Regular) ,所以一共有9个类别,在设置 Size Class 的时候页面会有提示。比如宽为 Compact 高为 Any 的情况,提示为 3.5-inch、4-inch、4.7-inch的横竖状态下的屏幕:

苹果官网文档举了一些例子,比如 iPad :

比如 iPhone :

比如 iPhone6 plus 的横屏状态:

实验

Size Class 的作用是将不同尺寸的屏幕进行分类处理,而最后进行布局管理的还是Autolayout。

下面我们来搞个小项目试验一下。项目源码可以在这里下载。

新建一个项目,进入到 Storyboard ,发现默认的尺寸是宽高均为 Any 的:

我们可以在右侧的视图中选择开启还是关闭 Size Class :

因为 Size Class 是依赖于 Autolayout 的,所以当你尝试关闭 AutoLayout 而打开 Size Class 的时候会有如下的提醒:

接下来我们先搞个 View 看看,测试一下直接扔进去会是什么效果:

看起来好像不错啊,难道不用做适配就可以了?

想太多。

我们把 Size 切换到 Compact 看下:

喔真的好 Compact 啊!

在不手动添加 Constraints 的情况下, Xcode 会自动自动分配一套默认的 Constraints ,以确保你在任何尺寸的屏幕下都看到一样坐标一样大小的页面。这就意味着我们有时可以忽视自动布局,不再需要设置那些自动布局且效果不错的控件,只需要为某些特定的视图创建 Constraints 。

不过现在我们想让这个正方形时刻保持居中,所以分别给它加上了四个 Constraints :

啊哈这样似乎就可以…就可以了…吗?

我们随便换了个 Size 看下效果,突然发现刚刚加的 Constraints 居然无效了,在导航栏里变成了灰色,在 Storyboard 里也看不到 Constraints 的影子:

这是因为刚刚我们的 Constraints 是在宽高均为 Compact 的 Size 中设置的,所以并不适用于其他尺寸的屏幕。这么说难道我们以后都要配置九份 Constraints 吗!这也太苦逼了吧!老板我们要涨工资啊!显然不是,我们只需要把默认的 Constraints 放在宽高均为 Any 的 Size 中即可:

这时再切换到其他尺寸就都没有问题了:

接下来,假设我们想在 iPhone 设备上显示两个 Label ,但是想在 iPad 上显示四个 Label,可以这样搞。

先把 Size 切换到 iPhone 的尺寸,然后添加两个 Label :

再把 Size 切换到 Regular ,添加三个 Label :

这时在 iPhone 中查看一下效果:

再去 iPad 里看下效果:

OK 就是这么简单。

实战

接下来我们来看一看如何利用 Size Class 来做适配。前面有说过, Size Class 不能解决适配问题,它的功能只是将屏幕进行分类,便于管理。真正搞适配的苦力还是 AutoLayout 。苹果的帮助文档给出三种方案解决 View 的适配问题。

我们先把项目改成最原始的版本,只留一个 View 在视图的正中央。原始版本的项目可以在这里下载。运行一下是这样的:

修改 Constraints

适配的第一个方案是针对不同尺寸的屏幕设置不同大小的 Constrain 。

我们选中一个 Constraint ,在右侧面板观察它的属性:

在右侧面板就是 Constraints 的值,第一行是默认值,适用于所有尺寸。如果要添加不同尺寸下的自定义值,可以点击加号:

这样就可以添加自定义的 Constraint 值了。其中, w 和 h 分别指宽 (width) 和 高(height) 。 C 是指 Size Class 中的 Compact, R 则对应 Regular , A 对应 Any 。

如果希望这个正方形在 iPad 下可以保持100的边距,在 iPhone 下可以保持0的边距,可以把每个 Constrant 的值都设为100,然后再添加一个 wC hA 的值为0:

运行一下程序看下,首先是 iPad 下:

简直完美,再看下 iPhone4s 下的效果:

哈哈似乎也不错。。。等下,说好的填满呢!怎么左右两边空了这么多空白?

突然想起了前几天在公司用 Xcode6 打开的项目再用 Xcode5 打开之后有些 xib 文件会报错,大意是: Xcode6 加了一些 Margin 我不认识。会不会是这些 Margin 在作怪呢?查了一下官方文档,确实在 iOS8 中多了一个 layoutMargin 的属性。偷偷拿 PS 量了一下,确实默认值是8个 point ,虚惊一场,还以为是 AutoLayout 坏了呢。

不过现在我不是很想要这个 Margin ,怎么把它关了呢?点击下方的 Pin 按钮,把 Margin 的勾选去掉即可:

然后再重新设置一下 Constraint ,OK它终于成功的填满了整个屏幕:

完整的源码可以在这里下载。

安装和卸载 Constraints

有时候我们可能会遇到比较复杂的设计,针对不同的尺寸需要有不同的布局,这和 Web 开发中的响应式设计颇有几分相似。

假设我们需要这样一个 View :在 iPad 下固定宽度,居中对齐,在 iPhone 下,则希望它保持左右边距居中对齐。

我们只需要添加 top 、 bottom 、 center x 、 width ,分分钟就可以搞出这样一个布局:

现在我们完成了第一步:在 iPad 下固定宽度,居中对齐。

接下来我们需要把 width 属性在 iPhone 中删除。选中 width 之后在右侧可以看到这样一个区域:

它表示,当前这个 Constraint 适用宽高均为 Any 的屏幕,和上一步相似,我们可以点击加号添加不同屏幕下的设置:

installed 前面打上勾,表示这个 Constraint 是适用这个尺寸的,如果没有打勾,则表明在那个尺寸下这个 Constraint 是无效的。比如下面的这个例子表示这个 Constraint 仅在宽高均为 Regular 的情况下 ( 也就是 iPad ) 有效:

接下来我们再添加上 leading 和 trailing 为0:

这样就能实现在 iPhone 下保持左右边距居中对齐的效果了:

但是打开 iPad 之后发现本来设置的固定宽度的效果失效了,变成了和 iPhone 一样的左右间距固定的情况。这是因为我们没有在 iPad 的屏幕下“卸载” (uninstall) 掉刚刚设置的 leading 和 trailing 。我们有两种方式解决这个问题。

第一种方案,选中 leading 和 trailing 这两个 Constraint 之后,在右侧添加宽高均为 Regular 的选项并去掉勾选,表明,这个 Constraint 适用于所有情况,就是不要用在宽高均为 Regular 的屏幕上:

第二种方案,切换到 Regular Regular 的尺寸之后,选中那两个 Constraint 然后按下Command+Delete ( 注意要按下 Command 键,要不然就是彻底删除了),就可以把这两个 Constraint 在当前的 Size 中卸载了:

运行一下, iPad 果然也没有问题了:

完整的源码可以在这里下载。

安装和卸载 View

有时候光设置 Constraint 是无法满足比较复杂的需求的,比如大屏下我希望能显示三个按钮,分别对应:吃早饭,吃午饭,吃晚饭。但是在 iPhone 等小屏下可能放不下这么多按钮,只能显示一个按钮:吃饭。遇到这种情况,我们只能对 View 进行安装 (install) 和卸载 (uninstall)。

我们先在 View 里面加上三个按钮:

但是我们并不希望这三个按钮出现在 iPhone 中,所以我们可以在右侧面板添加适用的尺寸,并去掉 Any 的勾选。这一步和上一章中 Constraint 的安装卸载十分类似:

可以看到左侧的 Button 变成了灰色,表示这个按钮在当前 Any 的尺寸下是不会显示的。我们再添加一个吃饭的按钮,添加 Regular 的尺寸并去掉勾选,表明自己不会在 Regular 屏幕中出现:

这样,在 iPhone 中我们可以看到 吃饭 的按钮:

而在 iPad 中可以看到 吃早饭 吃午饭 吃晚饭 的按钮:

完整的源码可以在这里下载。

其他

最后,无意中看到仿佛 Font 的左边多了点什么:

相信大家早已轻车熟路了,不妨动手试试看。可以参考苹果官方的帮助文档学习。

后话

第一次接触 Size Class ,还没有在实际项目中应用过,可能有些理解偏差,如有错误,还望指正,不胜感激。

一路走来,感觉有了 Size Class 之后,iOS 开发的适配工作可能并没有想象中的复杂,哪怕屏幕比更大还大,我们依旧能够真的笑,笑出声。

2019-09-23 21:23:48 DY_1024 阅读数 435

原文地址:http://blog.anbig.com/2019/08/24/ios屏幕旋转适配/

一、最让人纠结的三种枚举
二、两种屏幕旋转的触发方式
三、屏幕旋转控制的优先级
四、开启屏幕旋转的全局权限
五、开启屏幕旋转的局部权限 (视图控制器)
六、实现需求:项目主要界面竖屏,部分界面横屏
七、默认横屏无效的问题
八、关于旋转后的适配问题
九、APP 启动即全屏

刚开始接触屏幕旋转这块知识的时候,最让人抓狂的也许就是三种相关的枚举类型了,它们就是 UIDeviceOrientation、UIInterfaceOrientation、UIInterfaceOrientationMask。下面我们针对三种属性进行解析:

1. 设备方向:UIDeviceOrientation

UIDeviceOrientation 是硬件设备 (iPhone、iPad 等) 本身的当前旋转方向,设备方向有 7 种(包括一种未知的情况),判断设备的方向是以 home 键的位置作为参照的,源码中的定义:

typedef NS_ENUM(NSInteger, UIDeviceOrientation) {

     UIDeviceOrientationUnknown,

     UIDeviceOrientationPortrait,           

     UIDeviceOrientationPortraitUpsideDown, 

     UIDeviceOrientationLandscapeLeft,      

     UIDeviceOrientationLandscapeRight,     

     UIDeviceOrientationFaceUp,             

     UIDeviceOrientationFaceDown            

   } __TVOS_PROHIBITED;

设备方向只能取值, 不能设置,
获取设备当前旋转方向使用方法:[UIDevice currentDevice].orientation

监测设备方向的变化,我们可以在 Appdelegate 文件中使用通知如下:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDeviceOrientationDidChange)
                     name:UIDeviceOrientationDidChangeNotification
                                               object:nil];

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

 - (BOOL)onDeviceOrientationDidChange{

    UIDevice *device = [UIDevice currentDevice] ;

    switch (device.orientation) {
        case UIDeviceOrientationFaceUp:
            NSLog(@"屏幕幕朝上平躺");
            break;

        case UIDeviceOrientationFaceDown:
            NSLog(@"屏幕朝下平躺");
            break;

        case UIDeviceOrientationUnknown:

            NSLog(@"未知方向");
            break;

        case UIDeviceOrientationLandscapeLeft:
            NSLog(@"屏幕向左橫置");
            break;

        case UIDeviceOrientationLandscapeRight:
            NSLog(@"屏幕向右橫置");
            break;

        case UIDeviceOrientationPortrait:
            NSLog(@"屏幕直立");
            break;

        case UIDeviceOrientationPortraitUpsideDown:
            NSLog(@"屏幕直立,上下顛倒");
            break;

        default:
            NSLog(@"無法识别");
            break;
    }
    return YES;
}


 

2. 页面方向:UIInterfaceOrientation

UIInterfaceOrientation 程序界面的当前旋转方向 (可以设置),源码中的定义如下:


    typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {

        UIInterfaceOrientationUnknown               = UIDeviceOrientationUnknown,

        UIInterfaceOrientationPortrait              = UIDeviceOrientationPortrait,

        UIInterfaceOrientationPortraitUpsideDown    = UIDeviceOrientationPortraitUpsideDown,

        UIInterfaceOrientationLandscapeLeft         = UIDeviceOrientationLandscapeRight,

        UIInterfaceOrientationLandscapeRight        = UIDeviceOrientationLandscapeLeft

    } __TVOS_PROHIBITED;

区别与 UIDeviceOrientation,表示我们开发的程序界面的方向使用 UIInterfaceOrientation。

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight, 
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

我们可以发现两者的枚举值大多是可以对应上的。只有左右旋转的时候是 UIInterfaceOrientationLandscapeLeft 与 UIDeviceOrientationLandscapeRight 相等,反之亦然,这是因为向左旋转设备需要旋转程序界面右边的内容。

3. 页面方向:UIInterfaceOrientationMask

UIInterfaceOrientationMask 是 iOS6 之后增加的一种枚举,其源码中的定义如下:

typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {

    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),

    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),

    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),

    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),

    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),

    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),

} __TVOS_PROHIBITED;

我们知道 UIDeviceOrientation 与 UIInterfaceOrientation 的区别在于:前者是真实的设备方向,后者是页面方向。
而 UIInterfaceOrientation 和 UIInterfaceOrientationMask 的区别是什么呢?其实观察源码,我们就会发现这是一种为了支持多种 UIInterfaceOrientation 而定义的类型。下面的示例将很好的说明这点:

在 iOS6 之后,控制单个界面的旋转我们通常是下面三个方法来控制:

- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

- (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

方法 2 的作用是设置当前界面支持的所有方向,所以返回值是 UIInterfaceOrientationMask,更加方便的表达支持多方向旋转的情况。

方法 3 作用是设置进入界面默认支持的方向,使用了返回值类型 UIInterfaceOrientation,默认进入界面的方向是个确定的方向,所以使用 UIInterfaceOrientation 更适合。

我们开发的 App 的,大多情况都是大多界面支持竖屏,几个特别的界面支持旋转横屏,两种界面相互切换,触发其旋转有两种情况:

情况 1:系统没有关闭自动旋转屏幕功能,

这种情况,支持旋转的界面跟随用户手持设备旋转方向自动旋转。我们需要在当前视图控制器中添加如下方法:

- (BOOL)shouldAutorotate {
      return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
     return UIInterfaceOrientationMaskAll;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
     return UIInterfaceOrientationPortrait;
}

情况 2:单个界面强制旋转

在程序界面通过点击等方式切换到横屏 (尤其是视频播放的情况),有以下两种方法:

- (void)setInterfaceOrientation:(UIDeviceOrientation)orientation {
      if ([[UIDevice currentDevice]   respondsToSelector:@selector(setOrientation:)]) {
          [[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:orientation]     
                                       forKey:@"orientation"];
        }
    }

- (void)setInterfaceOrientation:(UIInterfaceOrientation)orientation {
   if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
            SEL selector = NSSelectorFromString(@"setOrientation:");
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice     
        instanceMethodSignatureForSelector:selector]];
            [invocation setSelector:selector];
            [invocation setTarget:[UIDevice currentDevice]];
            int val = orientation;
            [invocation setArgument:&val atIndex:2];
            [invocation invoke];
        }
    }

注意:使用这两个方法的时候,也要确保 shouldAutorotate 方法返回 YES,这样这两个方法才会生效。还要注意两者使用的参数类型不同。

事实上,如果我们只用上面的方法来控制旋转的开启与关闭,并不能符合我们的需求,而且方法无效。这是因为我们忽略了旋转权限优先级的问题。关于屏幕旋转的设置有很多,有 Xcode 的 General 设置,也有 info.plist 设置,更还有代码设置等,这么多的设置很是繁杂。但是这些其实都是在不同级别上实现旋转的设置,我们会遇到设置关闭旋转无效的情况,这就很可能是被上一级别控制的原因。

我们首先有个大致的了解,控制屏幕旋转优先级为:工程 Target 属性配置 (全局权限) = Appdelegate&&Window > 根视图控制器 > 普通视图控制器。

这里我使用全局权限来描述这个问题可能不太准确,其实是设置我们的设备能够支持的方向有哪些,这也是实现旋转的前提。
开启屏幕旋转的全局权限有三种方法,包括通过 Xcode 直接配置的两种方法和代码控制的一种方法。这三种方法作用相同,但是由于代码的控制在程序启动之后,所以也是最有效的。下面分别对三种方法的用法介绍:

1.Device Orientation 属性配置

我们创建了新工程,Xcode 就默认替我们选择了支持旋转的几个方向,这就是 Device Orientation 属性的默认配置。在 Xcode 中依次打开:【General】—>【Deployment Info】—>【Device Orientation】, 我们可以看到默认支持的设备方向如下:

 

可以发现,UpsideDown 没有被默认支持,因为对于 iPhone 即使勾选也没有 UpSideDown 的旋转效果。我们可以在这里勾选或者取消以修改支持的旋转方向。如果是 iPad 设备勾选之后会同时支持四个方向。

值得注意的是,对于 iPhone,如果四个属性我们都选或者都不选,效果和默认的情况一样。

2.Info.Plist 设置

其实我们设置了 Device Orientation 之后,再到 info.plist 中查看 Supported interface orientation, 我们会看到:

 

没错,此时 Supported interface orientation 里的设置和 UIDevice Orientation 的值一致的,并且我们在这里增加或者删除其中的值,UIDevice Orientation 的值也会随之变化,两者属于同一种设置。

3.Appdelegate&&Window 中设置

正常情况下,我们的 App 从 Appdelegate 中启动,而 Appdelegate 所持有唯一的 Window 对象是全局的,所以在 Appdelegate 文件中设置屏幕旋转也是全局有效的。下面的代码设置了只支持竖屏和右旋转:

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

    return  UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;

}

值得注意的是:如果我们实现了 Appdelegate 的这一方法,那么我们的 App 的全局旋转设置将以这里的为准,即使前两种方法的设置与这里的不同。

五、开启屏幕旋转的局部权限 (视图控制器)

在设置了全局所支持的旋转方向后,接着就开始设置具体的控制器界面了。我们在上面已经说明了关于旋转的优先级了。而这里主要涉及了三种视图控制器 (UITabbarViewController,UINavigationBarController ,UIViewController)

自全局权限开启之后,接下来具有最高权限的就是 Window 的根视图控制器 rootViewController 了。如果我们要具体控制单个界面 UIViewController 的旋转就必须先看一下根视图控制器的配置情况了。

当然,在一般情况下,我们的项目都是用 UITabbarViewController 作为 Window 的根视图控制器,然后管理着若干个导航控制器 UINavigationBarController,再由导航栏控制器去管理普通的视图控制器 UIViewController。若以此为例的话,关于旋转的优先级从高到低就是 UITabbarViewController>UINavigationBarController >UIViewController 了。如果具有高优先级的控制器关闭了旋转设置,那么低优先级的控制器是无法做到旋转的。

比如说我们设置要单个视图控制器可以自动旋转,这需要在视图控制器中增加 shouldAutorotate 方法返回 YES 或者 NO 来控制。但如果存在上层根视图控制器,而我们只在这个视图控制器中实现方法,会发现这个方法是不走的,因为这个方法被上层根视图控制器拦截了。理解这个原理后,我们有两种方法实现自动可控的旋转设置。

方法 1:逐级设置各视图控制器,高优先级的视图控制器影响低优先级控制器,

解决上述的问题我们需要设置 UITabbarViewController 如下:

-(BOOL)shouldAutorotate{
    return self.selectedViewController.shouldAutorotate;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return [self.selectedViewController supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

设置导航控制器 UINavigationController 如下:

-(BOOL)shouldAutorotate{
    return self.topViewController.shouldAutorotate;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return [self.topViewController supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return [self.topViewController preferredInterfaceOrientationForPresentation];
}

到这里,我们就应该明白了,其实就是高优先级的视图控制器要跟随低优先级控制器的旋转配置。这样就能够达到目的。

方法 2: 另辟蹊径,使用模态视图

使用模态视图可以不受这种根视图控制器优先级的限制。这个也很容易理解,模态弹出的视图控制器是隔离出来的,不受根视图控制的影响。具体的设置和普通视图器代码相同,这里就不累述了。

这其实也是一个我们做屏幕旋转最常见的需求,在根据上面的讲述之后,我们实现这个需求会很容易,但是具体的实现却有着不同的思路,我在这里总结了两种方法:

方法 1:使用基类控制器逐级控制

步骤:
1.开启全局权限设置项目支持的旋转方向
2.根据第五节中的方法1,自定义标签控制器和导航控制器来设置屏幕的自动旋转。
3.自定义基类控制器设置不支持自动转屏,并默认只支持竖屏
4.对项目中需要转屏幕的控制器开启自动转屏、设置支持的旋转方向并设置默认方向

demo1 链接: https://github.com/DreamcoffeeZS/Demo_TestRotatesOne.git

方法 2:Appdelegate 增设旋转属性

步骤:
1.在Applegate文件中增加一个用于记录当前屏幕是否横屏的属性
2.需要横屏的界面,进入界面后强制横屏,离开界面时恢复竖屏

demo2 链接: https://github.com/DreamcoffeeZS/Demo_TestRotatesTwo.git

七、默认横屏无效的问题

在上面的项目中,我们可能会遇到一个关于默认横屏的问题,把它拿出来细说一下。
我们项目中有支持竖屏的界面 A,也有支持横竖屏的界面 B,而且界面 B 需要进入时就显示横屏。从界面 A 到界面 B 中,如果我们使用第五节中的方法 1 会遇到无法显示默认横屏的情况,因为没有旋转设备,shouldAutorotate 就没被调用,也就没法显示我们需要的横屏。这里有两个解决方法:

方法 1:在自定义导航控制器中增加以下方法

#pragma mark -UINavigationControllerDelegate

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [self presentViewController:[UIViewController new] animated:NO completion:^{
        [self dismissViewControllerAnimated:NO completion:nil];
    }];
}

这个方法的缺点是,原理上利用弹出模态视图来调用转屏,造成切换界面的时候有闪烁效果,体验不佳。所以这里也只是提供一种思路,不推荐使用。

方法 2: 在需要默认横屏的界面里设置,进入时强制横屏,离开时强制竖屏

关于这种使用,这个具体可以参考第五节中的 demo2

注:两种方法不可同时使用

屏幕旋转的实现会带来相应的 UI 适配问题,我们需要针对不同方向下的界面重新调整视图布局。首先我们要能够监测到屏幕旋转事件,这里分为两种情况:

1. 视图控制器 UIViewController 里的监测

当发生转屏事件的时候,下面的 UIViewControoller 方法会监测到视图 View 的大小变化,从而帮助我们适配

/*
This method is called when the view controller's view's size is
changed by its parent (i.e. for the root view controller when its window rotates or is resized).

If you override this method, you should either call super to
propagate the change to children or manually forward the 
change to children.
 */
- (void)viewWillTransitionToSize:(CGSize)size 
withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0);

从注释里可以看出此方法在屏幕旋转的时候被调用,我们使用时候也应该首先调用 super 方法,具体代码使用示例如下:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    if (size.width > size.height) {

        self.textView_height.constant = 50;
    }else{

        self.textView_height.constant = 200;
    }
}

2. 子视图横竖屏监测

如果是类似于表视图的单元格,要监测到屏幕变化实现适配,我们需要用到 layoutSubviews 方法,因为屏幕切换横竖屏时会触发此方法,然后我们根据状态栏的位置就可以判断横竖屏了,代码示例如下:

- (void)layoutSubviews {
    [super layoutSubviews];

    if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationMaskPortrait) {

    } else {

    }
}

有时项目需要从 App 启动就默认是横屏,这里有个很方便的方法,就是我们在 Device Orientation 属性配置里设置如下:

 

但是只这样处理的话,会让项目只支持横屏,所以我们可以在 Appdelegate 里再次调整我们所支持的方向,方法已经说过,这里就不累述了。

2016-01-04 00:10:44 u014536527 阅读数 2746

iOS适配的相关内容的整理

       之前iOS开发者一直很庆幸自己不用像安卓开发者那样适配各种不同类型的机型,但如今随着iPhone各种机型的改变,适配也成了我们开发中必须会的内容了。首先我们来了解一下对于不同苹果设备,各个参数的列表:

       各机型参数对比

  

一、机型的适配;

1.机型的变化:

  坐标:表示屏幕物理尺寸大小,坐标变大了,表示机器屏幕尺寸变大了;

  像素:表示屏幕图片的大小,跟坐标之间有个对应关系,比如1:1或1:2等;

  ppi:代表屏幕物理大小到图片大小的比例值,如果ppi不变,则坐标和像素的比例不会变;


iPhone 4 以前

iPhone、iPhone3/3G机型未采用retina,坐标是320 x 480,屏幕像素320 x 480 ,他们一一对应,1:1关系。即一个坐标对应1个像素。

iPhone4/4s

机器采用了retina屏幕,坐标是320 x 480,屏幕像素640 x 960,他们之间是1:2关系。即一个坐标对应2个像素。

iPhone 5/5s/5c

机器采用了retina屏幕,坐标是320 x 568,屏幕像素640 x 1136,他们之间关系式1:2关系。即一个坐标对应2个像素。

iPhone 6

机器采用了retina屏幕,坐标是375, 667,屏幕像素750 x 1334,他们之间关系式1:2关系。即一个坐标对应2个像素.

iPhone 6 plus

机器采用了retina屏幕,坐标是414, 736,屏幕像素1080 x 1920,他们之间关系式1:2.6关系。即一个坐标对应2.6个像素.

2.适配方法:

2.1.1图片适配

  • iPhone 4s之后,不同机型,屏幕大小坐标不变,跟实际图片大小比例不是1:1就是1:2关系。因为坐标不变,所以在开发中可以使用绝对定位,确定每个视图位置,同时提供俩套图片,~.png和~@2x.png,系统根据机器的分辨率自动决定使用哪张图片。
  • iPhone 5/5s/5c之后,因为屏幕大小坐标已变,高度增加568 - 480 = 88个点,再使用绝对定位的方式,会导致程序高度不够,如果程序未做适配,系统会将多出来的88个点将会将会被自动均分为上下两部分,使得上下出现黑边。对应不同机型,屏幕坐标大小改变了,不能再绝对定位了,为了解决这个问题,ios出现了一种新技术:AutoLayout。AutoLayout可以解决不同机型,屏幕大小的变化,至于图片的适配,因为5/5s/5c,坐标:像素 = 1:2,所以直接使用@2x.png图片就行。                                                                      至于@2x图片大小,是按照640 x 960 还是 640 x 1136 的大小,一个是拉伸效果,一个是压缩效果,因为比例差不多,推荐使用大图的。
  • iPhone 6之后,因为屏幕大小坐标已变,宽、高都增大,但是宽、高比例不变,类似之前的处理方式,使用AutoLayout自动适配,坐标:像素 = 1:2,使用@2x.png图片。
    综合之前的,@2x图片可以按照750 x 1334规格来
  • iPhone 6 plus,类似之前使用AutoLayout,在使用图片的时候,因为 坐标:像素 = 1:2.6,理论上使用@2.6x.png图片即可,但是这不是整数,实际使用很不方便,而@2x 和 @3x 都不太行得通,怎么办?

     引用一段文字说的很好:  

             “不是现有的屏幕物理分辨率明显超过了 @2x 但还达不到 @3x 的水平么?那我们歪打正着一个满足 @3x 的屏幕总可以吧?
                对的,歪打正着。
                程序在 iPhone 6 Plus 上运行的时候,iOS 会骗它说,你运行在一个超大的 @3x Retina 显示屏上,物理分辨率高达 1242 x 2208,逻辑分辨率是 414 x 736,两者都比 iPhone 6 要大。然后作为设计师和开发人员,也跟着一起歪打正着。设计师画图的时候要把屏幕当成 1242 x 2208 来画图(而且要提供@3x 的高清图),开发人员也按照 414 x 736 的逻辑分辨率来写程序。
                但借来的总要还的。等咱们歪歪结束了以后,iOS 拿到这个假大的 UI 绘制结果,实时地再缩小到实际的 1080 x 1920 分辨率(系统通过某种算法)。于是,用户在 iPhone 6 Plus 的屏幕上看到的永远是被缩小了的图像:

              这么做使得设计和开发的过程大大简化,且最后的实际缩放系数 @2.62x 非常接近理想的 @2.46x,使得同样的素材在真机上看起来尺寸也非常合理。

2.1.2代码适配

(1)根据屏幕的宽和高写相关的frame

        在新特性界面中,根据:[UIScreen mainScreen].bounds.size.height.来判断用户的屏幕长度,来判断时3.5寸,4     寸,4.7寸,5.5寸,以此来设置新特性中图片选用哪套。

  常用写法:

  #define kScreenWidth [UIScreen mainScreen].bounds.size.width

  CGFloat btnW =kScreenWidth * 1/4;


(2)存代码实现AutoLayout,一般使用第三方封装好的Masonry
         


(3)StoryBoard的AutoLayout,这个我在项目中使用不是太多,但是收集一下网址,大家可以参照学习哦!

机型适配总结:

  • 不同机型适配可看成两部分,一是屏幕大小适配(坐标),一是像素适配;前者根据不同的机型大小,视图大小自动适应(AutoLayout);后者根据机型的分辨率和坐标比率,提供合适@xx图片;
  • 目前4s、5/5s/5c、6的适配,使用图片部分,都是使用@2x的图片,在不同的机器上肯定会有一定的拉伸、缩小,目前没看到什么好的解决方案,推荐图片按大图标准做;
  • 趋势:机器屏幕的大小可能会越来越多,绝对定位的方式肯定不行,使用AutoLayout,自动适配屏幕大小,类似网页的思想来设计界面;
  • 趋势:xcode 6中已经可以使用矢量图了,可以使用矢量图,避免各种规格图片;
  • 对于设计师:
    (1)非矢量素材,就可以做尺寸最大的,之后再进行缩小。比如你需要兼容3x的屏幕,就直接做最高那种图片。因为之后几种机型长宽比都是9:16,可以直接拉伸。
    (2)已有非矢量素材,直接拉伸放大到@3x。
    (3)
    而当使用Flash之类的矢量工具来做素材的时候,应该直接做点那个尺寸。比如44 x 66个点的按钮。就建立一个44 x 66的场景。之后再导出成2倍图,3倍图,因为矢量放大不失真。不要建立一个3x的场景,导出成大图片,再进行缩小,这样就容易失真。

二、系统适配;

1.iOS9网络适配,改为更为安全的HTTPS

在Info.plist的source code中添加一段代码即可:
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>



2.Bitcode

Bitcode支持watchOS,如果在程序中Bitcode开关是打开的状态,那么第三方库必须支持Bitcode,但是好多第三方库不支持Bitcode,因此在Xcode7会报如下错误:


UMengFeedback_SDK_2.1/libUMFeedback.a(UMChatTableViewCell.o)'doesnot contain bitcode. You must rebuild it with bitcode enabled (XcodesettingENABLE_BITCODE), obtain an updated library from the vendor, or disablebitcodefor this target. for architecture arm64

解决方案有两种:

第一种:使第三方库支持Bitcode(当然这个我们不容易控制,所以这个方案一般不采用);

第二种:关闭taget的Bitcode选项

实际上,在Xcode 7中,我们新建一个iOS程序时,Bitcode选项默认是设置为YES的。我们可以在”BuildSettings”->”Enable Bitcode”选项中看到这个设置。不过,我们现在需要考虑的是三个平台:iOSMac OSwatchOS;

对于iOSBitcode是可选的;对于watchOSBitcode是必须的;而Mac OS是不支持Bitcode

如果我们开启了Bitcode,在提交程序到AppStore时,会看到有Bitcode的选项

3.iOS9 URL Scheme适配引入白名单

一般应用中都会集成第三方分享,登陆,以及支付,所以需要将三方的相关内容加入到相关的白名单中,可以直接修改plist文件中的代码:
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>testA</string>
        </array>
    </dict>
</array>
也可以直接通过如下方式添加:





4.代码创建UITableView无法隐藏cell的分割线;以及reloadData刷新失效;

解决方法是将设置分割线隐藏的方法 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 写在 -layoutSubviews 中:
-(void)layoutSubviews{
    [super layoutSubviews];
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}

现象: [tableView reloadData] 无效,有一行 cell 明明改变了但是刷新不出来。

感觉可能是这个方法和某种新加的特性冲突了,猜测可能是 reloadData 的操作被推迟到下一个 RunLoop 执行最终失效。

解决的方法是,注释 [tableView reloadData] ,改用局部刷新:

[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];

这两个推测均属 Xcode7 的bug,将来 Apple 肯定会修复。

【项目中关于iOS9的适配暂时鄙人遇到这么多,如果你还想了解更多详情,请参照如下教程:iOS9适配系列教程】。

说完iOS9的适配我们来了解一下iOS的一些适配的相关内容(iOS8的适配没有像iOS9那样火爆,就如网络请求一样,如果你不适配iOS9是请求不到数据的,可以说我们是被逼着往前跑的),项目中涉及到的iOS8的适配有如下内容:
1.

#ifdef IS_IOS8
@property (nonatomic,strong)UIAlertController *alertC;  ///ios8的提醒框
#endif


2.
/**
    消息推送
 **/
- (void) msgPush
{
    //推送的形式:标记,声音,提示
    if (IS_IOS8) {
        //1.创建消息上面要添加的动作(按钮的形式显示出来)
        UIMutableUserNotificationAction *action = [[UIMutableUserNotificationAction alloc] init];
        action.identifier = @"action";//按钮的标示
        action.title=@"Accept";//按钮的标题
        action.activationMode = UIUserNotificationActivationModeForeground;//当点击的时候启动程序
        //    action.authenticationRequired = YES;
        //    action.destructive = YES;
        
        UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
        action2.identifier = @"action2";
        action2.title=@"Reject";
        action2.activationMode = UIUserNotificationActivationModeBackground;//当点击的时候不启动程序,在后台处理
        action.authenticationRequired = YES;//需要解锁才能处理,如果action.activationMode = UIUserNotificationActivationModeForeground;则这个属性被忽略;
        action.destructive = YES;
        
        //2.创建动作(按钮)的类别集合
        UIMutableUserNotificationCategory *categorys = [[UIMutableUserNotificationCategory alloc] init];
        categorys.identifier = @"alert";//这组动作的唯一标示,推送通知的时候也是根据这个来区分
        [categorys setActions:@[action,action2] forContext:(UIUserNotificationActionContextMinimal)];
        
        //3.创建UIUserNotificationSettings,并设置消息的显示类类型
        UIUserNotificationSettings *notiSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIRemoteNotificationTypeSound) categories:[NSSet setWithObjects:categorys, nil]];
        [[UIApplication sharedApplication] registerUserNotificationSettings:notiSettings];
    }else{
        
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
    }
    
}

当然了iOS8的适配我们也需要了解一下,具体总结如下:iOS8适配入门&资料总结
2018-07-06 14:50:58 weixin_41809141 阅读数 2679
 rem移动端布局怎么适配IOS和Android
        昨天“佬大”问我做的h5页面在ios上面显示正常,但是Android就变惨不忍睹了,于是我又开始了度量之路,几个小时过去了......“佬大”问好了没。我说:“还没”那你还是问下“俊伟”吧,果然一问牛逼的同事,迎刃而解的快感你感受到了没。做为一个程序员一定要学会问问问。

  我当时用的是这种方式

     <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" id="vp" />
    <script type="text/javascript">
    // 把尺寸放大N倍(N是window.devicePixelRatio)
    var wd = document.documentElement.clientWidth*window.devicePixelRatio/10;
    //物理像素*设备像素比=真实像素
    document.getElementsByTagName("html")[0].style.fontSize = wd + "px";
    // 把屏幕的倍率缩小到N分之一(N是window.devicePixelRatio)
    var scale = 1/window.devicePixelRatio;
    var mstr = 'initial-scale='+ scale +', maximum-scale='+ scale +', minimum-scale='+ scale +', user-scalable=no';
    document.getElementById("vp").content = mstr;
    </script>

只能兼容ios,android失效

在实际项目开发中,我有用到的两种比较有效的方式(兼容ios和Android)

方法一:

案例实战

了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。

创建HTML模板

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta content="yes" name="apple-mobile-web-app-capable">

meta content="yes" name="apple-touch-fullscreen">

<meta content="telephone=no,email=no" name="format-detection">

<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

<title>再来一波</title>

</head>

<body><!-- 页面结构写在这里 --></body>

</html>

正如前面所介绍的一样,首先加载了Flexible所需

这个时候可以根据设计的图需求,在HTML文档的<body></body>中添加对应的HTML结构

这仅是一个示例文档,大家可以根据自己风格写模板

为了能更好的测试页面,给其配置一点假数据:

//define data
var pageData = {
    sections:[{
        "brannerImag":"http://xxx.cdn.com/B1PNLZKXXXXXaTXXXXXXXXXXXX-750-481.jpg",
        items:[{
            "itemLink": "##",
            "imgSrc": "https://placeimg.com/350/350/people/grayscale",
            "poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093",
            "price": "299.06",
            "preferential": "满400减100",
            "activityType": "1小时内热卖5885件",
            "shopLink":"##",
            "activeName": "马上抢!"
        }
            ....
        }]
    }]
}

接下来的工作就是美化工作了。在写具体样式之前,有几个点需要先了解一下。

把视觉稿中的px转换成rem

读到这里,大家应该都知道,我们接下来要做的事情,就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。

首先,目前日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px750px以及1125px宽度为准。甚至为什么?大家应该懂的(考虑Retina屏)。

正如文章开头显示的示例设计稿,他就是一张以750px为基础设计的。那么问题来了,我们如何将设计稿中的各元素的px转换成rem

如何快速计算

在实际生产当中,如果每一次计算px转换rem,或许会觉得非常麻烦,或许直接影响大家平时的开发效率。为了能让大家更快进行转换,我们团队内的同学各施所长,为px转换rem写了各式各样的小工具。

CSSREM

CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。这个插件是由@正霖编写。先来看看插件的效果:

Flexible实现手淘H5页面的终端适配

有关于CSSREM如何安装、配置教程可以点击这里查阅

CSS处理器

除了使用编辑器的插件之外,还可以使用CSS的处理器来帮助大家处理。比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

Sass

使用Sass的同学,可以使用Sass的函数、混合宏这些功能来实现:

@function px2em($px, $base-font-size: 16px) {
    @if (unitless($px)) {
        @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
        @return px2em($px + 0px); // That may fail.
    } @else if (unit($px) == em) {
        @return $px;
    }
    @return ($px / $base-font-size) * 1em;
}

除了使用Sass函数外,还可以使用Sass的混合宏:

@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
    //Conver the baseline into rems
    $baseline-rem: $baseline-px / 1rem * 1;
    //Print the first line in pixel values
    @if $support-for-ie {
        #{$property}: $px-values;
    }
    //if there is only one (numeric) value, return the property/value line for it.
    @if type-of($px-values) == "number"{
        #{$property}: $px-values / $baseline-rem;
    }
    @else {
        //Create an empty list that we can dump values into
        $rem-values:();
        @each $value in $px-values{
            // If the value is zero or not a number, return it
            @if $value == 0 or type-of($value) != "number"{
                $rem-values: append($rem-values, $value / $baseline-rem);
            }
        }
        // Return the property and its list of converted values
        #{$property}: $rem-values;
    }
}

有关于更多的介绍,可以点击这里进行了解。

PostCSS(px2rem)

除了Sass这样的CSS处理器这外,我们团队的@颂奇同学还开发了一款npm的工具px2rem。安装好px2rem之后,可以在项目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var px2rem = require('postcss-px2rem');

gulp.task('default', function() {
    var processors = [px2rem({remUnit: 75})];
    return gulp.src('./src/*.css')
        .pipe(postcss(processors))
        .pipe(gulp.dest('./dest'));
});

除了在Gulp中配置外,还可以使用其他的配置方式,详细的介绍可以点击这里进行了解。

配置完成之后,在实际使用时,你只要像下面这样使用:

.selector {
    width: 150px;
    height: 64px; /*px*/
    font-size: 28px; /*px*/
    border: 1px solid #ddd; /*no*/
}

px2rem处理之后将会变成:

.selector {
    width: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

在整个开发中有了这些工具之后,完全不用担心px值转rem值影响开发效率。

字号不使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px24px,所以我们不希望出现13px15px这样的奇葩尺寸

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

div {
    width: 1rem; 
    height: 0.4rem;
    font-size: 12px; // 默认写上dpr为1的fontSize
}
[data-dpr="2"] div {
    font-size: 24px;
}
[data-dpr="3"] div {
    font-size: 36px;
}

为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

@mixin font-dpr($font-size){
    font-size: $font-size;

    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }

    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

有了这样的混合宏之后,在开发中可以直接这样使用:

@include font-dpr(16px);

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

CSS

本来想把这个页面的用到的CSS(或SCSS)贴出来,但考虑篇幅过长,而且这么简单的页面,我想大家也能轻而易举搞定。所以就省略了。权当是给大家留的一个作业吧,感兴趣的可以试试Flexible能否帮你快速完成H5页面终端适配。

方法二:
使用微信的官方框架WeUI

用代码来征服你吧,来感受它的强大之处



  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" charset="utf-8">
  5. <title></title>
  6. <link rel="stylesheet" type="text/css" href="https://res.wx.qq.com/open/libs/weui/1.1.2/weui.min.css">
  7. <script type="text/javascript" href="https://res.wx.qq.com/open/libs/weuijs/1.1.3/weui.min.js"></script>
  8. </head>
  9. <body>
  10. <div class="weui-cells__title">新增会员</div>
  11. <div class="weui-cell">
  12. <div class="weui-cell__hd"><label class="weui-label">姓名</label></div>
  13. <div class="weui-cell__bd">
  14. <input class="weui-input" type="text" placeholder="请输入姓名"/>
  15. </div>
  16. </div>
  17. <div class="weui-cell weui-cell_select weui-cell_select-after">
  18. <div class="weui-cell__hd">
  19. <label for="" class="weui-label">性别</label>
  20. </div>
  21. <div class="weui-cell__bd">
  22. <select class="weui-select" name="select2">
  23. <option value="1"></option>
  24. <option value="2"></option>
  25. </select>
  26. </div>
  27. </div>
  28. <div class="weui-cell">
  29. <div class="weui-cell__hd"><label class="weui-label">身份证号</label></div>
  30. <div class="weui-cell__bd">
  31. <input class="weui-input" type="text" placeholder="请输入身份证号"/>
  32. </div>
  33. </div>
  34. <div class="weui-cell">
  35. <div class="weui-cell__hd"><label class="weui-label">手机号</label></div>
  36. <div class="weui-cell__bd">
  37. <input class="weui-input" type="tel" placeholder="请输入手机号"/>
  38. </div>
  39. </div>
  40. <div class="weui-cell">
  41. <div class="weui-cell__hd"><label class="weui-label">地址</label></div>
  42. <div class="weui-cell__bd">
  43. <input class="weui-input" type="tel" placeholder="请输入地址"/>
  44. </div>
  45. </div>
  46. <div class="weui-btn-area">
  47. <a class="weui-btn weui-btn_primary" href="javascript:" id="showTooltips">确定</a>
  48. </div>
  49. </body>
  50. </html>
原来用好UI框架这么爽,分分钟做一个页面出来,哈哈哈。
2015-07-26 01:07:56 CHENYUFENG1991 阅读数 3230

       屏幕适配问题共有四种解决方案:(1)根据屏幕宽高写控件frame(下策);(2)Autoresizing的使用(中策);(3)AutoLayout的使用(上策);(4)sizeClasses+AutoLayout的使用(上上策)。下面将会分别来进行叙述。


(1)根据当前屏幕的宽高写frame

      在新特性界面中,根据:[UIScreen mainScreen].bounds.size.height.来判断用户的屏幕长度,来判断时3.5寸,4寸,4.7寸,5.5寸,以此来设置新特性中图片选用哪套。

常用写法:

#define JKScreenW [UIScreen mainScreen].bounds.size.width

CGFloat btnW = JKScreenW * 0.2;

缺点:代码复杂,容易出错;而且维护难度大,灵活性极差。


(2)Autoresizing使用

     在Autolayout以前,有Autoresizing可以做屏幕适配,但局限性较大,只能针对父子关系进行有限调整,如边距固定,尺寸可变,对于兄弟关系的调整无法实现。对于UI比较固定的app,这种方式基本满足。相比之下,Autolayout比Autoresizing强大很多。


(3)Autolayout使用

--在以前的iOS程序是怎样布局UI的?

经常编写大量的坐标计算代码;

为了保证在各种屏幕上都能有完美的UI界面效果,有时还需要分别为几种屏幕编写不同的坐标计算代码(即传说中的“屏幕适配”)


--什么是Autolayout?

Autolayout是一种“自动布局”技术,专门用来布局UI界面的。

Autolayout自iOS6开始引入,由于Xcode4的不给力,当时并没有得到很大的推广。

自iOS7(Xcode5)开始,Autolayout的开发效率得到很大的提升。

苹果官方也推荐开发者使用Autolayout来布局UI界面。

Autolayout能够很轻松的解决屏幕适配的问题。


(4)Size Classes使用

      iOS8中新增了Size Classes特性,他是对当前所有iOS设备尺寸的一个抽象。

用法:

屏幕的宽和高分别分成三种情况:(Compact,Regular,Any).也就是紧凑,正常和任意。这样宽和高三三整合,一共九种情况。针对每一种情况,如果需要的话,我们可以单独在storyboard或xib中设置UIView的自动布局约束,甚至某一个button是否显示都是能轻松实现的。

具体使用方法以后我们实际项目用到再进行分析。


本篇内容参考极客学院视频课程《iOS8 SDK新特性系列课程》,非常感谢!


github主页:https://github.com/chenyufeng1991  。欢迎大家访问!

iOS多语言适配

阅读数 983