2007年1月9日,Macworld大会如期在美国旧金山召开。在乔布斯说完Apple TV后,现场的Keynote切换到下面这张传奇性的图片上,这就像是在预示之后iPhone的辉煌。
从2007年到现在,苹果发布了6代iPhone,这款智能手机彻底改变了全球用户与移动设备交互的方式。
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;
}
相对于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添加了一层第三方代码,所以效率很高,而且是专为高性能设计的(例如,通过自动添加约束到最近的原始视图)。
有机会,我们将以代码来详细的分析各种方式的不同。
扩展: