Xamarin.Forms RadioButton

Xamarin.FormsRadioButton 是一种按钮,允许用户从集中选择一个选项。 每个选项都表示为一个单选按钮,只能在一组中选择一个单选按钮。 默认情况下,每个 RadioButton 都显示文本:

默认 RadioButton 的屏幕截图

但是,在某些平台上,RadioButton 可以显示 View,而在所有平台上,可以使用 ControlTemplate 重新定义每个 RadioButton 的外观:

重新定义的 RadioButton 的屏幕截图

RadioButton 控件定义以下属性:

  • Content,类型为 object,用于定义要由 RadioButton 显示的 stringView
  • IsChecked,类型为 bool,用于定义是否选中 RadioButton。 此属性使用 TwoWay 绑定,默认值为 false
  • GroupName,类型为 string,用于定义指明哪些 RadioButton 控件互斥的名称。 此属性的默认值为 null
  • Value,类型为 object,用于定义与 RadioButton 关联的可选的唯一值。
  • BorderColor,类型为 Color,用于定义边框笔触颜色。
  • BorderWidth,类型为 double,用于定义 RadioButton 边框的宽度。
  • CharacterSpacing,类型为 double,用于定义任何所显示的文本的字符之间的间距。
  • CornerRadius,类型为 int,用于定义 RadioButton 的圆角半径。
  • FontAttributes,类型为 FontAttributes,用于确定文本样式。
  • FontFamily,类型为 string,用于定义字体系列。
  • FontSize,类型为 double,用于定义字体大小。
  • TextColor,类型为 Color,用于定义任何所显示的文本的颜色。
  • TextTransform,类型为 TextTransform,用于定义任何所显示的文本的大小写。

这些属性由 BindableProperty 对象提供支持,表示它们可以是数据绑定的目标,并可以设置样式。

RadioButton 控件还定义了一个 CheckedChanged 事件,该事件在 IsChecked 属性由于用户或者程序操作而更改时触发。 CheckedChanged 事件附带的 CheckedChangedEventArgs 对象包含名为 Value、类型为 bool 的属性。 当该事件触发时,CheckedChangedEventArgs.Value 属性的值将设置为 IsChecked 属性的新值。

RadioButton 分组可以由 RadioButtonGroup 类管理,该类定义下列附加属性:

  • GroupName(类型为 string),定义 Layout<View> 中的 RadioButton 对象的组名称。
  • SelectedValue(类型为 object),表示 Layout<View> 组中选中的 RadioButton 对象的值。 默认情况下,此附加属性使用 TwoWay 绑定。

有关 GroupName 附加属性的详细信息,请参阅对 RadioButtons 进行分组。 有关 SelectedValue 附加属性的详细信息,请参阅响应 RadioButton 状态更改

创建 RadioButton

RadioButton 的外观由分配给 RadioButton.Content 属性的数据类型定义:

  • RadioButton.Content 属性分配 string 后,该属性将显示在每个平台上,与单选按钮圆圈水平对齐。
  • RadioButton.Content 分配了 View 时,它将显示在受支持的平台上(iOS、UWP),而不受支持的平台将回退到 View 对象的字符串表示形式 (Android)。 在这两种情况下,内容在单选按钮圆圈旁边水平对齐显示。
  • ControlTemplate 应用于 RadioButton 时,可以在所有平台上将 View 分配给 RadioButton.Content 属性。 有关详细信息,请参阅重新定义 RadioButton 外观

显示基于字符串的内容

当为 Content 属性分配 string 时,RadioButton 显示文本:

<StackLayout>
    <Label Text="What's your favorite animal?" />
    <RadioButton Content="Cat" />
    <RadioButton Content="Dog" />
    <RadioButton Content="Elephant" />
    <RadioButton Content="Monkey"
                 IsChecked="true" />
</StackLayout>

在此示例中,RadioButton 对象被隐式分组到同一个父容器内。 此 XAML 会生成以下屏幕截图中所示的外观:

文本型 RadioButton 的屏幕截图

显示任意内容

在 iOS 和 UWP 上,当 Content 属性被分配了 View 时,RadioButton 可以显示任意内容:

<StackLayout>
    <Label Text="What's your favorite animal?" />
    <RadioButton>
        <RadioButton.Content>
            <Image Source="cat.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton>
        <RadioButton.Content>
            <Image Source="dog.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton>
        <RadioButton.Content>
            <Image Source="elephant.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton>
        <RadioButton.Content>
            <Image Source="monkey.png" />
        </RadioButton.Content>
    </RadioButton>
</StackLayout>

在此示例中,RadioButton 对象被隐式分组到同一个父容器内。 此 XAML 会生成以下屏幕截图中所示的外观:

基于视图的 RadioButton 的屏幕截图

在 Android 上,RadioButton 对象将显示设置为内容的 View 对象的基于字符串的表示形式:

Android 上基于视图的 RadioButton 的屏幕截图

注意

ControlTemplate 应用于 RadioButton 时,可以在所有平台上将 View 分配给 RadioButton.Content 属性。 有关详细信息,请参阅重新定义 RadioButton 外观

将值与 RadioButton 关联

每个 RadioButton 对象都有一个类型为 objectValue 属性,用于定义要与单选按钮关联的可选唯一值。 这样,RadioButton 的值就可以不同于其内容,这在 RadioButton 对象显示 View 对象时特别有用。

以下 XAML 展示了如何在每个 RadioButton 对象上设置 ContentValue 属性:

<StackLayout>
    <Label Text="What's your favorite animal?" />
    <RadioButton Value="Cat">
        <RadioButton.Content>
            <Image Source="cat.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Dog">
        <RadioButton.Content>
            <Image Source="dog.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Elephant">
        <RadioButton.Content>
            <Image Source="elephant.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Monkey">
        <RadioButton.Content>
            <Image Source="monkey.png" />
        </RadioButton.Content>
    </RadioButton>
</StackLayout>

在此示例中,每个 RadioButton 都有一个作为其内容的 Image,同时还定义了基于字符串的值。 这样可以很容易地识别选中的单选按钮的值。

对 RadioButtons 进行分组

单选按钮以组方式工作,可通过三种方法对单选按钮进行分组:

  • 将它们放在同一个父容器内。 这称为隐式分组。
  • 将组中每个单选按钮的 GroupName 属性设置为相同的值。 这称为显式分组。
  • 在父容器上设置 RadioButtonGroup.GroupName 附加属性,后者又在容器中设置任何 RadioButton 对象的 GroupName 属性。 这也称为显式分组。

重要

RadioButton 对象不必属于同一父对象即可分组。 如果它们共享组名称,则会相互排斥。

使用 GroupName 属性进行显式分组

以下 XAML 示例演示如何通过设置 GroupName 属性对 RadioButton 对象进行显式分组:

<Label Text="What's your favorite color?" />
<RadioButton Content="Red"
             GroupName="colors" />
<RadioButton Content="Green"
             GroupName="colors" />
<RadioButton Content="Blue"
             GroupName="colors" />
<RadioButton Content="Other"
             GroupName="colors" />

在此示例中,每个 RadioButton 由于共享同一 GroupName 值而互斥。

使用 RadioButtonGroup.GroupName 附加属性进行显式分组

RadioButtonGroup 类定义类型为 stringGroupName 附加属性,该属性可以在 Layout<View> 对象上设置。 这样,任何布局都可以转换为单选按钮组:

<StackLayout RadioButtonGroup.GroupName="colors">
    <Label Text="What's your favorite color?" />
    <RadioButton Content="Red" />
    <RadioButton Content="Green" />
    <RadioButton Content="Blue" />
    <RadioButton Content="Other" />
</StackLayout>

在此示例中,StackLayout 中的每个 RadioButton 都将其 GroupName 属性设置为 colors,并且互斥。

注意

当设置了 RadioButtonGroup.GroupName 附加属性的 Layout<View> 对象包含设置了其 GroupName 属性的 RadioButton 时,RadioButton.GroupName 属性的值优先级更高。

响应 RadioButton 状态更改

单选按钮有两个状态:“已选中”或“取消选中”。 选中单选按钮时,其 IsChecked 属性为 true。 取消选中单选按钮时,其 IsChecked 属性为 false。 可以通过点击同一组中的另一个单选按钮来清除单选按钮,但不能通过再次点击来清除它。 但是,你可以通过将单选按钮的 IsChecked 属性设置为 false,以编程方式清除它。

响应事件触发

IsChecked 属性因为用户或编程操作而发生更改时,将触发 CheckedChanged 事件。 可以注册此事件的事件处理程序以响应更改:

<RadioButton Content="Red"
             GroupName="colors"
             CheckedChanged="OnColorsRadioButtonCheckedChanged" />

代码隐藏包含 CheckedChanged 事件的处理程序:

void OnColorsRadioButtonCheckedChanged(object sender, CheckedChangedEventArgs e)
{
    // Perform required operation
}

sender 参数是负责此事件的 RadioButton。 可以使用它访问 RadioButton 对象,或区分共享同一 CheckedChanged 事件处理程序的多个 RadioButton 对象。

响应属性更改

RadioButtonGroup 类定义类型为 objectSelectedValue 附加属性,该属性可以在 Layout<View> 对象上设置。 此附加属性表示在布局上定义的组中选中的 RadioButton 的值。

IsChecked 属性因为用户或编程操作而发生更改时,RadioButtonGroup.SelectedValue 附加属性也会更改。 因此,RadioButtonGroup.SelectedValue 附加属性可以是绑定到存储用户选择的属性的数据:

<StackLayout RadioButtonGroup.GroupName="{Binding GroupName}"
             RadioButtonGroup.SelectedValue="{Binding Selection}">
    <Label Text="What's your favorite animal?" />
    <RadioButton Content="Cat"
                 Value="Cat" />
    <RadioButton Content="Dog"
                 Value="Dog" />
    <RadioButton Content="Elephant"
                 Value="Elephant" />
    <RadioButton Content="Monkey"
                 Value="Monkey"/>
    <Label x:Name="animalLabel">
        <Label.FormattedText>
            <FormattedString>
                <Span Text="You have chosen:" />
                <Span Text="{Binding Selection}" />
            </FormattedString>
        </Label.FormattedText>
    </Label>
</StackLayout>

在此示例中,RadioButtonGroup.GroupName 附加属性的值由绑定上下文上的 GroupName 属性设置。 同样,RadioButtonGroup.SelectedValue 附加属性的值由绑定上下文上的 Selection 属性设置。 此外,Selection 属性更新为选中的 RadioButtonValue 属性。

RadioButton 视觉状态

RadioButton 对象具有 CheckedUnchecked 视觉状态,可用于在选中或不选中 RadioButton 时启动视觉更改。

以下 XAML 示例展示了如何为 CheckedUnchecked 状态定义视觉状态:

<ContentPage ...>
    <ContentPage.Resources>
        <Style TargetType="RadioButton">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CheckedStates">
                        <VisualState x:Name="Checked">
                            <VisualState.Setters>
                                <Setter Property="TextColor"
                                        Value="Green" />
                                <Setter Property="Opacity"
                                        Value="1" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Unchecked">
                            <VisualState.Setters>
                                <Setter Property="TextColor"
                                        Value="Red" />
                                <Setter Property="Opacity"
                                        Value="0.5" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>
    </ContentPage.Resources>
    <StackLayout>
        <Label Text="What's your favorite mode of transport?" />
        <RadioButton Content="Car" />
        <RadioButton Content="Bike" />
        <RadioButton Content="Train" />
        <RadioButton Content="Walking" />
    </StackLayout>
</ContentPage>

在此示例中,隐式 StyleRadioButton 对象为目标。 CheckedVisualState 指定当选中 RadioButton 时,其 TextColor 属性将设置为绿色,Opacity 值为 1。 UncheckedVisualState 指定当 RadioButton 处于未选中状态时,其 TextColor 属性将设置为红色,Opacity 值为 0.5。 因此,总体效果是,当未选中 RadioButton 时,它是红色且部分透明的,而当选中时,它是绿色且不透明的:

RadioButton 视觉状态的屏幕截图

若要详细了解可视状态,请参阅 Xamarin.Forms 可视状态管理器

重新定义单选按钮外观

默认情况下,RadioButton 对象使用平台呈现器利用受支持的平台上的原生控件。 但是,可以使用 ControlTemplate 重新定义 RadioButton 视觉结构,这样 RadioButton 对象在所有平台上都具有相同的外观。 这是可能的,因为 RadioButton 类继承自 TemplatedView 类。

以下 XAML 显示了一个 ControlTemplate,其可用于重新定义 RadioButton 对象的视觉结构:

<ContentPage ...>
    <ContentPage.Resources>
        <ControlTemplate x:Key="RadioButtonTemplate">
            <Frame BorderColor="#F3F2F1"
                   BackgroundColor="#F3F2F1"
                   HasShadow="False"
                   HeightRequest="100"
                   WidthRequest="100"
                   HorizontalOptions="Start"
                   VerticalOptions="Start"
                   Padding="0">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CheckedStates">
                            <VisualState x:Name="Checked">
                                <VisualState.Setters>
                                    <Setter Property="BorderColor"
                                            Value="#FF3300" />
                                    <Setter TargetName="check"
                                            Property="Opacity"
                                            Value="1" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Unchecked">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor"
                                            Value="#F3F2F1" />
                                    <Setter Property="BorderColor"
                                            Value="#F3F2F1" />
                                    <Setter TargetName="check"
                                            Property="Opacity"
                                            Value="0" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </VisualStateManager.VisualStateGroups>
                <Grid Margin="4"
                      WidthRequest="100">
                    <Grid WidthRequest="18"
                          HeightRequest="18"
                          HorizontalOptions="End"
                          VerticalOptions="Start">
                        <Ellipse Stroke="Blue"
                                 Fill="White"
                                 WidthRequest="16"
                                 HeightRequest="16"
                                 HorizontalOptions="Center"
                                 VerticalOptions="Center" />
                        <Ellipse x:Name="check"
                                 Fill="Blue"
                                 WidthRequest="8"
                                 HeightRequest="8"
                                 HorizontalOptions="Center"
                                 VerticalOptions="Center" />
                    </Grid>
                    <ContentPresenter />
                </Grid>
            </Frame>
        </ControlTemplate>

        <Style TargetType="RadioButton">
            <Setter Property="ControlTemplate"
                    Value="{StaticResource RadioButtonTemplate}" />
        </Style>
    </ContentPage.Resources>
    <!-- Page content -->
</ContentPage>

在此示例中,ControlTemplate 的根元素是一个 Frame 对象,用于定义 CheckedUnchecked 视觉状态。 Frame 对象使用 GridEllipseContentPresenter 对象的组合来定义 RadioButton 的视觉结构。 该示例还包括一个隐式样式,该样式将 RadioButtonTemplate 分配给页面上任何 RadioButton 对象的 ControlTemplate 属性。

注意

ContentPresenter 对象将标记视觉结构中将显示 RadioButton 内容的位置。

以下 XAML 展示了通过隐式样式使用 ControlTemplateRadioButton 对象:

<StackLayout>
    <Label Text="What's your favorite animal?" />
    <StackLayout RadioButtonGroup.GroupName="animals"
                 Orientation="Horizontal">
        <RadioButton Value="Cat">
            <RadioButton.Content>
                <StackLayout>
                    <Image Source="cat.png"
                           HorizontalOptions="Center"
                           VerticalOptions="CenterAndExpand" />
                    <Label Text="Cat"
                           HorizontalOptions="Center"
                           VerticalOptions="End" />
                </StackLayout>
            </RadioButton.Content>
        </RadioButton>
        <RadioButton Value="Dog">
            <RadioButton.Content>
                <StackLayout>
                    <Image Source="dog.png"
                           HorizontalOptions="Center"
                           VerticalOptions="CenterAndExpand" />
                    <Label Text="Dog"
                           HorizontalOptions="Center"
                           VerticalOptions="End" />
                </StackLayout>
            </RadioButton.Content>
        </RadioButton>
        <RadioButton Value="Elephant">
            <RadioButton.Content>
                <StackLayout>
                    <Image Source="elephant.png"
                           HorizontalOptions="Center"
                           VerticalOptions="CenterAndExpand" />
                    <Label Text="Elephant"
                           HorizontalOptions="Center"
                           VerticalOptions="End" />
                </StackLayout>
            </RadioButton.Content>
        </RadioButton>
        <RadioButton Value="Monkey">
            <RadioButton.Content>
                <StackLayout>
                    <Image Source="monkey.png"
                           HorizontalOptions="Center"
                           VerticalOptions="CenterAndExpand" />
                    <Label Text="Monkey"
                           HorizontalOptions="Center"
                           VerticalOptions="End" />
                </StackLayout>
            </RadioButton.Content>
        </RadioButton>
    </StackLayout>
</StackLayout>

在此示例中,为每个 RadioButton 定义的视觉结构被替换为 ControlTemplate 中定义的视觉结构,因此在运行时,ControlTemplate 中的对象成为每个 RadioButton 的可视化树的一部分。 此外,每个 RadioButton 的内容都被替换到控件模板中定义的 ContentPresenter 中。 这将导致以下 RadioButton 外观:

模板化 RadioButton 的屏幕截图

有关控件模板的详细信息,请参阅 Xamarin.Forms 控件模板

禁用 RadioButton

有时,应用进入选中 RadioButton 不是有效操作的状态。 在这种情况下,可以通过将 RadioButtonIsEnabled 属性设置为 false 来对其进行禁用。