iDroidLayout 0.0.1

iDroidLayout 0.0.1

测试已测试
Lang语言 Obj-CObjective C
许可证 Apache 2
发布最新发布2014年12月

Tom Quist维护。




  • Tom Quist

iDroid-Layout

iDroid-Layout是将Android的布局系统和其可绘制的资源框架移植到iOS的一套工具。

当前版本为预alpha实验版,API不稳定。在了解情况之前不要使用它!

为什么?

这个项目的主要目的是为了更深入地了解Android布局系统的实现方式和原理。另一个原因是iOS缺乏高级的布局系统(更新:在iOS 6及以上版本中,由于引入了布局约束,这个情况不再成立)。在iOS中目前构建可维护的UI代码是很痛苦的事情。您可以选择在界面编辑器中布局,这对于静态布局很好,但对于动态内容则不够强大;或者全部通过代码实现,这使得代码难以维护。在Android中可以使用XML定义布局,视图会根据内容需求和父视图的大小限制自动调整其大小。

亮点

  • 使用XML定义布局
  • 在布局XML中使用原生UI小部件,如UIButton、UITextField等,甚至可以自定义视图的子类
  • 线性布局(LinearLayout),以及从右到左或从上到下的布局
  • 相对布局(RelativeLayout),可以根据彼此和父视图的位置布局视图
  • 将视图添加到UIScrollViews中,让它们根据布局自动调整内容大小
  • 通过实现自定义布局容器来扩展布局系统
  • 在Interface Builder中加载动态XML布局
  • 使用功能强大的资源管理器维护资源
  • 在XML中定义可维护的可视图形,并在运行时实时渲染
  • 支持9-Patch PNG

入门

可以使用CocoaPods安装iDroidLayout

Podfile

pod 'iDroidLayout'

使用iDroid-Layout定义和使用布局可以简单地分为两步

  1. 创建一个包含你的视图层次结构的布局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>
    
  2. 创建一个IDLLayoutViewController的实例

    IDLLayoutViewController *vc = [[IDLLayoutViewController alloc] initWithLayoutName:@"myLayout" bundle:nil];
    [self.navigationController pushViewController:vc animated:TRUE];
    [vc release];
    
  3. 享受

    Layout

资源

idroid-Layout 包含一个高级资源解析框架。它允许您引用资源,如图片、布局、字符串、颜色和样式。资源标识符允许(跨)引用资源。例如,它可以允许您在布局中指定视图的文本和图片。

资源标识符语法

资源标识符的语法如下:[<bundle-identifier>:]<resource-type>/<resource-name>[.<resource-subname>]

  • <bundle-identifier>是包含资源的包的标识符。如果省略 bundle-identifier,资源将在主包中搜索。要使用除主包之外的其他包,您必须在使用具有该包的资源标识符之前至少加载该包一次。
  • <resource-type>是资源类型(以下之一:stringlayoutdrawablecolorstyle
  • <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"/>

Button in normal state

图1:正常状态下背景为自定义可绘制内容的按钮

Button in pressed state

图2:按下的状态下背景为自定义可绘制内容的按钮

问题和答案

我不想从布局 XML 加载整个视图层次结构。我如何将布局加载到我现有视图层次结构的一部分中?

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

我的自定义视图不应使用init(类似于IDLLayoutInflater通常所做的)进行初始化。我该如何实现自定义初始化?

IDLLayoutInflater使用IDLViewFactory协议的默认实现来创建视图对象。您可以通过实现协议并设置IDLLayoutInflaterviewFactory属性来创建自定义视图工厂。

我可以在UITableViewCell中使用XML布局吗?

是的,您可以使用IDLTableViewCell或创建一个自定义的UITableViewCell,将布局填充到一个IDLLayoutBridge中。

我能否将XML布局加载到XIB文件中定义的视图中?

是的,可以将布局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/>标签的位置。