iPhone的进化

2007年1月9日,Macworld大会如期在美国旧金山召开。在乔布斯说完Apple TV后,现场的Keynote切换到下面这张传奇性的图片上,这就像是在预示之后iPhone的辉煌。

iPhone的开始

从2007年到现在,苹果发布了6代iPhone,这款智能手机彻底改变了全球用户与移动设备交互的方式。

iPhone尺寸的进化

iPhone尺寸

Scale

iOS绘制图形均以point为单位

1 point = 1 pixel(Point Per Inch=Pixel Per Inch=PPI)

早期的iPhone3GS的屏幕分辨率是320x480(PPI=163),后来在iPhone4中,同样大小(3.5 inch)的屏幕采用了Retina显示技术,横、纵向方向像素密度都被放大到2倍,像素分辨率提高到(320x2)x(480x2)= 960x640(PPI=326), 显像分辨率提升至iPhone3GS的4倍(1个Point被渲染成1个2x2的像素矩阵)。

但是对于开发者来说,iOS绘制图形的API依然沿袭point为单位。在同样的逻辑坐标系下(320x480):

1 point = scale x pixel(在iPhone4~6中,缩放因子scale=2;在iPhone6+中,缩放因子scale=3)。

可以理解为:

scale=绝对长度比(point/pixel)=单位长度内的数量比(pixel/point)

为了自动适应分辨率,系统会根据设备实际分辨率,自动给UIScreen.scale赋值,该属性对开发者只读。

iPhone3GS时代,我们为一个应用提供图标(或按钮提供贴图),只需要icon.png。针对现在的iPhone4~6 Retina显示屏,需要制作额外的@2x高分辨率版本。

iPhone6+在实际渲染时,准确的讲,应该是@2.46x。苹果为方便开发者用的是@3x的素材,然后再缩放到@2.46x上。

需要注意的是,iOS APP图标的尺寸和命名都需要遵守相关规范。

对于iPhone3、4/5/6、6+三类机型,需要按分辨率提供相应的高倍图并且文件名添加相应后缀,否则会拉伸(stretchable/resizable)失真(模糊或边角出现锯齿)。

机型辨别

通过[[UIDevice currentDevice] model]只能判别iPhone、iPad、iPod大类,要判断iPhone具体机型型号,则需要通过sysctlbyname(“machine”)获取详细的设备参数信息予以甄别(代码参考下面)。

判别iPhone、iPad、iPod大类

NSLog(@"globallyUniqueString=%@",[[NSProcessInfo processInfo] globallyUniqueString]);//全球唯一标识
NSLog(@"uniqueIdentifie=%@",[UIDevice currentDevice].uniqueIdentifier);//唯一的标识 可用于区分设备
NSLog(@"name=%@",[UIDevice currentDevice].name);//设备的名称  李四的 iPad、王五的 iPad .。。
NSLog(@"systemName=%@",[UIDevice currentDevice].systemName);//系统的名称  iPhone OS
NSLog(@"systemVersion=%@",[UIDevice currentDevice].systemVersion);//设备系统的版本号  5.1.1、6.0
NSLog(@"model=%@",[UIDevice currentDevice].model);//设备的型号   iPad、iphone、ipod touch。。。
NSLog(@"localizedModel=%@",[UIDevice currentDevice].localizedModel);//本地化的模型  iPad
NSLog(@"batteryLevel=%lf",[UIDevice currentDevice].batteryLevel);//电池电量

设备参数信息

@implementation DeviceManager


+ (NSString*)getDeviceVersion

{

size_t size;

sysctlbyname("machine",NULL, &size, NULL,0);

char *machine = (char*)malloc(size);

sysctlbyname("machine", machine, &size,NULL, 0);

NSString *platform = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding];

//NSString *platform = [NSString stringWithUTF8String:machine];二者等效

free(machine);

return platform;

}


+ (NSString *)getPlatformString

{

NSString *platform = [self getDeviceVersion];

//iPhone

if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 1";

if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3";

if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS";

if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4";

if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4s";

if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5";

if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5";

if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5C";

if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5C";

if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5S";

if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5S";

if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6";

if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6 Plus";

//iPot Touch

if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch";

if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2";

if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3";

if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4";

if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5";

//iPad

if ([platform isEqualToString:@"iPad1,1"]) return @"iPad";

if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,4"]) return @"iPad 2";

if ([platform isEqualToString:@"iPad2,5"]) return @"iPad Mini 1";

if ([platform isEqualToString:@"iPad2,6"]) return @"iPad Mini 1";

if ([platform isEqualToString:@"iPad2,7"]) return @"iPad Mini 1";

if ([platform isEqualToString:@"iPad3,1"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,2"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,3"]) return @"iPad 3";

if ([platform isEqualToString:@"iPad3,4"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad3,5"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad3,6"]) return @"iPad 4";

if ([platform isEqualToString:@"iPad4,1"]) return @"iPad air";

if ([platform isEqualToString:@"iPad4,2"]) return @"iPad air";

if ([platform isEqualToString:@"iPad4,3"]) return @"iPad air";

if ([platform isEqualToString:@"iPad4,4"]) return @"iPad mini 2";

if ([platform isEqualToString:@"iPad4,5"]) return @"iPad mini 2";

if ([platform isEqualToString:@"iPad4,6"]) return @"iPad mini 2";

if ([platform isEqualToString:@"iPad4,7"]) return @"iPad mini 3";

if ([platform isEqualToString:@"iPad4,8"]) return @"iPad mini 3";

if ([platform isEqualToString:@"iPad4,9"]) return @"iPad mini 3";

if ([platform isEqualToString:@"iPad5,3"]) return @"iPad air 2";

if ([platform isEqualToString:@"iPad5,4"]) return @"iPad air 2";

if ([platform isEqualToString:@"iPhone Simulator"] || [platform isEqualToString:@"x86_64"]) return @"iPhone Simulator";

return platform;

}

iOS布局的三种方式

相对于Android开发,界面的管理就两种方式,一种是纯代码,另外一种是XML布局方式。 对于实现ios界面总的来说,有三种方式,传统的是纯代码创建与xib创建和storyboard方式。下面我们就简单的看一看他们的不同。

纯代码创建

优点:可以灵活地适应各种环境,无论是什么ios版本,或者iPhone,ipad,都可以动态地适应各种场景。

缺点:代码量大,构建控件麻烦,点击的监听函数和delegate要自己手动创建。

xib方式创建
xib文件是一个xml文件,右键xib文件,用source code方式打开就可以看到里面的内容了。使用xib创建视图,就如同Android的XML一样,但是它比Android的XML方式还强大。可以直接设置控件的监听函数与delegate,控件的各种属性基本都能设置。

优点:每个viewcontroller对应单独的xib,可以更加方便单独管理,项目也方便多人一起开发,改动视图方便,不用全局改动。

缺点:项目大的话,xib文件过多,不容易统一管理。跳转只能在代码实现,比较混乱。

storyboard方式

storyboard方式是ios5之后Apple提供了一种全新的方式。简单来说,StoryBoard是一个包含了多个xib与xib之间跳转关系的文件。在StoryBoard中不仅可以看到每个ViewController的布局样式,也可以知道各个ViewController之间的转换关系。

优点:所有xib集中在一个storyboard文件中,管理方便,View Controller跳转很轻松就可以实现,大大减少代码量。

缺点:由于所有xib都集中在一个文件中,对于一些大型项目,分工起来就比较困难,不好分工,而且采用storyboard方式对系统资源的耗费比代码和xib方式要大。

代码实现自动布局的几种方式

1.NSLayoutConstraint

AutoLayout是从IOS 6开始苹果引入来取代autoresizing的新的布局技术。autolayout能够设置视图的大小(即视图的绝对大小),视图的位置(视图相对于父视图或者兄弟视图的位置),视图的对齐方式(相对于父视图或者相对于兄弟视图)。

+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

该方法实际上就是满足一个数学关系

item1 =(>=,<=) multiplier * item2 + constant。

翻译过来就是:

第一个视图(宽度) = 2 * 第二个视图(宽度) + 0 

控制的属性

NSLayoutAttributeLeft
视图的左边

NSLayoutAttributeRight
视图的右边

NSLayoutAttributeTop
视图的上边

NSLayoutAttributeBottom
视图的下边

NSLayoutAttributeLeading
视图的前边

NSLayoutAttributeTrailing
视图的后边

NSLayoutAttributeWidth
视图的宽度

NSLayoutAttributeHeight
视图的高度

NSLayoutAttributeCenterX
视图的中点的X值

NSLayoutAttributeCenterY
视图中点的Y值

NSLayoutAttributeBaseline
视图的基准线

NSLayoutAttributeNotAnAttribute
无属性

2.MyLinearLayout

这套布局库是以android的线性布局,相对布局,框架布局,表格布局为蓝本。同时又具有IOS的AutoLayout的功能,和部分SIZECLASS功能,以及IOS9中的UIStackView的功能,参考了masonry的一些语法机制。使用简单方便,代码清晰。

3.Masonry

Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用更优雅的链式语法封装自动布局 简洁明了 并具有高可读性 而且同时支持 iOS 和 Max OS X。

4.PureLayout
PureLayout是iOS Auto Layout的终端API,强大而简单。由UIView、NSArray和NSLayoutConstraint类别组成。

PureLayout为大多数Auto Layout用例提供了一个开发者友好型的界面。简洁清晰,灵感来自于Interface Builder的Auto Layout UI选项,但是更灵活,功能更强大。该API添加了一层第三方代码,所以效率很高,而且是专为高性能设计的(例如,通过自动添加约束到最近的原始视图)。

有机会,我们将以代码来详细的分析各种方式的不同。

扩展:

Icon and Image Sizes

ios项目icon和default图片命名规则

苹果官网

APP界面设计