Xamarin.Forms Przycisk

Download Sample Pobieranie przykładu

Przycisk odpowiada na naciśnięcie lub kliknięcie, które kieruje aplikację do wykonania określonego zadania.

Jest Button to najbardziej podstawowa interaktywna kontrolka we wszystkich elementach Xamarin.Forms. Zazwyczaj Button wyświetla krótki ciąg tekstowy wskazujący polecenie, ale może również wyświetlać obraz mapy bitowej lub kombinację tekstu i obrazu. Użytkownik naciska Button palcem lub klika go myszą, aby zainicjować to polecenie.

Większość omówionych poniżej tematów odpowiada stronom w przykładzie ButtonDemos .

Obsługa kliknięć przycisków

ButtonClicked Definiuje zdarzenie, które jest wyzwalane, gdy użytkownik naciska Button palcem lub wskaźnikiem myszy. Zdarzenie jest wyzwalane, gdy palec lub przycisk myszy jest zwalniany z powierzchni Button. Właściwość musi być IsEnabled ustawiona Button na true , aby odpowiadała na naciśnięcia.

Na stronie Kliknięcie przycisku podstawowego w przykładzie ButtonDemos pokazano, jak utworzyć wystąpienie Button elementu w języku XAML i obsługiwać jego Clicked zdarzenie. Plik BasicButtonClickPage.xaml zawiera obiekt StackLayout z elementem i LabelButton:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.BasicButtonClickPage"
             Title="Basic Button Click">
    <StackLayout>

        <Label x:Name="label"
               Text="Click the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Click to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Clicked="OnButtonClicked" />

    </StackLayout>
</ContentPage>

Ma Button tendencję do zajmowania całej przestrzeni, która jest dla niego dozwolona. Jeśli na przykład nie ustawisz HorizontalOptions właściwości Button innej wartości niż Fill, Button właściwość będzie zajmować pełną szerokość jej elementu nadrzędnego.

Domyślnie Button obiekt jest prostokątny, ale można nadać jej zaokrąglone rogi za pomocą CornerRadius właściwości , jak opisano poniżej w sekcji Wygląd przycisku.

Właściwość Text określa tekst wyświetlany w obiekcie Button. Zdarzenie Clicked jest ustawione na program obsługi zdarzeń o nazwie OnButtonClicked. Ta procedura obsługi znajduje się w pliku za pomocą kodu, BasicButtonClickPage.xaml.cs:

public partial class BasicButtonClickPage : ContentPage
{
    public BasicButtonClickPage ()
    {
        InitializeComponent ();
    }

    async void OnButtonClicked(object sender, EventArgs args)
    {
        await label.RelRotateTo(360, 1000);
    }
}

W przypadku naciśnięcia obiektu Button jest wykonywana metoda OnButtonClicked. Argument sender jest obiektem odpowiedzialnym Button za to zdarzenie. Można go użyć, aby uzyskać dostęp do Button obiektu lub rozróżnić wiele Button obiektów współużytkowania tego samego Clicked zdarzenia.

Ten konkretny Clicked program obsługi wywołuje funkcję animacji, która obraca Label 360 stopni w 1000 milisekundach. Oto program działający na urządzeniach z systemami iOS i Android oraz jako aplikacja platforma uniwersalna systemu Windows (UWP) na pulpicie systemu Windows 10:

Basic Button Click

Zwróć uwagę, że OnButtonClicked metoda zawiera async modyfikator, ponieważ await jest używana w programie obsługi zdarzeń. Program Clicked obsługi zdarzeń wymaga async modyfikatora tylko wtedy, gdy treść programu obsługi używa elementu await.

Każda platforma renderuje Button element w określony sposób. W sekcji Wygląd przycisku zobaczysz, jak ustawić kolory i uwidocznić Button obramowanie w celu uzyskania bardziej dostosowanych wyglądów. Button implementuje IFontElement interfejs, więc zawiera FontFamilywłaściwości , FontSizei FontAttributes .

Tworzenie przycisku w kodzie

Tworzenie wystąpienia elementu Button w języku XAML jest powszechne, ale można również utworzyć element Button w kodzie. Może to być wygodne, gdy aplikacja musi utworzyć wiele przycisków na podstawie danych, które można wyliczać za pomocą foreach pętli.

Na stronie Kliknięcie przycisku kodu pokazano, jak utworzyć stronę, która jest funkcjonalnie równoważna stronie kliknięcia przycisku podstawowego, ale w całości w języku C#:

public class CodeButtonClickPage : ContentPage
{
    public CodeButtonClickPage ()
    {
        Title = "Code Button Click";

        Label label = new Label
        {
            Text = "Click the Button below",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };

        Button button = new Button
        {
            Text = "Click to Rotate Text!",
            VerticalOptions = LayoutOptions.CenterAndExpand,
            HorizontalOptions = LayoutOptions.Center
        };
        button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

        Content = new StackLayout
        {
            Children =
            {
                label,
                button
            }
        };
    }
}

Wszystko jest wykonywane w konstruktorze klasy. Clicked Ponieważ procedura obsługi jest długa tylko jedną instrukcją, można ją bardzo łatwo dołączyć do zdarzenia:

button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

Oczywiście można również zdefiniować procedurę obsługi zdarzeń jako oddzielną metodę (podobnie jak OnButtonClick metoda w kliknięciu przycisku podstawowego) i dołączyć tę metodę do zdarzenia:

button.Clicked += OnButtonClicked;

Wyłączanie przycisku

Czasami aplikacja jest w określonym stanie, w którym określone Button kliknięcie nie jest prawidłową operacją. W takich przypadkach właściwość powinna być wyłączona Button , ustawiając jej IsEnabled właściwość na false. Klasyczny przykład to kontrolka Entry dla nazwy pliku, której towarzyszy plik otwarty Button: Button element powinien być włączony tylko wtedy, gdy w pliku Entryzostał wpisany jakiś tekst . Możesz użyć elementu DataTrigger dla tego zadania, jak pokazano w artykule Wyzwalacze danych.

Korzystanie z interfejsu poleceń

Aplikacja może reagować na Button naciśnięcia bez obsługi Clicked zdarzenia. Funkcja Button implementuje alternatywny mechanizm powiadamiania nazywany interfejsem polecenia lub polecenia . Składa się z dwóch właściwości:

Takie podejście jest szczególnie odpowiednie w połączeniu z powiązaniem danych, a szczególnie podczas implementowania architektury Model-View-ViewModel (MVVM). Te tematy zostały omówione w artykułach Powiązanie danych, Od powiązań danych do MVVM i MVVM.

W aplikacji MVVM model widoku definiuje właściwości typu ICommand , które są następnie połączone z elementami XAML Button z powiązaniami danych. Xamarin.Forms definiuje Command również klasy, Command<T> które implementują ICommand interfejs i pomagają modelowi widoku w definiowaniu właściwości typu ICommand.

Polecenie zostało szczegółowo opisane w artykule Interfejs polecenia, ale strona Podstawowe polecenie w przykładzie ButtonDemos pokazuje podstawowe podejście.

Klasa CommandDemoViewModel jest bardzo prostym modelem widoków, który definiuje właściwość typu o nazwie Numberi dwie właściwości typu doubleICommand o nazwie MultiplyBy2Command i DivideBy2Command:

class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;

    public event PropertyChangedEventHandler PropertyChanged;

    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(() => Number *= 2);

        DivideBy2Command = new Command(() => Number /= 2);
    }

    public double Number
    {
        set
        {
            if (number != value)
            {
                number = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
            }
        }
        get
        {
            return number;
        }
    }

    public ICommand MultiplyBy2Command { private set; get; }

    public ICommand DivideBy2Command { private set; get; }
}

ICommand Dwie właściwości są inicjowane w konstruktorze klasy z dwoma obiektami typu Command. Konstruktory Command zawierają niewielką funkcję (nazywaną argumentem konstruktora execute ), która podwaja lub połówkę Number właściwości.

Plik BasicButtonCommand.xaml ustawia go BindingContext na wystąpienie klasy CommandDemoViewModel. Element Label i dwa Button elementy zawierają powiązania z trzema właściwościami w pliku CommandDemoViewModel:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.BasicButtonCommandPage"
             Title="Basic Button Command">

    <ContentPage.BindingContext>
        <local:CommandDemoViewModel />
    </ContentPage.BindingContext>

    <StackLayout>
        <Label Text="{Binding Number, StringFormat='Value is now {0}'}"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Multiply by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding MultiplyBy2Command}" />

        <Button Text="Divide by 2"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Command="{Binding DivideBy2Command}" />
    </StackLayout>
</ContentPage>

Gdy dwa Button elementy są mapowane, polecenia są wykonywane, a liczba zmienia wartość:

Basic Button Command

Zaletą tej metody Clicked obsługi jest to, że cała logika obejmująca funkcje tej strony znajduje się w modelu widoków, a nie w pliku z kodem, co zapewnia lepszą separację interfejsu użytkownika z logiki biznesowej.

Istnieje również możliwość Command kontrolowania i wyłączania Button elementów przez obiekty. Załóżmy na przykład, że chcesz ograniczyć zakres wartości liczbowych z zakresu od 210 do 2–10. Do konstruktora (nazywanego argumentem canExecute ) można dodać inną funkcję, która zwraca true wartość , jeśli Button ma zostać włączona. Oto modyfikacja konstruktora CommandDemoViewModel :

class CommandDemoViewModel : INotifyPropertyChanged
{
    ···
    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(
            execute: () =>
            {
                Number *= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number < Math.Pow(2, 10));

        DivideBy2Command = new Command(
            execute: () =>
            {
                Number /= 2;
                ((Command)MultiplyBy2Command).ChangeCanExecute();
                ((Command)DivideBy2Command).ChangeCanExecute();
            },
            canExecute: () => Number > Math.Pow(2, -10));
    }
    ···
}

Wywołania ChangeCanExecute metody Command są niezbędne, Command aby metoda mogła wywołać metodę canExecute i określić, czy powinna być wyłączona Button , czy nie. Po zmianie tego kodu w miarę osiągnięcia limitu liczba jest wyłączona Button :

Basic Button Command - Modified

Istnieje możliwość, że co najmniej dwa Button elementy mają być powiązane z tą samą ICommand właściwością. Button Elementy można odróżnić za pomocą CommandParameter właściwości Button. W takim przypadku należy użyć klasy ogólnej Command<T> . Obiekt CommandParameter jest następnie przekazywany jako argument do execute metod i canExecute . Ta technika jest szczegółowo pokazana w sekcji Podstawowe polecenia w artykule Interfejs wiersza polecenia.

Przykład ButtonDemos używa również tej techniki w swojej MainPage klasie. Plik MainPage.xaml zawiera Button element dla każdej strony przykładu:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.MainPage"
             Title="Button Demos">
    <ScrollView>
        <FlexLayout Direction="Column"
                    JustifyContent="SpaceEvenly"
                    AlignItems="Center">

            <Button Text="Basic Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonClickPage}" />

            <Button Text="Code Button Click"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:CodeButtonClickPage}" />

            <Button Text="Basic Button Command"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:BasicButtonCommandPage}" />

            <Button Text="Press and Release Button"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:PressAndReleaseButtonPage}" />

            <Button Text="Button Appearance"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ButtonAppearancePage}" />

            <Button Text="Toggle Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ToggleButtonDemoPage}" />

            <Button Text="Image Button Demo"
                    Command="{Binding NavigateCommand}"
                    CommandParameter="{x:Type local:ImageButtonDemoPage}" />

        </FlexLayout>
    </ScrollView>
</ContentPage>

Każda Button właściwość jest Command powiązana z właściwością o nazwie NavigateCommand, a CommandParameter właściwość jest ustawiona na Type obiekt odpowiadający jednej z klas stron w projekcie.

Ta NavigateCommand właściwość jest typu ICommand i jest zdefiniowana w pliku za kodem:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        NavigateCommand = new Command<Type>(async (Type pageType) =>
        {
            Page page = (Page)Activator.CreateInstance(pageType);
            await Navigation.PushAsync(page);
        });

        BindingContext = this;
    }

    public ICommand NavigateCommand { private set; get; }
}

Konstruktor inicjuje NavigateCommand właściwość do obiektu, ponieważ Type jest typem Command<Type>CommandParameter obiektu ustawionego w pliku XAML. Oznacza to, że execute metoda ma argument typu Type , który odpowiada temu CommandParameter obiektowi. Funkcja tworzy wystąpienie strony, a następnie przechodzi do niej.

Zwróć uwagę, że konstruktor kończy się ustawieniem samego siebie BindingContext . Jest to konieczne, aby właściwości w pliku XAML wiązały się z właściwością NavigateCommand .

Naciśnięcie i zwolnienie przycisku

Oprócz zdarzenia Clicked obiekt Button definiuje zdarzenia Pressed i Released. Zdarzenie Pressed występuje, gdy naciśnięcie palca na Buttonobiekcie lub naciśnięcie przycisku myszy jest naciśnięty z wskaźnikiem umieszczonym Buttonnad . Zdarzenie Released występuje po zwolnieniu palca lub przycisku myszy. Ogólnie rzecz biorąc, Clicked zdarzenie jest również wyzwalane w tym samym czasie co Released zdarzenie, ale jeśli palec lub wskaźnik myszy przesuwa się z dala od powierzchni Button przed zwolnieniem, Clicked zdarzenie może nie wystąpić.

Zdarzenia Pressed i Released nie są często używane, ale mogą być używane do celów specjalnych, jak pokazano na stronie Przycisk prasy i wydania. Plik XAML zawiera element Label i Button z procedurami obsługi dołączonymi do zdarzeń Pressed i Released :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.PressAndReleaseButtonPage"
             Title="Press and Release Button">
    <StackLayout>

        <Label x:Name="label"
               Text="Press and hold the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />

        <Button Text="Press to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Pressed="OnButtonPressed"
                Released="OnButtonReleased" />

    </StackLayout>
</ContentPage>

Plik związany z kodem animuje LabelPressed czas wystąpienia zdarzenia, ale zawiesza rotację w przypadku Released wystąpienia zdarzenia:

public partial class PressAndReleaseButtonPage : ContentPage
{
    bool animationInProgress = false;
    Stopwatch stopwatch = new Stopwatch();

    public PressAndReleaseButtonPage ()
    {
        InitializeComponent ();
    }

    void OnButtonPressed(object sender, EventArgs args)
    {
        stopwatch.Start();
        animationInProgress = true;

        Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
        {
            label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);

            return animationInProgress;
        });
    }

    void OnButtonReleased(object sender, EventArgs args)
    {
        animationInProgress = false;
        stopwatch.Stop();
    }
}

Rezultatem jest to, że Label tylko obraca się, gdy palec jest w kontakcie z Button, i zatrzymuje się po zwolnieniu palca:

Press and Release Button

Takie zachowanie ma zastosowania do gier: palec trzymany na ekranie Button może sprawić, że obiekt na ekranie porusza się w określonym kierunku.

Wygląd przycisku

Dziedziczy Button lub definiuje kilka właściwości, które wpływają na jej wygląd:

Uwaga

Klasa Button ma Margin również właściwości i Padding kontrolujące zachowanie układu obiektu Button. Aby uzyskać więcej informacji, zobacz Margines i wypełnienie.

Efekty sześciu z tych właściwości (z wyłączeniem FontFamily i FontAttributes) są pokazane na stronie Wygląd przycisku. W sekcji Używanie map bitowych z przyciskiem omówiono inną właściwość . Image

Wszystkie widoki i powiązania danych na stronie Wygląd przycisku są zdefiniowane w pliku XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ButtonAppearancePage"
             Title="Button Appearance">
    <StackLayout>
        <Button x:Name="button"
                Text="Button"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                TextColor="{Binding Source={x:Reference textColorPicker},
                                    Path=SelectedItem.Color}"
                BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
                                          Path=SelectedItem.Color}"
                BorderColor="{Binding Source={x:Reference borderColorPicker},
                                      Path=SelectedItem.Color}" />

        <StackLayout BindingContext="{x:Reference button}"
                     Padding="10">

            <Slider x:Name="fontSizeSlider"
                    Maximum="48"
                    Minimum="1"
                    Value="{Binding FontSize}" />

            <Label Text="{Binding Source={x:Reference fontSizeSlider},
                                  Path=Value,
                                  StringFormat='FontSize = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="borderWidthSlider"
                    Minimum="-1"
                    Maximum="12"
                    Value="{Binding BorderWidth}" />

            <Label Text="{Binding Source={x:Reference borderWidthSlider},
                                  Path=Value,
                                  StringFormat='BorderWidth = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="cornerRadiusSlider"
                    Minimum="-1"
                    Maximum="24"
                    Value="{Binding CornerRadius}" />

            <Label Text="{Binding Source={x:Reference cornerRadiusSlider},
                                  Path=Value,
                                  StringFormat='CornerRadius = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Grid.Resources>
                    <Style TargetType="Label">
                        <Setter Property="VerticalOptions" Value="Center" />
                    </Style>
                </Grid.Resources>

                <Label Text="Text Color:"
                       Grid.Row="0" Grid.Column="0" />

                <Picker x:Name="textColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="0" Grid.Column="1" />

                <Label Text="Background Color:"
                       Grid.Row="1" Grid.Column="0" />

                <Picker x:Name="backgroundColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="1" Grid.Column="1" />

                <Label Text="Border Color:"
                       Grid.Row="2" Grid.Column="0" />

                <Picker x:Name="borderColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="2" Grid.Column="1" />
            </Grid>
        </StackLayout>
    </StackLayout>
</ContentPage>

W Button górnej części strony znajdują się jej trzy Color właściwości powiązane z Picker elementami w dolnej części strony. Elementy w elementach Picker są kolorami z klasy uwzględnionej NamedColor w projekcie. Trzy Slider elementy zawierają powiązania dwukierunkowe z właściwościami FontSize, BorderWidthi CornerRadius .Button

Ten program umożliwia eksperymentowanie z kombinacjami wszystkich tych właściwości:

Button Appearance

Aby wyświetlić obramowanie Button , musisz ustawić wartość na inną BorderColor niż Default, i BorderWidth na wartość dodatnią.

W systemie iOS zauważysz, że duże szerokości obramowania wtargną do wnętrza Button obiektu i zakłócają wyświetlanie tekstu. Jeśli zdecydujesz się używać obramowania z systemem iOS Button, prawdopodobnie chcesz rozpocząć i zakończyć Text właściwość spacjami, aby zachować jej widoczność.

W przypadku platformy UWP wybranie elementu CornerRadius , które przekracza połowę wysokości wyjątku Button .

Stany wizualizacji przycisku

ButtonPressedVisualState element ma wartość , która może służyć do inicjowania zmiany wizualizacji Button po naciśnięciu przez użytkownika, pod warunkiem, że jest włączona.

W poniższym przykładzie XAML pokazano, jak zdefiniować stan wizualizacji Pressed dla stanu:

<Button Text="Click me!"
        ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="1" />
                </VisualState.Setters>
            </VisualState>

            <VisualState x:Name="Pressed">
                <VisualState.Setters>
                    <Setter Property="Scale"
                            Value="0.8" />
                </VisualState.Setters>
            </VisualState>

        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Button>

Określa PressedVisualState , że po naciśnięciu Button klawisza właściwość Scale zostanie zmieniona z domyślnej wartości 1 na 0,8. Określa NormalVisualState , że gdy Button właściwość jest w stanie normalnym, jej Scale właściwość zostanie ustawiona na 1. W związku z tym ogólny efekt polega na tym, że po naciśnięciu Button klawisza jest ona nieco mniejsza, a po jej wydaniu Button zostanie ponownie przeskalowana do rozmiaru domyślnego.

Aby uzyskać więcej informacji na temat stanów wizualizacji, zobacz Xamarin.Forms Visual State Manager.

Tworzenie przycisku przełącznika

Istnieje możliwość podklasy Button tak, aby działała jak przełącznik włączony: naciśnij przycisk raz, aby przełączyć przycisk i nacisnąć go ponownie, aby wyłączyć go.

Następująca ToggleButton klasa pochodzi z Button klasy i definiuje nowe zdarzenie o nazwie i właściwość logiczną o nazwie ToggledIsToggled. Są to te same dwie właściwości zdefiniowane przez element Xamarin.FormsSwitch:

class ToggleButton : Button
{
    public event EventHandler<ToggledEventArgs> Toggled;

    public static BindableProperty IsToggledProperty =
        BindableProperty.Create("IsToggled", typeof(bool), typeof(ToggleButton), false,
                                propertyChanged: OnIsToggledChanged);

    public ToggleButton()
    {
        Clicked += (sender, args) => IsToggled ^= true;
    }

    public bool IsToggled
    {
        set { SetValue(IsToggledProperty, value); }
        get { return (bool)GetValue(IsToggledProperty); }
    }

    protected override void OnParentSet()
    {
        base.OnParentSet();
        VisualStateManager.GoToState(this, "ToggledOff");
    }

    static void OnIsToggledChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ToggleButton toggleButton = (ToggleButton)bindable;
        bool isToggled = (bool)newValue;

        // Fire event
        toggleButton.Toggled?.Invoke(toggleButton, new ToggledEventArgs(isToggled));

        // Set the visual state
        VisualStateManager.GoToState(toggleButton, isToggled ? "ToggledOn" : "ToggledOff");
    }
}

Konstruktor ToggleButton dołącza program obsługi do Clicked zdarzenia, aby mógł zmienić wartość IsToggled właściwości. Metoda OnIsToggledChanged uruchamia Toggled zdarzenie.

Ostatni wiersz OnIsToggledChanged metody wywołuje metodę statyczną VisualStateManager.GoToState z dwoma ciągami tekstowymi "ToggledOn" i "ToggledOff". Możesz przeczytać o tej metodzie i sposobie reagowania aplikacji na stany wizualizacji w artykule Visual State Manager.Xamarin.Forms

Ponieważ ToggleButton wywołuje metodę VisualStateManager.GoToState, sama klasa nie musi zawierać żadnych dodatkowych obiektów, aby zmienić wygląd przycisku na podstawie jego IsToggled stanu. Jest to odpowiedzialność za kod XAML hostujący element ToggleButton.

Strona pokazu przycisku przełączania zawiera dwa wystąpienia ToggleButtonelementu , w tym znaczniki Visual State Manager, które ustawiają Textelement , BackgroundColori TextColor przycisku na podstawie stanu wizualizacji:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ToggleButtonDemoPage"
             Title="Toggle Button Demo">

    <ContentPage.Resources>
        <Style TargetType="local:ToggleButton">
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            <Setter Property="HorizontalOptions" Value="Center" />
        </Style>
    </ContentPage.Resources>

    <StackLayout Padding="10, 0">
        <local:ToggleButton Toggled="OnItalicButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Italic Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Italic On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <local:ToggleButton Toggled="OnBoldButtonToggled">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup Name="ToggleStates">
                    <VisualState Name="ToggledOff">
                        <VisualState.Setters>
                            <Setter Property="Text" Value="Bold Off" />
                            <Setter Property="BackgroundColor" Value="#C0C0C0" />
                            <Setter Property="TextColor" Value="Black" />
                        </VisualState.Setters>
                    </VisualState>

                    <VisualState Name="ToggledOn">
                        <VisualState.Setters>
                            <Setter Property="Text" Value=" Bold On " />
                            <Setter Property="BackgroundColor" Value="#404040" />
                            <Setter Property="TextColor" Value="White" />
                        </VisualState.Setters>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </local:ToggleButton>

        <Label x:Name="label"
               Text="Just a little passage of some sample text that can be formatted in italic or boldface by toggling the two buttons."
               FontSize="Large"
               HorizontalTextAlignment="Center"
               VerticalOptions="CenterAndExpand" />

    </StackLayout>
</ContentPage>

Programy Toggled obsługi zdarzeń znajdują się w pliku za pomocą kodu. Są one odpowiedzialne za ustawienie FontAttributes właściwości Label na podstawie stanu przycisków:

public partial class ToggleButtonDemoPage : ContentPage
{
    public ToggleButtonDemoPage ()
    {
        InitializeComponent ();
    }

    void OnItalicButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Italic;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Italic;
        }
    }

    void OnBoldButtonToggled(object sender, ToggledEventArgs args)
    {
        if (args.Value)
        {
            label.FontAttributes |= FontAttributes.Bold;
        }
        else
        {
            label.FontAttributes &= ~FontAttributes.Bold;
        }
    }
}

Oto program uruchomiony w systemach iOS, Android i UWP:

Toggle Button Demo

Używanie map bitowych z przyciskami

Klasa Button definiuje ImageSource właściwość, która umożliwia wyświetlanie obrazu mapy bitowej na obiekcie , samodzielnie lub w połączeniu Buttonz tekstem. Można również określić sposób rozmieszczania tekstu i obrazu.

Właściwość ImageSource ma typ ImageSource, co oznacza, że mapy bitowe mogą być ładowane z pliku, zasobu osadzonego, identyfikatora URI lub strumienia.

Uwaga

Button Chociaż obiekt może załadować animowany plik GIF, będzie wyświetlać tylko pierwszą ramkę gif.

Każda platforma obsługiwana przez Xamarin.Forms program umożliwia przechowywanie obrazów w wielu rozmiarach dla różnych rozdzielczości pikseli różnych urządzeń, na których może działać aplikacja. Te wiele map bitowych jest nazwanych lub przechowywanych w taki sposób, że system operacyjny może wybrać najlepsze dopasowanie do rozdzielczości ekranu wideo urządzenia.

W przypadku mapy bitowej na obiekcie najlepszym rozmiarem Buttonjest zwykle od 32 do 64 jednostek niezależnych od urządzenia, w zależności od tego, jak duży ma być. Obrazy używane w tym przykładzie są oparte na rozmiarze 48 jednostek niezależnych od urządzenia.

W projekcie systemu iOS folder Resources zawiera trzy rozmiary tego obrazu:

  • Mapa bitowa o powierzchni 48 pikseli przechowywana jako /Resources/MonkeyFace.png
  • Mapa bitowa o powierzchni 96 pikseli przechowywana jako /Resource/MonkeyFace@2x.png
  • Mapa bitowa o powierzchni 144 pikseli przechowywana jako /Resource/MonkeyFace@3x.png

Wszystkie trzy mapy bitowe otrzymały akcję kompilacji BundleResource.

W przypadku projektu systemu Android wszystkie mapy bitowe mają taką samą nazwę, ale są przechowywane w różnych podfolderach folderu Resources :

  • Mapa bitowa o powierzchni 72 pikseli przechowywana jako /Resources/drawable-hdpi/MonkeyFace.png
  • Mapa bitowa o powierzchni 96 pikseli przechowywana jako /Resources/drawable-xhdpi/MonkeyFace.png
  • Mapa bitowa kwadratowa o powierzchni 144 pikseli przechowywana jako /Resources/drawable-xxhdpi/MonkeyFace.png
  • Mapa bitowa kwadratowa z 192 pikselami przechowywana jako /Resources/drawable-xxxhdpi/MonkeyFace.png

Otrzymały one akcję kompilacji androidResource.

W projekcie platformy UWP mapy bitowe mogą być przechowywane w dowolnym miejscu w projekcie, ale są one zwykle przechowywane w folderze niestandardowym lub w istniejącym folderze Assets . Projekt platformy UWP zawiera następujące mapy bitowe:

  • Mapa bitowa o powierzchni 48 pikseli przechowywana jako /Assets/MonkeyFace.scale-100.png
  • Mapa bitowa o powierzchni 96 pikseli przechowywana jako /Assets/MonkeyFace.scale-200.png
  • Mapa bitowa kwadratowa z 192 pikselami przechowywana jako /Assets/MonkeyFace.scale-400.png

Wszystkie one otrzymały akcję kompilacji zawartości.

Możesz określić sposób Text rozmieszczania Button właściwości i ImageSource przy użyciu ContentLayout właściwości Button. Ta właściwość jest typu ButtonContentLayout, który jest klasą osadzoną w obiekcie Button. Konstruktor ma dwa argumenty:

  • Element członkowski ImagePosition wyliczenia: Left, , TopRightlub Bottom wskazujący sposób wyświetlania mapy bitowej względem tekstu.
  • double Wartość odstępu między mapą bitową a tekstem.

Wartości domyślne to Left i 10 jednostek. Dwie właściwości tylko do odczytu nazwane ButtonContentLayoutPosition i Spacing podają wartości tych właściwości.

W kodzie możesz utworzyć Button właściwość i ustawić następującą ContentLayout właściwość:

Button button = new Button
{
    Text = "button text",
    ImageSource = new FileImageSource
    {
        File = "image filename"
    },
    ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};

W języku XAML należy określić tylko składowy wyliczenia lub odstępy albo obie w dowolnej kolejności rozdzielone przecinkami:

<Button Text="button text"
        ImageSource="image filename"
        ContentLayout="Right, 20" />

Strona pokazowa przycisku obrazu służy OnPlatform do określania różnych nazw plików map bitowych systemów iOS, Android i UWP. Jeśli chcesz użyć tej samej nazwy pliku dla każdej platformy i uniknąć użycia OnPlatformprogramu , musisz przechowywać mapy bitowe platformy UWP w katalogu głównym projektu.

Pierwszy Button na stronie Pokaz przycisku obrazu ustawia Image właściwość, ale nie Textwłaściwość:

<Button>
    <Button.ImageSource>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="MonkeyFace.png" />
            <On Platform="UWP" Value="Assets/MonkeyFace.png" />
        </OnPlatform>
    </Button.ImageSource>
</Button>

Jeśli mapy bitowe platformy uwP są przechowywane w katalogu głównym projektu, ten znacznik można znacznie uprościć:

<Button ImageSource="MonkeyFace.png" />

Aby uniknąć wielu powtórzonych znaczników w pliku ImageButtonDemo.xaml , niejawny kod jest Style również definiowany w celu ustawienia ImageSource właściwości. Jest to Style automatycznie stosowane do pięciu innych Button elementów. Oto kompletny plik XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ButtonDemos.ImageButtonDemoPage">

    <FlexLayout Direction="Column"
                JustifyContent="SpaceEvenly"
                AlignItems="Center">

        <FlexLayout.Resources>
            <Style TargetType="Button">
                <Setter Property="ImageSource">
                    <OnPlatform x:TypeArguments="ImageSource">
                        <On Platform="iOS, Android" Value="MonkeyFace.png" />
                        <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                    </OnPlatform>
                </Setter>
            </Style>
        </FlexLayout.Resources>

        <Button>
            <Button.ImageSource>
                <OnPlatform x:TypeArguments="ImageSource">
                    <On Platform="iOS, Android" Value="MonkeyFace.png" />
                    <On Platform="UWP" Value="Assets/MonkeyFace.png" />
                </OnPlatform>
            </Button.ImageSource>
        </Button>

        <Button Text="Default" />

        <Button Text="Left - 10"
                ContentLayout="Left, 10" />

        <Button Text="Top - 10"
                ContentLayout="Top, 10" />

        <Button Text="Right - 20"
                ContentLayout="Right, 20" />

        <Button Text="Bottom - 20"
                ContentLayout="Bottom, 20" />
    </FlexLayout>
</ContentPage>

Ostatnie cztery Button elementy korzystają z ContentLayout właściwości w celu określenia położenia i odstępów między tekstem a mapą bitową:

Image Button Demo

Znasz już różne sposoby obsługi Button zdarzeń i zmieniania wyglądu Button .