次の方法で共有


Xamarin.Forms スライダー

スライダーを使用して、連続する値の範囲から値を選択します。

Xamarin.FormsSlider は、連続した範囲から double 値を選択するためにユーザーが操作できる水平バーです。

Slider では、double 型の 3 つのプロパティが定義されています。

  • Minimum は範囲の最小値で、既定値は 0 です。
  • Maximum は範囲の最大値で、既定値は 1 です。
  • Value はスライダーの値で、範囲は Minimum から Maximum で、既定値は 0 です。

3 つのプロパティはすべて BindableProperty オブジェクトでサポートされています。 Value プロパティの既定のバインド モードは BindingMode.TwoWay で、Model-View-ViewModel (MVVM) アーキテクチャを使用するアプリケーションのバインディング ソースとして適していることを意味します。

警告

内部的には、SliderMinimumMaximum より小さくなるようにします。 MinimumMaximum より小さくならないように MinimumMaximum が設定された場合、例外が発生します。 Minimum および Maximum プロパティの設定の詳細については、以下の「注意事項」セクションを参照してください。

Slider は、Value プロパティを MinimumMaximum の間になるように強制します(両端の値を含む)。 Minimum プロパティが Value プロパティより大きい値に設定されている場合、SliderValue プロパティを Minimum に設定します。 同様に、MaximumValue より小さい値に設定されている場合は、SliderValue プロパティを Maximum に設定します。

Slider は、Slider がユーザーによって操作されるか、プログラムで Value プロパティが直接設定されることで、Value が変化したときに発生する ValueChanged イベントを定義します。 前の段落で説明したように、Value プロパティが強制された場合にも ValueChanged イベントが発生します。

ValueChanged イベントに付随する ValueChangedEventArgs オブジェクトには、double 型の 2 つのプロパティ (OldValueNewValue) があります。 イベントが発生した時点では、NewValue の値は Slider オブジェクトの Value プロパティと同じです。

Slider では、ドラッグ操作の開始時と終了時に発生する DragStarted および DragCompleted イベントも定義されています。 ValueChanged イベントとは異なり、DragStarted および DragCompleted イベントは Slider に対するユーザー操作によってのみ発生します。 DragStarted イベントが発生すると、ICommand 型の DragStartedCommand を実行します。 同様に、DragCompleted イベントが発生すると、ICommand 型の DragCompletedCommand をが実行します。

警告

Slider で、CenterStartEnd の制約のない水平レイアウト オプションを使用しないでください。 Android と UWP の両方で、Slider は長さ が 0 のバーに折りたたまれ、iOS ではバーが非常に短くなります。 Fill の既定の HorizontalOptions 設定をそのまま使用し、Grid レイアウトに Slider を配置する場合は、Auto の幅を使用しないでください。

Slider では、その外観に影響を与えるいくつかのプロパティも定義されています。

Note

ThumbColorThumbImageSource のプロパティは相互に排他的です。 両方が設定されている場合、ThumbImageSource プロパティが優先されます。

基本的なスライダーのコードとマークアップ

サンプルは、機能的には同じですが、異なる方法で実装された 3 つのページから始まります。 最初のページでは C# コードのみを使用し、2 番目のページではコード内のイベント ハンドラーで XAML を使用し、3 番目のページでは XAML ファイル内のデータ バインディングを使用してイベント ハンドラーを回避できます。

コードでのスライダーの作成

[基本的なスライダー コード] ページには、コード内に Slider と 2 つの Label オブジェクトを作成する方法が示されています。

public class BasicSliderCodePage : ContentPage
{
    public BasicSliderCodePage()
    {
        Label rotationLabel = new Label
        {
            Text = "ROTATING TEXT",
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Label displayLabel = new Label
        {
            Text = "(uninitialized)",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        Slider slider = new Slider
        {
            Maximum = 360
        };
        slider.ValueChanged += (sender, args) =>
        {
            rotationLabel.Rotation = slider.Value;
            displayLabel.Text = String.Format("The Slider value is {0}", args.NewValue);
        };

        Title = "Basic Slider Code";
        Padding = new Thickness(10, 0);
        Content = new StackLayout
        {
            Children =
            {
                rotationLabel,
                slider,
                displayLabel
            }
        };
    }
}

Slider は初期化され、Maximum プロパティが 360 になります。 SliderValueChanged ハンドラーは、slider オブジェクトの Value プロパティを使用して最初の LabelRotation プロパティを設定し、String.Format メソッドをイベント引数の NewValue プロパティと共に使用して 2 番目の LabelText プロパティを設定します。 Slider の現在の値を取得するこれらの 2 つの方法は、相互に置き換え可能です。

iOS および Android デバイスで実行されているプログラムを次に示します。

基本的なスライダー コード

2 番目の Label には、Slider が操作されるまで "(初期化されていません)" というテキストが表示されます。これにより、最初の ValueChanged イベントが発生します。 表示される小数点以下の桁数は、プラットフォームごとに異なることに注意してください。 これらの違いは Slider のプラットフォーム実装に関連しており、この記事の後半の「プラットフォーム実装の違い」セクションで説明します。

XAML でのスライダーの作成

[基本的なスライダー XAML] ページは、基本的なスライダー コードと機能的には同じですが、主に XAML で実装されています。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.BasicSliderXamlPage"
             Title="Basic Slider XAML"
             Padding="10, 0">
    <StackLayout>
        <Label x:Name="rotatingLabel"
               Text="ROTATING TEXT"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider Maximum="360"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="displayLabel"
               Text="(uninitialized)"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

分離コード ファイルには、ValueChanged イベントのハンドラーが含まれます。

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

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        double value = args.NewValue;
        rotatingLabel.Rotation = value;
        displayLabel.Text = String.Format("The Slider value is {0}", value);
    }
}

イベント ハンドラーは、sender 引数でイベントを発生させる Slider を取得することもできます。 Value プロパティは現在値を含みます。

double value = ((Slider)sender).Value;

XAML ファイルで x:Name 属性 ("slider" など) を持つ名前が Slider オブジェクトに指定されている場合、イベント ハンドラーはそのオブジェクトを直接参照できます。

double value = slider.Value;

スライダーのデータ バインディング

[基本的なスライダー バインディング] ページでは、データ バインディングを使用して Value イベント ハンドラーを除去する、ほぼ同等のプログラムを作成する方法を示します。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.BasicSliderBindingsPage"
             Title="Basic Slider Bindings"
             Padding="10, 0">
    <StackLayout>
        <Label Text="ROTATING TEXT"
               Rotation="{Binding Source={x:Reference slider},
                                  Path=Value}"
               FontSize="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Slider x:Name="slider"
                Maximum="360" />

        <Label x:Name="displayLabel"
               Text="{Binding Source={x:Reference slider},
                              Path=Value,
                              StringFormat='The Slider value is {0:F0}'}"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

最初の LabelRotation プロパティは SliderValue プロパティにバインドされ、2 番目の LabelText プロパティは StringFormat の仕様でバインドされています。 [基本的なスライダー バインディング] ページは、前の 2 つのページとは少し異なる形で機能します。ページが最初に表示されると、2 番目の Label に値を含むテキスト文字列が表示されます。 これは、データ バインディングを使用する利点です。 データ バインディングなしでテキストを表示するには、LabelText プロパティを具体的に初期化するか、クラス コンストラクターからイベント ハンドラーを呼び出して ValueChanged イベントの発生をシミュレートする必要があります。

注意事項

Minimum プロパティの値は常に、Maximum プロパティの値より小さくする必要があります。 次のコード スニペットを使用すると、Slider で例外が発生します。

// Throws an exception!
Slider slider = new Slider
{
    Minimum = 10,
    Maximum = 20
};

C# コンパイラは、これら 2 つのプロパティを順番に設定するコードを生成します。Minimum プロパティを 10 に設定すると、Maximum の既定値 1 より大きくなります。 この場合、最初に Maximum プロパティを設定することで例外を回避できます。

Slider slider = new Slider
{
    Maximum = 20,
    Minimum = 10
};

Maximum を 20 に設定しても、既定の Minimum 値の 0 より大きいため、問題ありません。 Minimum を設定すると、この値は Maximum の値 20 より小さくなります。

XAML でも同じ問題が存在します。 Maximum が常に Minimum より大きくなる順序でプロパティを設定します。

<Slider Maximum="20"
        Minimum="10" ... />

MinimumMaximum の値を負の数に設定できますが、Minimum が常に Maximum より小さくなるような順序でのみ設定できます。

<Slider Minimum="-20"
        Maximum="-10" ... />

Value プロパティは常に Minimum 値以上、Maximum 値以下です。 Value がその範囲外の値に設定された場合、値は強制的に範囲内に設定されますが、例外は発生しません。 たとえば、次のコードを使用しても、例外は発生しません

Slider slider = new Slider
{
    Value = 10
};

代わりに、Value プロパティは、Maximum 値の 1 に強制的に設定されます。

上記のコード スニペットを次に示します。

Slider slider = new Slider
{
    Maximum = 20,
    Minimum = 10
};

Minimum を 10 に設定した場合、Value も 10 に設定されます。

ValueChanged イベント ハンドラーが、Value プロパティが既定値 0 以外の値に強制された時点ですでにアタッチされていた場合、ValueChanged イベントが発生します。 XAML のスニペットを次に示します。

<Slider ValueChanged="OnSliderValueChanged"
        Maximum="20"
        Minimum="10" />

Minimum を 10 に設定すると、Value も 10 に設定され、ValueChanged イベントが発生します。 これは、ページの残りの部分が作成される前に発生する可能性があり、ハンドラーは、まだ作成されていないページ上の他の要素を参照しようとする可能性があります。 ページ上の他の要素の null 値をチェックするコードを、ValueChanged ハンドラーに追加できます。 または、Slider の値が初期化された後に ValueChanged イベント ハンドラーを設定することもできます。

プラットフォーム実装の違い

前に示したスクリーンショットでは、Slider の値が異なる小数点以下の桁数で表示されています。 これは、Android および UWP プラットフォームで Slider を実装する方法に関連しています。

Android 実装

Slider の Android 実装は Android SeekBar に基づいており、Max プロパティが常に 1000 に設定されます。 これは、Android の Slider の離散値は 1,001 個のみであることを意味します。 SliderMinimum を 0、Maximum を 5000 に設定した場合、Slider を操作すると、Value プロパティには 0、5、10、15 などの値が含まれるようになります。

UWP 実装

Slider の UWP 実装は UWP Slider コントロールに基づいています。 UWP SliderStepFrequency プロパティは、MaximumMinimum のプロパティの差を 10 で割った値に設定されますが、1 を超えることはありません。

たとえば、既定の範囲である 0 から 1 の場合、StepFrequency プロパティは 0.1 に設定されます。 Slider を操作すると、Value プロパティは 0、0.1、0.2、0.3、0.4、0.5、0.6、0.7、0.8、0.9、1.0 に制限されます MaximumMinimum のプロパティの差が 10 以上の場合、StepFrequency は 1 に設定され、Value プロパティには整数値が含まれます。

StepSlider ソリューション

より汎用的な StepSlider については、書籍『Xamarin.Forms を使用したモバイル アプリの作成』の「第 27 章 カスタム レンダラー」を参照してください。 StepSliderSlider と似ていますが、MinimumMaximum の間の値の数を指定するための Steps プロパティを追加します。

色を選択するためのスライダー

サンプルの最後の 2 ページでは、両方とも 3 つの Slider インスタンスを使用して色を選択します。 最初のページでは、分離コード ファイル内のすべての操作が処理され、2 番目のページでは、ViewModel を使用してデータ バインディングを使用する方法を示します。

分離コード ファイルでのスライダーの処理

[RGB カラー スライダー] ページでは、色を表示するための BoxView、色の赤、緑、青コンポーネントを選択するための 3 つの Slider インスタンス、それらの色の値を表示するための 3 つの Label 要素のインスタンスが作成されます。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="SliderDemos.RgbColorSlidersPage"
             Title="RGB Color Sliders">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Slider">
                <Setter Property="Maximum" Value="255" />
            </Style>

            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Margin="10">
        <BoxView x:Name="boxView"
                 Color="Black"
                 VerticalOptions="FillAndExpand" />

        <Slider x:Name="redSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="redLabel" />

        <Slider x:Name="greenSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="greenLabel" />

        <Slider x:Name="blueSlider"
                ValueChanged="OnSliderValueChanged" />

        <Label x:Name="blueLabel" />
    </StackLayout>
</ContentPage>

Style によって、3つの Slider 要素すべての範囲が 0 から 255 になります。 Slider 要素は、分離コード ファイルで実装される同じ ValueChanged ハンドラーを共有します。

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

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        if (sender == redSlider)
        {
            redLabel.Text = String.Format("Red = {0:X2}", (int)args.NewValue);
        }
        else if (sender == greenSlider)
        {
            greenLabel.Text = String.Format("Green = {0:X2}", (int)args.NewValue);
        }
        else if (sender == blueSlider)
        {
            blueLabel.Text = String.Format("Blue = {0:X2}", (int)args.NewValue);
        }

        boxView.Color = Color.FromRgb((int)redSlider.Value,
                                      (int)greenSlider.Value,
                                      (int)blueSlider.Value);
    }
}

最初のセクションでは、Label インスタンスの 1 つの Text プロパティが、Slider の値を 16 進数で示す短いテキスト文字列に設定されます。 次に、3 つの Slider インスタンスすべてにアクセスして、RGB コンポーネントから Color 値を作成します。

RGB カラー スライダー

スライダーの ViewModel へのバインド

[HSL カラー スライダー] ページでは、ViewModel を使用して、色相、彩度、明度の値から Color 値を作成するために使用される計算を実行する方法を示します。 すべての ViewModel と同様に、HSLColorViewModel クラスは INotifyPropertyChanged インターフェイスを実装し、プロパティのいずれかが変更されるたびに PropertyChanged イベントが発生します。

public class HslColorViewModel : INotifyPropertyChanged
{
    Color color;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Hue
    {
        set
        {
            if (color.Hue != value)
            {
                Color = Color.FromHsla(value, color.Saturation, color.Luminosity);
            }
        }
        get
        {
            return color.Hue;
        }
    }

    public double Saturation
    {
        set
        {
            if (color.Saturation != value)
            {
                Color = Color.FromHsla(color.Hue, value, color.Luminosity);
            }
        }
        get
        {
            return color.Saturation;
        }
    }

    public double Luminosity
    {
        set
        {
            if (color.Luminosity != value)
            {
                Color = Color.FromHsla(color.Hue, color.Saturation, value);
            }
        }
        get
        {
            return color.Luminosity;
        }
    }

    public Color Color
    {
        set
        {
            if (color != value)
            {
                color = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
            }
        }
        get
        {
            return color;
        }
    }
}

ViewModel と INotifyPropertyChanged インターフェイスについては、データ バインディングに関する記事で説明します。

HslColorSlidersPage.xaml ファイルは HslColorViewModel のインスタンスを作成し、ページの BindingContext プロパティに設定します。 これにより、XAML ファイル内のすべての要素を ViewModel のプロパティにバインドできます。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SliderDemos"
             x:Class="SliderDemos.HslColorSlidersPage"
             Title="HSL Color Sliders">

    <ContentPage.BindingContext>
        <local:HslColorViewModel Color="Chocolate" />
    </ContentPage.BindingContext>

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Margin="10">
        <BoxView Color="{Binding Color}"
                 VerticalOptions="FillAndExpand" />

        <Slider Value="{Binding Hue}" />
        <Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />

        <Slider Value="{Binding Saturation}" />
        <Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />

        <Slider Value="{Binding Luminosity}" />
        <Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
    </StackLayout>
</ContentPage>

Slider 要素を操作すると、ViewModel から BoxView および Label 要素が更新されます。

HSL カラー スライダー

Binding マークアップ拡張の StringFormat コンポーネントは、小数点以下 2 桁を表示する "F2" 形式に設定されています (データ バインディングでの文字列の書式設定については、文字列の書式設定に関する記事で説明します)。ただし、プログラムの UWP バージョンの値は、0、0.1、0.2、...0.9、1.0 に制限されます。 これは、上記の「プラットフォーム実装の違い」セクションで説明したように、UWP Slider の実装による直接的な結果です。