介绍一下Quartz 2D,主要资料来源于苹果官网;不足之处有请大家拍砖。
Quartz 2D是iPhone OS和Mac OS X环境下的二维绘图引擎。借用Quartz 2D API,你可以接触到这样一些特性:基于路径的绘图,透明度绘图,遮盖,阴影,透明层,颜色管理,防锯齿渲染,生成PDF,以及PDF元数据相关处理。可能的时候,Quartz 2D会借助硬件的力量。
在Mac OS X下,Quartz 2D能与其它图形图像技术相结合——Core Image,Core Video,OpenGL,以及Quick Time。
类似的,在iPhone OS下的Quartz 2D也能与其它的图像和动画技术相结合——Core Animation,OpenGL ES,以及UIKit类。
1. 页面(Page)
Quartz 2D使用画笔模型——每一个绘图操作在一块输出画布上进行一层绘制(paint),这个画布就叫做页面。绘制在页面上的东西无法改动,除非修改该页面。
下图显示了“后来者居上”的遮盖顺序。页面可以是一张真正的纸(如果输出设备是打印机);可以是一张虚拟的纸(如果输出设备是pdf);甚至可以是一幅位图。
2. 绘制目标:图形内容(Graphics Context)
图形内容是一个复杂的数据类型(CGContextRef),用于封装Quartz用于绘图的信息。这些信息包括了绘图参数以及页面上的绘图的代表。
同一幅画可以绘制到不同的设备上,而只需要改变图形内容的,无需改变Quartz绘制顺序。你不需要自行针对设备进行计算——Quartz会替你完成这一切。
3. Quartz 2D的模糊数据类型(Opaque Data Type)
在图形内容之外,Quartz 2D还定义了一系列模糊数据类型,均以CG为前缀。其中三种数据类型如下图所示。
4. 图形状态(Graphics States)
Quartz 2D根据当前的图形状态来修改绘图结果。例如,当你调用函数来填充颜色时,你同时也就修改了储存在图形状态中的数值。其它常用的图形状态颜色包括线宽,当前位置,以及字体大小。
图形内容包含了一个堆栈,储存了图形状态。初建图形内容时,此堆栈为空。图形状态可以通过函数 CGContextSaveGState 和 CGContextRestoreGState 来保存和恢复。
5.Quartz 2D坐标
Quartz 2D的坐标体系如下图所示,原点在左下方。
考虑到不同的设备有着不同的图像能力,因此图形的位置和大小必需独立于设备来定义——这由当前变换矩阵(CTM)来完成。
6. 内存管理
几个简单实用的准则:
6.1 如果你创建或复制一个对象,该对象的retain值会加一;因此你也必需释放它。具体反映在带有Create或Copy的函数名当中。
6.2 反之,如果函数名中没有Create或Copy,你就不需要释放。
6.3 如果你不拥有一个对象但需要使用它,你可以retain之后再释放
http://blog.codingmylife.com/?p=40
属性是一种定义类所提供的数据的通常方法。在Movie这个类里,诸如“标题”,“工作室”和“发布年份”等等都算是属性。这里是用Objective-C 1.x语法定义的Movie类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
@interface Movie : NSObject { NSString* title; NSString* studio; int yearReleased; } + (id)movie; - (NSString*)title; - (void)setTitle:(NSString*)aValue; - (NSString*)studio; - (void)setStudio:(NSString*)aValue; - (int)yearReleased; - (void)setYearReleased:(int)aValue; - (NSString*)summary; @end
这里是它在Objective-C 2.0里面的样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@interface Movie : NSObject { NSString* title; NSString* studio; NSInteger yearReleased; } + (id)movie; @property (copy) NSString* title; @property (copy) NSString* studio; @property (assign) NSInteger yearReleased; @property (readonly) NSString* summary; @end
需要注意的是并不是所有的东西都是属性。假如有一个生成新object的类方法 +move,这一类的东西不需要被声明成属性。
属性的定义格式如下:
1
@property (<parameters>) <type> <name>;
assign关键字代表setter直接赋值,而不是复制或者保留它。这种机制非常适合一些基本类型,比如NSInteger和CGFloat,或者你并不直接拥有的类型,比如delegates。
readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用。我们把 summary 定义为 readonly 是因为它并不需要一个专门的类变量,相应的,我们会在用到的时候动态生成它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
@implementation Movie + (id)movie { return [[[Movie alloc] init] autorelease]; } - (NSString*)title { return title; } - (void)setTitle:(NSString*)aValue { [title autorelease]; title = [aValue copy]; } - (NSString*)studio { return studio; } - (void)setStudio:(NSString*)aValue { [studio autorelease]; studio = [aValue copy]; } - (int)yearReleased { return yearReleased; } - (void)setYearReleased:(int)aValue { yearReleased = aValue; } - (NSString*)summary { NSNumber* yearAsObject; yearAsObject = [NSNumber numberWithInt:[self yearReleased]]; return [NSString stringWithFormat:@"%@ by %@, released in %@", [self title], [self studio], yearAsObject]; } @end
这里是 Objective-C 2.0 版本(启用了垃圾回收):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
@implementation Movie @synthesize title; @synthesize studio; @synthesize yearReleased; + (id)movie { return [[Movie alloc] init]; } - (NSString*)summary { NSNumber* yearAsObject; yearAsObject = [NSNumber numberWithInteger:self.yearReleased]; return [NSString stringWithFormat:@"%@ by %@. Released in %@.", self.title, self.studio, yearAsObject]; } @end
@synthesize 指令生成了相应的访问方法,垃圾回收代表 +movie 不需要 autorelease它返回的object。还有,我们使用了self.title,self.studio替代了[self title]和[self studio]。
现在让我们从使用者的角度看看Movie类:
1 2 3 4 5 6
Movie* newMovie = [Movie movie]; newMovie.title = @"The Incredibles"; newMovie.studio = @"Pixar"; newMovie.yearReleased = 2004; NSLog (@"Movie summary: %@", newMovie.summary);
运行结果:
1
Movie summary: The Incredibles, by Pixar. Released in 2004.
在Objective-C 2.0中你可以同时使用两种属性访问方式。”.”操作符并不是唯一的方法。你也可以使用”.”访问没有被明确定义的属性。例如:
1 2
NSString* newString = [textField stringValue]; NSString* newString = textField.stringValue;
@property和@synthesize的区别可能在一开始并不容易看出来。@property定义一个已经存在的属性,而@synthesize实现了具体的访问方法,如果需要的话。
注:当getter需要返回一个有效值的时候synthesize标记会被默认使用。如果启用了垃圾回收的话,这不会产生任何额外的开销。你可以使用 nonatomic 关键字来禁用这个行为。
在有APKTool之前,Android软件的汉化是一件非常痛苦的事情。例如汉化狂人的汉化工具,那都是直接修改二进制文件的,首先是寻找需要修改的字符串苦难(当然汉化狂人已经做得不错了),然后修改的字符串长度还要注意中文长度不能长过原来的文字……个中郁闷就不细说了。
APKTool可以说是一个革命性的工具,有了APKTool之后,可以说,俺拽软件的汉化工作到了一个前所未有的简单程度。
闲话不说,我们用汉化实例来证明APKTool的方便简单,在动手之前,需要去 APKTool 的网站把工具下载下来。当然也可以下载我已经打包的 APKTool.zip(Windows下使用)。
确保你的电脑已经安装了JDK1.6(JRE1.6也可以),而且安装了一个优秀的编辑软件(推荐UltraEdit),把APKTool解压到随便哪个你认为操作起来方便的目录。如果都好了,我们动手吧:
第一步,把需要汉化的文件(以汉化ColorNote为例)放到APKTool所在目录,然后命令行进入APKTool目录,执行下面的命令:
apktool d ColorNote.apk ColorNote
这句命令的意思是,对ColorNote.apk这个程序进行反编译,获得的文件放在当前目录下的ColorNote目录中。正常反编译的话,能看到下面的提示:
反编译完成,会在APKTool的目录下面,出现一个名叫ColorNote的目录,进去看看,是这个样子的!
用UltraEdit打开这个AndroidManifest.xml看看?哈哈,是纯文本文件呀!在打开res目录中的values中随便一个文件看看?也是纯文本文件啊!也就是说,只要一个UltraEdit,我们就可以轻轻松松进行汉化了(就把需要的字符串转换成中文就可以了,也不用考虑长度了!)至于要汉化哪些内容,这个大家自己研究吧,不用我详细说,也没有办法详细说的吧?(事实上,除了XML的文本资源文件外,老外写的很多程序,字符串都是hard coding在执行代码里面的,APKTool反编译会得到smali伪代码,有些在XML资源里面找不到的字符串,去看看smali的代码吧。)
中间的翻译过程我们跳过去,例如我们已经翻译好了,就在APKTool目录下执行下面的命令行:
apktool b ColorNote
这条命令是告诉APKTool,把这个ColorNote目录里的东西编译打包成APK程序
I: Checking whether sources has changed…
I: Smaling…
I: Checking whether resources has changed…
I: Building resources…
I: Building apk file…
生成的APK程序在哪里呢?在ColorNote\Dist目录里面,名字是out.apk
我们把这个out.apk文件签名之后安装看看?哈哈!完美中文汉化的俺拽程序来了!(当然,这要看汉化者的功力了。)