iDroid-Layout是将Android的布局系统和其可绘制的资源框架移植到iOS的一套工具。
这个项目的主要目的是为了更深入地了解Android布局系统的实现方式和原理。另一个原因是iOS缺乏高级的布局系统(更新:在iOS 6及以上版本中,由于引入了布局约束,这个情况不再成立)。在iOS中目前构建可维护的UI代码是很痛苦的事情。您可以选择在界面编辑器中布局,这对于静态布局很好,但对于动态内容则不够强大;或者全部通过代码实现,这使得代码难以维护。在Android中可以使用XML定义布局,视图会根据内容需求和父视图的大小限制自动调整其大小。
可以使用CocoaPods安装iDroidLayout
pod 'iDroidLayout'
使用iDroid-Layout定义和使用布局可以简单地分为两步
创建一个包含你的视图层次结构的布局xml文件,将其保存为myLayout.xml
。例如:
<LinearLayout
layout_width="match_parent"
layout_height="wrap_content"
orientation="vertical"
padding="10">
<LinearLayout
layout_width="match_parent"
layout_height="wrap_content"
orientation="horizontal">
<TextView
id="text"
layout_width="wrap_content"
layout_height="wrap_content"
padding="10"
text="Some text"
textColor="#ffffff"
background="#80000000"/>
<TextView
id="otherText"
layout_width="match_parent"
layout_height="match_parent"
padding="10"
textColor="#ffffff"
background="#ff0000"
gravity="right"
text="Some other text"/>
</LinearLayout>
<UIButton
id="button"
background="#ff0000"
layout_width="100"
layout_height="30"
layout_gravity="center_horizontal"
layout_marginTop="10"
text="Click me"/>
</LinearLayout>
创建一个IDLLayoutViewController的实例
IDLLayoutViewController *vc = [[IDLLayoutViewController alloc] initWithLayoutName:@"myLayout" bundle:nil];
[self.navigationController pushViewController:vc animated:TRUE];
[vc release];
享受
idroid-Layout 包含一个高级资源解析框架。它允许您引用资源,如图片、布局、字符串、颜色和样式。资源标识符允许(跨)引用资源。例如,它可以允许您在布局中指定视图的文本和图片。
资源标识符的语法如下:[<bundle-identifier>:]<resource-type>/<resource-name>[.<resource-subname>]
<bundle-identifier>
是包含资源的包的标识符。如果省略 bundle-identifier,资源将在主包中搜索。要使用除主包之外的其他包,您必须在使用具有该包的资源标识符之前至少加载该包一次。<resource-type>
是资源类型(以下之一:string
、layout
、drawable
、color
或 style
)<resource-name>
是资源文件的名称<resource-subname>
是资源文件中特定资源的标识符。这仅用于某些充当资源容器的资源类型。可绘制内容包括可以在屏幕上绘制的内容。这可以是简单的光栅图、颜色、形状或这些的组合。目前实现了以下类型的可绘制内容:
位图
位图图形(例如 png、jpg),也可以是 9-patch 图形
层列表
管理其他可绘制内容的可绘制内容。这些是按数组顺序绘制的,因此具有最大索引的元素在上面绘制
状态列表
根据可绘制状态引用其他可绘制内容的可绘制内容(例如,为不同的按钮状态绘制不同的图片)。
内嵌可绘制内容
在另一个可绘制内容中内嵌的可绘制内容
剪辑可绘制内容
根据可绘制层级别剪辑另一个可绘制内容
形状可绘制内容
绘制几何形状,可以用颜色或渐变填充
可绘制内容可以在 XML 中定义,并可以膨胀到可绘制对象树。以下是一个示例
<layer-list>
<item left="12" top="12" right="8" bottom="8">
<shape shape="rectangle">
<solid color="#8000"/>
<corners topLeftRadius="40" bottomRightRadius="10"/>
</shape>
</item>
<item left="10" top="10" right="10" bottom="10">
<shape shape="rectangle" thicknessRatio="8" innerRadiusRatio="3">
<gradient centerX="-0.1" centerY="-0.1" gradientRadius="300%" type="radial" startColor="#ccc" centerColor="#0fff" endColor="#0f0"/>
<corners topLeftRadius="40" bottomRightRadius="10"/>
<stroke width="1" color="#8000"/>
<padding left="5"/>
</shape>
</item>
<item>
<selector>
<item state_pressed="true">
<inset insetLeft="10" insetTop="10" insetRight="10" insetBottom="10">
<shape shape="rectangle">
<gradient startColor="#f00" centerColor="#0fff" endColor="#0ff"/>
<corners topLeftRadius="40" bottomRightRadius="10"/>
</shape>
</inset>
</item>
</selector
</item>
</layer-list>
假设你将可绘制 XML 保存到文件 background.xml
中。现在您可以在布局中这样定义一个按钮:
<Button
textColor="#eee"
layout_width="match_parent"
layout_height="100"
layout_gravity="center"
background="@drawable/background"
text="Button"/>
图1:正常状态下背景为自定义可绘制内容的按钮
图2:按下的状态下背景为自定义可绘制内容的按钮
IDLLayoutBridge
是一个 UIView,它 acting 作为普通视图布局机制和 iDroid-Layout 机制之间的桥梁。首先您必须创建一个 IDLLayoutBridge 对象并将其添加到您的视图层次结构中。现在您可以使用 IDLLayoutInflater
将 xml 布局加载到 IDLLayoutBridge
视图中。
IDLLayoutBridge *bridge = [[IDLLayoutBridge alloc] initWithFrame:CGRectMake(100, 100, 120, 220)];
IDLLayoutInflater *inflater = [[IDLLayoutInflater alloc] init];
[inflater inflateURL:[[NSBundle mainBundle] URLForResource:@"myLayout" withExtension:@"xml"] intoRootView:bridge attachToRoot:TRUE];
[inflater release];
[self.view addSubview:bridge];
[bridge release];
是的,您可以使用原生视图。只需使用视图的类名作为 XML 标签名(例如 <UIButton/>
)。但是,对于某些原生视图,onMeasureWithWidthMeasureSpec:heightMeasureSpec:
选择器尚未实现,因此您不应使用 wrap_content
为视图的宽度和高度。
是的,只需将视图类名用作XML标签名即可(例如:<MyCustomView/>
)。但是,您应该实现onMeasureWithWidthMeasureSpec:heightMeasureSpec:
选择器。否则,您不应为视图的宽度和高度使用wrap_content
。
IDLLayoutInflater
通常所做的)进行初始化。我该如何实现自定义初始化?IDLLayoutInflater
使用IDLViewFactory
协议的默认实现来创建视图对象。您可以通过实现协议并设置IDLLayoutInflater
的viewFactory
属性来创建自定义视图工厂。
UITableViewCell
中使用XML布局吗?是的,您可以使用IDLTableViewCell
或创建一个自定义的UITableViewCell
,将布局填充到一个IDLLayoutBridge
中。
是的,可以将布局XML文件展开到接口构建器中的视图。在接口构建器中简单添加一个普通视图,将新添加的视图的“自定义类”设置为IDLLayoutBridge
,并定义一个名为layout
的运行时用户定义属性,其值为XML文件的名称(不带文件扩展名)。有关更多详细信息,请查看示例项目。
类似于Android布局系统,您可以使用<include/>
和<merge/>
标签在布局XML文件中嵌入其他布局。在希望添加可重用组件的布局中添加标签。以下是一个示例
<LinearLayout
layout_width="match_parent"
layout_height="match_parent"
orientation="vertical">
<include layout="@layout/layoutToInclude"/>
<TextView
layout_width="match_parent"
layout_height="wrap_content"
text="Some text"/>
</LinearLayout>
您也可以通过在<include/>
标签中指定它们,覆盖包含布局的根视图的所有布局参数(任何layout_*
属性)、id以及可见性。例如
<include id="title"
layout_width="match_parent"
layout_height="match_parent"
layout="@layout/layoutToInclude"
visibility="gone"/>
XML文件始终需要一个根元素。如果您必须从一个具有单个根元素的另一个单布局文件中包含多个视图,您需要一个容器作为根元素。这就是<merge/>
标签发挥作用的地方。它允许您同时包含多个视图,而无需额外的布局容器。
<merge>
<TextView
layout_width="match_parent"
layout_height="wrap_content"
text="First text view"/>
<TextView
layout_width="match_parent"
layout_height="wrap_content"
text="Second text view"/>
</merge>
现在,当您在另一个布局中包含此布局(使用<include/>
标签)时,系统会忽略<merge/>
元素,并将两个文本视图直接放置在布局中,代替<include/>
标签的位置。