美文网首页
屏幕适配

屏幕适配

作者: wpf_register | 来源:发表于2020-01-10 15:13 被阅读0次

    基础知识

    • 屏幕尺寸
      手机屏幕对角线的长度 1英寸(inch)=2.54厘米(cm)

    • 分辨率
      在我们手机上呈现的一条线,一个面,一张图像都是由最小的单位像素来表示的,也可以简单理解为是由一个个小方块组成的。
      例:当5.2英寸的手机分辨率1920px*1080px
      即手机在竖向的高度上有1920个像素块,在横向的宽度上有1080个像。

    • 像素密度
      屏幕像素密度,即每英寸屏幕所拥有的像素数,英文简称PPI
      每英寸不是每平方英寸的简称,
      这个英寸跟之前手机屏幕的尺寸一样,也是对角线的长度
      即在一个对角线长度为1英寸的正方形内所拥有的像素数。
      例: 5.2寸手机分辨率1920 *1080 px 密度约为424
      (1920px就是公式里的纵向,1080px就是公式里的横向)

    • 像素没有固定的物理性大小
      苹果6手机 ,5英寸, 1920 * 1080 px, 469 ppi
      荣耀7手机, 5.2英寸,1920 *1080px, 424 ppi
      分辨率相同,苹果手机的屏幕尺寸比华为荣耀7小了0.2英寸,
      但苹果(PPI)却比华为荣耀7高了45个PPI。

      一个像素其实就是一个色彩块,
      同样的一英寸,苹果手机展示469个色彩,华为展示424个色彩,
      苹果手机的显示效果当然就更好了。

    • 电脑调整分辨率,是弄啥呢
      在同一个设备上,它的像素个数是固定的,厂商在出厂时就设置好了。只有不同的设备之间,才有像素大小的区别。既然在同一个设备上,像素点数早就设定好了,那电脑上可以调整分辨率是怎么回事?

      系统给你推荐的是1366px*768px的分辨率,
      意味着微软在这块屏幕上横向设置了768个像素,竖向设置了1366个像素。这个数字是确定且不会改变的。

      如果把分辨率调成800 * 600,系统就会分配给你800 * 600个有效像素个数,也就是真实的色彩块。其他的个数呢,就由系统自作主张,通过一系列运算给你一个模拟色彩块,填充成正好1366*768个色彩块。

    导航栏高度

    iphone 系列开发尺寸
    手机型号 Physical Device Points (pt) Rendered Pixels(px) Render 屏幕密度
    2G 3G 3GS 3.5 320*480 320*480 @2x 326
    4 4S 3.5 320*480 640*960 @2x 326
    5 5s 5c SE 4 320*568 640*1136 @2x 326
    6 6s 7 8 4.7 375*667 750*1334 @2x 326
    6+ 6S+ 7+ 8+ 5.5 414*736 1242*2208 @3x 401
    X Xs 5.8 375*812 1125*2436 @3x
    Xr 6.1 414*896 828*1792 @2x
    Xs Max 6.5 414*896 1242*2688 @3x
    判断iPhoneX Type机型的方法汇总

    方式一:通过获取设备的 device model 来判断
    每一台 iOS 设备都有对应的硬件编码/标识符,
    称为 device model 或者叫 machine name,
    可以通过如下两种方法来获取 device model/machine name

    #import <sys/sysctl.h>
    #import <sys/utsname.h>
    
    // 获取 device model/machine name 的方法一
    + (NSString *)machineName1 {
        size_t size;
        sysctlbyname("hw.machine", NULL, &size, NULL, 0);
        char *machine = (char *)malloc(size);
        if (machine == NULL) {
            return nil;
        }
        sysctlbyname("hw.machine", machine, &size, NULL, 0);
        NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];
        free(machine);
        return platform;
    }
    
    // 获取 device model/machine name 的方法二
    + (NSString *)machineName2 {
        struct utsname systemInfo;
        uname(&systemInfo);
        return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    }
    
    

    iPhone X 对应的 device mode 为 iPhone10,3 和 iPhone10,6
    iPhone XS 对应 iPhone11,2,
    iPhone XS Max 对应 iPhone11,4 和 iPhone11,6,
    iPhone XR 对应 iPhone11,8
    参考链接

    上述两种获取 device model 的方法在模拟器中运行得到的值为 i386 或 x86_64,
    因此在模拟器中正确获取模拟器所对应的 device model:

    // 获取模拟器所对应的 device model
    NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
    

    综上完整代码应该是

    + (BOOL)isiPhoneX {
        static BOOL isiPhoneX = NO;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
    #if TARGET_IPHONE_SIMULATOR
            // 获取模拟器所对应的 device model
            NSString *model = NSProcessInfo.processInfo.environment[@"SIMULATOR_MODEL_IDENTIFIER"];
    #else
            // 获取真机设备的 device model
            struct utsname systemInfo;
            uname(&systemInfo);
            NSString *model = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    #endif
            // 判断 device model 是否为 "iPhone10,3" 和 "iPhone10,6" 或者以 "iPhone11," 开头
            // 如果是,就认为是 iPhone X
            isiPhoneX = [model isEqualToString:@"iPhone10,3"] || [model isEqualToString:@"iPhone10,6"] || [model hasPrefix:@"iPhone11,"];
        });
        
        return isiPhoneX;
    }
    

    方式二:通过获取屏幕的宽高来判断
    目前 iPhone X 设备的屏幕宽高对应的开发尺寸只有两种,
    分别为 375pt * 812pt 和 414pt * 896pt,因此我们可以根据屏幕的高度来判断设备是否为 iPhone X。
    但是此时需要考虑设备处于横屏或者竖屏的情况

    在 UIDevice 中提供了一个 orientation 属性用于获取设备的方向(横向、竖向、或者水平),一开始我们想着先通过这个属性判断设备处于横屏或者竖屏,然后分别取其对应的屏幕宽度(横屏下)或者高度(竖屏下)来判断,但是当这个属性的值为 FaceUp 或者 FaceDown(即设备放在水平面上),我们是无法知道此时设备是处于横屏还是竖屏的。

    后面我们想了一个简便的方法,即获取屏幕的宽度和高度,取较大一方进行比较是等于 812.0 或 896.0,代码如下:

    + (BOOL)isiPhoneX {
        // 先判断当前设备是否为 iPhone 或 iPod touch
        if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
            // 获取屏幕的宽度和高度,取较大一方判断是否为 812.0 或 896.0
            CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
            CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
            CGFloat maxLength = screenWidth > screenHeight ? screenWidth : screenHeight;
            if (maxLength == 812.0f || maxLength == 896.0f) {
                return YES;
            }
        }
        return NO;
    }
    

    方式三:通过底部安全区域的高度来判断
    iPhone X 发布后,为了适配顶部的浏览和底部的操作条,苹果在 iOS 11 上引入安全区域概念,建议开发者在安全区域内进行 UI 布局,因此我们可以获取屏幕 keyWindow 的 safeAreaInsets 值来判断设备是否 iPhone X。

    //iPhone X 
    //竖屏,keyWindow 的 safeAreaInsets 值为:
    {top: 44, left: 0, bottom: 34, right: 0}
    //横屏
    {top: 0, left: 44, bottom: 21, right: 44}
    

    我们可以比较 safeAreaInsets 的 bottom 是否等于 34.0 或者 21.0 来判断设备是否为 iPhone X,
    因为其他设备对应的 bottom 横竖屏下都为 0

    + (BOOL)isiPhoneX {
        if (@available(iOS 11.0, *)) {
            UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
            // 获取底部安全区域高度,iPhone X 竖屏下为 34.0,横屏下为 21.0,其他类型设备都为 0
            CGFloat bottomSafeInset = keyWindow.safeAreaInsets.bottom;
            if (bottomSafeInset == 34.0f || bottomSafeInset == 21.0f) {
                return YES;
            }
        }
        return NO;
    }
    
    

    不足:必须在 AppDelegate 的 didFinishLaunchingWithOptions 回调中等 keyWindow 初始化之后才能正确判断

    方式四:通过是否支持 FaceID 判断
    由于目前只有 iPhone X 设备支持 FaceID,因此我们也可以通过判断设备是否支持 FaceID 来判断,代码如下:

    + (BOOL)canUseFaceID {
        if (@available(iOS 11.0, *)) {
            // will fail if user denies `canEvaluatePolicy:error:`
            LAContext *context = [[LAContext alloc] init];
            if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:nil]) {
                return (context.biometryType == LABiometryTypeFaceID);
            }
        }
        return NO;
    }
    

    不足:如果用户禁用 canEvaluatePolicy:error: 方法的使用将无法正确判断,而且在也不适用于模拟器中的判断。
    方式五:通过 UIStatusBar 的高度判断
    在 iPhone X 之前,所有 iPhone 设备的 StatusBar(状态栏)高度都为 20pt,而 iPhone X 的为 44pt,因此我们可以通过获取状态栏的高度判断是否等于 44.0 来检测设备是否为 iPhone X,代码如下:

    + (BOOL)isiPhoneX {
        CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
        if (statusBarFrame.size.height == 44.0f) {
            return YES;
        }
        return NO;
    }
    

    不足:该方法只适用于竖屏且显示状态栏的情况下才能正确检测,
    而在横屏模式下,或者 App 隐藏导航栏时,获取到的状态栏高度都为 0(statusBarFrame 的值为 CGRectZero),就无法判断了。

    系统版本的宏
    #define IOS [[[UIDevice currentDevice] systemVersion] floatValue]
    #define IOS8 [[[UIDevice currentDevice] systemVersion] floatValue] >= 8 ? YES : NO
    #define IOS9 [[[UIDevice currentDevice] systemVersion] floatValue] >= 9 ? YES : NO
    #define IOS10 [[[UIDevice currentDevice] systemVersion] floatValue] >= 10 ? YES : NO
    #define IOS11 [[[UIDevice currentDevice] systemVersion] floatValue] >= 11 ? YES
    
    
    其它宏
    // debug下打印日志, release下不执行NSLog代码
    #ifdef DEBUG
    #define NSLog(...) printf("myAppInfo %s\n %s\n",__func__, [[NSString stringWithFormat:__VA_ARGS__]UTF8String]);
    #else
    #define NSLog(format, ...)
    #endif
    
    

    相关文章

      网友评论

          本文标题:屏幕适配

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