当Fuse的默认组件难以满足我们需求的时候我们就可以通过自建UI组件来在App中使用,具体方法如下:
首先,我们需要引入一个概念——ux:Class
"类"属性:
ux类的建立(ux:Class)
我们通过在UX markup代码里指定一个节点的ux:Class
属性来定义一个新的组件类,“类”是一个可以在你的项目中的其它位置,通过实例化来重复多次使用的组件。
ux:Class
建立了一个独立而功能齐全的组件,能被用到项目的任何地方。在类的自身之外是�无法访问到ux:Name
s的,如果需要建立一个在某些特定的上下文情况中能有权限访问到ux:Name
s的类的话请参看ux:InnerClass
区。
Example
下面的代码建立了一个从Text
元素继承的被称为Header
的类:
<Text ux:Class="Header" FontSize="22" />
他能被实例化,就像其它的Fuse标准内建元素一样。
<Header>Welcome</Header>
在上述例子中,Header
类将成为一个来自于但不同于Text类的类, 尽管所有的可用属性都来自于Text。注意,类可以放在单独的.ux
文件中定义,通常情况下也一般是这么来定义的。
自定义类也可以做到很复杂的效果,如果你有需求的话:
<pre>
<Image ux:Class="BurgerIcon">
<MultiDensityImageSource>
<FileImageSource File="Burger.png" Density="1"/>
<FileImageSource File="Burger.png@2x.png" Density="2"/>
</MultiDenistyImageSoruce>
</Image>
<Panel>
<BurgerIcon />
</Panel>
</pre>
他们可以有自己的逻辑性"logic",包括使用触发器、动作、和JavaScript等(triggers, actions)。
注意:使用ux:Class
建立的类�映射到了真正的Uno类里边Uno-classes,可以理解成为原生的了吧:
如:
<Panel ux:Class="MyPanel"/>
等同于下面的Uno类Uno-class:
public class MyPanel : Panel { ... }
ux类的属性定义(ux:Property)
当建立一个自定义类时,在很多情况下,我们需要能够定义出能实现交互效果的类,这可以通过UX来实现,使用的是ux:Property
语法,这样我们就可以在实例化时用属性来在有限的范围内控制自己所写的类了。
MyButton.ux:
<pre>
<Panel ux:Class="MyButton" Text="Click me!"
Fill="#f00" TextColor="#000" CornerRadius="10">
<string ux:Property="Text"/>
<float4 ux:Property="CornerRadius" />
<Brush ux:Property="Fill" />
<float4 ux:Property="TextColor"/>
<Text Alignment="Center" TextColor="{Property this.TextColor}" Value="{Property this.Text}"/>
<Rectangle Layer="Background" CornerRadius="{Property this.CornerRadius}" Fill="{Property this.Fill}" />
</Panel>
</pre>
上例我们建立了一个称为MyButton的类,定义了并陈列出四个自定义的属性(Text, CornerRadius, Fill and TextColor)。这些属性能被梆定到我们的类ux:Class之内,使用{Property this.PropName}
句式来实现。
- 注意:现在存在一个被称为
this
的隐藏名称,我们一般在{Property this.PropName}
句式之内使用,此名称常用来引用ux:Class
里的最顶级根元素。(易咸注:其实个人觉得可以理解为面向对象里边的this指针,this指向的是实例化时的对象本身)。
实例化时自定义ux类的属性传递(ux:Property)
当我们实例化了我们自己定义的类的时候,就可以直接访问变量了。
MainView.ux:
<pre>
<App>
<MyButton CornerRadius="20" Text="MyText"
TextColor="#fff" Width="200" Height="50">
<LinearGradient ux:Binding="Fill">
<GradientStop Color="#0f0" Offset="0" />
<GradientStop Color="#00f" Offset="1" />
</LinearGradient>
</MyButton>
</App>
</pre>
你可以使用ux:Binding
来设置或访问父元素引用类别的属性,像笔刷Brush
这类,在上例中,我们建立了一个线性渐变LinearGradient
,接着又把它梆定到父元素的Fill
属性上,从而看起来像是直接作为Fill使用的。
我们做一个图来分析一下
通过此图我们不难看出:
- 定义类时使用的元素样本是可以设置默认值的,当实例化时如果没有设置这个属性的值的话,会使用在类中的默认值来实例化类(已测,公共属性与自定义属性都支持默认值的设置);
- 像Width和Height这些元素公共属性在实例化时是可以直接使用的,也就是是说无须做自定义属性的,因为生成的实例继承了类中样本元素的属性(已测);
- 如果你定义类的自定义属性时使用了与样本元素的公共属性集里的名称,也就是说重名了的话,Fuse不会提示错误,但是你的自定义属性不会生效(已测),可在此处查到这些元素对应的属性https://www.fusetools.com/learn/reference;
可见量/数组属性 Observable/Array properties
如果你想进入一个可见量或数组以属性的方式,可以用object
类型,如下例:
<pre>
<Panel ux:Class="ListView">
<object ux:Property="ListItems" />
<StackPanel>
<Each Items="{Property this.ListItems}">
<Panel Padding="10">
<Text Value="{}" />
</Panel>
</Each>
</StackPanel>
</Panel>
<JavaScript>
exports.items = ["Foo", "Bar", "Baz"];
</JavaScript>
<ListView ListItems="{items}" />
</pre>
ux内部类(ux:InnerClass)
内部类的定义
内部类是定义在其他类内部的类。它几乎可以处于类内部任何位置,可以与实例变量处于同一级,或处于方法之内,甚至是一个表达式的一部分!
优点如下
⒈ 内部类对象可以访问创建它的对象的实现,包括私有数据;
⒉ 内部类不为同一包的其他类所见,具有很好的封装性;
⒊ 使用内部类可以很方便的编写事件驱动程序;
⒋ 匿名内部类可以方便的定义运行时回调;
好了,普及完了,回归正题吧!
一个内部类隶属于一个特定的范围或作用域,而且对在此作用域中声明的ux:Name
s具有访问权限。内部类仅仅只能用在声明过他的作用域中。
<pre>
<App Theme="Basic">
<Button ux:InnerClass="ActivateButton" ux:Name="btn" Margin="10">
<Clicked>
<Set highlight.LayoutMaster="btn" />
</Clicked>
</Button>
<StackPanel>
<ActivateButton Text="Option A" ux:Name="defaultOption"/>
<ActivateButton Text="Option B" />
<ActivateButton Text="Option C" />
<Rectangle Fill="Red" ux:Name="highlight" Margin="-5" LayoutMaster="defaultOption">
<LayoutAnimation>
<Move RelativeTo="PositionChange" X="1" Y="1" Duration="0.4" Easing="BackOut" />
</LayoutAnimation>
</Rectangle>
</StackPanel>
</App>
</pre>
ux文件包含(ux:Include)
你可以插入一个UX文件中的内容到另外一个UX文件中,使用ux:Include。
上面例子,ux:InnerClass
能被分开成单独的文件,分离后的主文件大致如下:
<pre>
<App Theme="Basic">
<ux:Include File="ActivateButton.ux" />
<StackPanel>
<ActivateButton Text="Option A" ux:Name="defaultOption"/>
...
</StackPanel>
</App>
</pre>
需要引用的代码放到ActivateButton.ux
中:
<pre>
<Button ux:InnerClass="ActivateButton" ux:Name="btn" Margin="10">
<Clicked>
<Set highlight.LayoutMaster="btn" />
</Clicked>
</Button>
</pre>
需要注意的是,包含的文件不能有ux:Class
在文档根节点,那样的话将会在你的项目中建立基于类生成的两个实例,可是,包含文件能指定ux:InnerClass
。这将建立一个内部类的本地版本,在每一个包含他的位置。
附:
英文原文:https://www.fusetools.com/learn/fuse#creating-custom-ui-components
高级部分参看,建立一个新类
https://www.fusetools.com/learn/guides/ux-markup-creating-new-classes
属性与梆定Properties and bindings
https://www.fusetools.com/learn/guides/ux-markup-properties-and-bindings
使用你自己的Uno类Using your own Uno classes
https://www.fusetools.com/learn/guides/ux-markup-using-your-own-classes
Tag:Fuse, Fuseapp, Fusetools, native app
发布时间:2016年05月10日
博客被黑,挪窝简书安家……