第二十三章:触发器和行为(二)

简介: 触发器在最普遍(和最模糊)的意义上,触发器是导致响应的条件。 更具体地说,触发器通过设置另一个属性或运行一些代码来响应属性更改或触发事件。 几乎总是,设置的属性或运行的代码涉及用户界面,并在XAML中表示。

触发器

在最普遍(和最模糊)的意义上,触发器是导致响应的条件。 更具体地说,触发器通过设置另一个属性或运行一些代码来响应属性更改或触发事件。 几乎总是,设置的属性或运行的代码涉及用户界面,并在XAML中表示。
VisualElement和Style都定义了IList 类型的Triggers属性。 抽象TriggerBase类派生自BindableObject。 四个密封类派生自TriggerBase:

  • Trigger设置属性(或运行代码)以响应属性更改。
  • EventTrigger,用于运行代码以响应事件。
  • DataTrigger,用于设置属性(或运行代码)以响应数据绑定中引用的属性更改。
  • MultiTrigger用于在发生多个触发器时设置属性(或运行代码)。

这些之间的差异将在实践中变得更加清晰。
最简单的触发器
在其通常的形式中,Trigger类检查元素的属性更改,并通过设置同一元素的另一个属性来响应。
例如,假设您设计了一个包含多个Entry视图的页面。 您已经确定当特定条目获得输入焦点时,您希望条目变大。 您希望使条目脱颖而出,包括用户键入的文本。
更具体地说,当Entry的IsFocused属性变为True时,您希望Entry的Scale属性设置为1.5。 当IsFocused属性恢复为False时,您希望Scale属性也恢复为其先前的值。
为了适应这个概念,Trigger定义了三个属性:

  • BindableProperty类型的属性。
  • 对象类型的值。
  • IList类型的setter。 这是Trigger的内容属性。

必须设置所有这些属性才能使触发器起作用。 从TriggerBase,Trigger继承了另一个基本属性:

  • TargetType 类型为Type。

这是连接触发器的元素的类型。
Trigger的Property和Value属性有时被认为是一个条件。 当Property引用的属性的值等于Value时,条件为true,并且Setter对象的集合将应用于该元素。
正如您将在第12章“样式”中回忆的那样,Setter定义了两个与前两个Trigger属性相同的属性:

  • Property 类型为BindableProperty。
  • Value类型为Object。

使用触发器,我们只处理可绑定属性。 Trigger条件属性必须由BindableProperty以及Setter设置的属性支持。
当条件变为false时,Setter对象是“未应用的”,这意味着Setter引用的属性将恢复为没有Setter的值,这可能是属性的默认值,直接设置的值 元素,或通过Style应用的值。
这是EntryPop程序的XAML文件。 页面上的三个Entry视图中的每一个都使用Entry.Triggers属性元素标记将一个Trigger对象添加到其Triggers集合中。 每个Trigger对象都有一个Setter添加到其Setters集合中。 因为Setters是Trigger的content属性,所以不需要Trigger.Setters属性元素标记:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="EntryPop.EntryPopPage"
             Padding="20, 50, 120, 0">
    <StackLayout Spacing="20">
        <Entry Placeholder="enter name"
                AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
        <Entry Placeholder="enter address"
                AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
        <Entry Placeholder="enter city and state"
                    AnchorX="0">
            <Entry.Triggers>
                <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                    <Setter Property="Scale" Value="1.5" />
                </Trigger>
            </Entry.Triggers>
        </Entry>
    </StackLayout>
</ContentPage>

每个Trigger对象必须设置其TargetType,在这种情况下,这是一个Entry。 在内部,Trigger使用PropertyChanged处理程序来监视IsFocused属性的值。 当该属性等于True时,单个Setter对象将Scale属性设置为1.5。 AnchorX设置为零会指示从Entry的左侧进行缩放。 (AnchorX的非默认值表示如果更改iOS屏幕的方向,则无法正确定位Entry视图。)
当Entry失去输入焦点并且IsFocused属性再次变为False时,Trigger会自动删除Setter的应用程序,在这种情况下,Scale属性将恢复为
它的预触发值,不一定是它的默认值。
以下是带有输入焦点的放大的Entry视图:
2019_03_27_095039
此示例中的每个Entry视图只有一个Trigger,每个Trigger只有一个Setter,但在一般情况下,visual元素在其Triggers集合中可以有多个Trigger对象,每个Trigger在其Setters集合中可以有多个Setter对象。
如果要在代码中执行类似的操作,则可以将PropertyChanged事件处理程序附加到每个Entry,并通过设置Scale属性来响应IsFocused属性中的更改。 触发器的优点是你可以在定义元素的位置完成标记的整个工作,留下工作代码可能比增加Entry元素的大小更重要!
因此,您不太可能需要在代码中创建Trigger对象。 从来没有,EntryPopCode程序演示了你是如何做到的。 代码已被设计为尽可能类似于XAML:

public class EntryPopCodePage : ContentPage
{
    public EntryPopCodePage()
    {
        Padding = new Thickness(20, 50, 120, 0);
        Content = new StackLayout
        {
            Spacing = 20,
            Children = 
            {
                new Entry
                {
                    Placeholder = "enter name",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                },
                new Entry
                {
                    Placeholder = "enter addresss",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                },
                new Entry
                {
                    Placeholder = "enter city and state",
                    AnchorX = 0,
                    Triggers = 
                    {
                        new Trigger(typeof(Entry))
                        {
                            Property = Entry.IsFocusedProperty,
                            Value = true,
                            Setters = 
                            {
                                new Setter
                                {
                                    Property = Entry.ScaleProperty,
                                    Value = 1.5
                                }
                            }
                        }
                    }
                }
            }
        };
    }
}

XAML和代码之间唯一真正的区别是TargetType属性的处理。 在XAML中,TargetType属性在三个Trigger定义中的每一个中设置为“Entry”。 但是,在代码中,必须将typeof(Entry)作为参数传递给Trigger构造函数。 如果查看Trigger类的文档,则会发现TargetType属性是get-only。 XAML解析器使用TargetType属性设置来实例化Trigger对象。
Style类还定义了IList 类型的Triggers属性,这意味着您可以使用Style在多个元素之间共享Trigger对象。 StyledTriggers程序显示了如何。 请注意,Style和Trigger标记都包含TargetType属性设置。 Style包含一个Setter对象,并为单个Trigger对象使用Style.Triggers属性 - 元素标记,该对象还包含Setter对象:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="StyledTriggers.StyledTriggersPage"
             Padding="20, 50, 120, 0">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Entry">
                <Setter Property="AnchorX" Value="0" />
                <Style.Triggers>
                    <Trigger TargetType="Entry" Property="IsFocused" Value="True">
                        <Setter Property="Scale" Value="1.5" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Spacing="20">
        <Entry Placeholder="enter name" />
        <Entry Placeholder="enter address" />
        <Entry Placeholder="enter city and state" />
    </StackLayout>
</ContentPage>

由于Style没有字典键,因此它是一种隐式样式,可自动应用于Entry类型的所有元素。 单个Entry元素只需包含每个元素的唯一元素。
也许在尝试使用EntryPop程序(或两个变体)之后,您决定不希望Scale属性简单地“弹出”到值1.5。 你想要一个动画。 您希望它在获得输入焦点时“膨胀”大小,并在失去输入焦点时将其动画恢复正常。
那也是可能的。

目录
相关文章
|
JavaScript Android开发
第二十三章:触发器和行为(十二)
淡化和定向在本书中,您已经看到了几个颜色选择程序,可以通过使用三个Slider元素以交互方式形成颜色。 本章的最后一个示例是另一个颜色选择程序,但是这个程序为您提供了选项:它包含三个标记为“RGB Hex”,“RGB Float”和“HSL”的单选按钮(实际上是简单的Label元素)。
677 0
|
JavaScript Android开发
第二十三章:触发器和行为(十一)
单选按钮内置于旧汽车仪表板中的无线电通常具有一排六个(左右)按钮,可以为各种无线电台“编程”。 按下其中一个按钮会导致无线电跳转到该预选电台,并且还会弹出前一个选择按钮。那些旧的汽车收音机现在是古董,但我们的电脑屏幕上的互斥选项仍然由我们称为单选按钮的视觉对象表示。
883 0
|
JavaScript Android开发
第二十三章:触发器和行为(十)
响应水龙头切换视图的各种表现形式演示了一种响应XAML文件中的点击的方法。 如果将tap事件集成到VisualElement类中,您可以使用EventTrigger更直接且更轻松地获取它们。 但是您无法将EventTrigger附加到TapGestureRecognizer。
523 0
|
JavaScript Android开发 Windows
第二十三章:触发器和行为(九)
切换和复选框在第15章“交互式界面”和第16章“数据绑定”中,您了解了如何构造传统的CheckBox视图。 但是,自定义视图的另一种方法是将视图的交互逻辑合并到行为中,然后完全在XAML中实现视觉效果。
703 0
|
Android开发
第二十三章:触发器和行为(八)
具有属性的行为Behavior 类派生自Behavior类,该类派生自BindableObject。这表明您的Behavior 派生可以定义自己的可绑定属性。之前你看过一些Action 衍生产品,比如ScaleAction和ShiverAction,它们定义了一些属性以赋予它们更大的灵活性。
622 0
|
JavaScript Android开发
第二十三章:触发器和行为(七)
行为 触发器和行为通常是串联讨论的,因为它们具有一些应用重叠。 有时候你会感到困惑是否使用触发器或行为,因为似乎要么这样做工作。你可以用触发器做任何事情,你也可以做一个行为。 但是,行为总是涉及一些代码,这是一个派生自Behavior 的类。
917 0
|
JavaScript Android开发
第二十三章:触发器和行为(六)
MultiTrigger中的组合条件Trigger和DataTrigger都有效地监视属性以确定它是否等于特定值。 这称为触发器的条件,如果条件为真,则调用Setter对象的集合。作为程序员,您可能会开始怀疑是否可以在触发器中具有多个条件。
623 0
|
JavaScript Android开发 iOS开发
第二十三章:触发器和行为(五)
数据触发器到目前为止,您只看到在特定对象的上下文中运行的触发器。 触发器通过更改同一对象的另一个属性或通过调用影响该对象的Action来响应对象属性的更改。 EventTrigger同样响应一个对象触发的事件,以在同一个对象上调用Action。
888 0
|
JavaScript Android开发 Windows
第二十三章:触发器和行为(四)
更多事件触发器前一章关于动画的章节展示了一个按钮,它在点击时旋转或缩放。 虽然大多数动画示例都是为了制作有趣的演示而采取极端措施,但是按钮用一点动画来响应点击并不是不合理的。 这是EventTrigger的完美工作。
732 0
|
JavaScript Android开发
第二十三章:触发器和行为(三)
触发动作和动画虽然某些触发器可以完全在XAML中实现,但其他触发器需要一些代码支持。 如您所知,Xamarin.Forms没有直接支持在XAML中实现动画,因此如果您想使用触发器为元素设置动画,则需要一些代码。
925 0