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) アーキテクチャを使用するアプリケーションのバインディング ソースとして適していることを意味します。
警告
内部的には、Slider
は Minimum
が Maximum
より小さくなるようにします。 Minimum
が Maximum
より小さくならないように Minimum
や Maximum
が設定された場合、例外が発生します。 Minimum
および Maximum
プロパティの設定の詳細については、以下の「注意事項」セクションを参照してください。
Slider
は、Value
プロパティを Minimum
と Maximum
の間になるように強制します(両端の値を含む)。 Minimum
プロパティが Value
プロパティより大きい値に設定されている場合、Slider
は Value
プロパティを Minimum
に設定します。 同様に、Maximum
が Value
より小さい値に設定されている場合は、Slider
は Value
プロパティを Maximum
に設定します。
Slider
は、Slider
がユーザーによって操作されるか、プログラムで Value
プロパティが直接設定されることで、Value
が変化したときに発生する ValueChanged
イベントを定義します。 前の段落で説明したように、Value
プロパティが強制された場合にも ValueChanged
イベントが発生します。
ValueChanged
イベントに付随する ValueChangedEventArgs
オブジェクトには、double
型の 2 つのプロパティ (OldValue
と NewValue
) があります。 イベントが発生した時点では、NewValue
の値は Slider
オブジェクトの Value
プロパティと同じです。
Slider
では、ドラッグ操作の開始時と終了時に発生する DragStarted
および DragCompleted
イベントも定義されています。 ValueChanged
イベントとは異なり、DragStarted
および DragCompleted
イベントは Slider
に対するユーザー操作によってのみ発生します。 DragStarted
イベントが発生すると、ICommand
型の DragStartedCommand
を実行します。 同様に、DragCompleted
イベントが発生すると、ICommand
型の DragCompletedCommand
をが実行します。
警告
Slider
で、Center
、Start
、End
の制約のない水平レイアウト オプションを使用しないでください。 Android と UWP の両方で、Slider
は長さ が 0 のバーに折りたたまれ、iOS ではバーが非常に短くなります。 Fill
の既定の HorizontalOptions
設定をそのまま使用し、Grid
レイアウトに Slider
を配置する場合は、Auto
の幅を使用しないでください。
Slider
では、その外観に影響を与えるいくつかのプロパティも定義されています。
MinimumTrackColor
は、つまみの左側のバーの色を示します。MaximumTrackColor
は、つまみの右側のバーの色を示します。ThumbColor
は、つまみの色を示します。ThumbImageSource
は、ImageSource
型のつまみに使用する画像を示します。
Note
ThumbColor
と ThumbImageSource
のプロパティは相互に排他的です。 両方が設定されている場合、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 になります。 Slider
の ValueChanged
ハンドラーは、slider
オブジェクトの Value
プロパティを使用して最初の Label
の Rotation
プロパティを設定し、String.Format
メソッドをイベント引数の NewValue
プロパティと共に使用して 2 番目の Label
の Text
プロパティを設定します。 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>
最初の Label
の Rotation
プロパティは Slider
の Value
プロパティにバインドされ、2 番目の Label
の Text
プロパティは StringFormat
の仕様でバインドされています。 [基本的なスライダー バインディング] ページは、前の 2 つのページとは少し異なる形で機能します。ページが最初に表示されると、2 番目の Label
に値を含むテキスト文字列が表示されます。 これは、データ バインディングを使用する利点です。 データ バインディングなしでテキストを表示するには、Label
の Text
プロパティを具体的に初期化するか、クラス コンストラクターからイベント ハンドラーを呼び出して 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" ... />
Minimum
と Maximum
の値を負の数に設定できますが、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 個のみであることを意味します。 Slider
の Minimum
を 0、Maximum
を 5000 に設定した場合、Slider
を操作すると、Value
プロパティには 0、5、10、15 などの値が含まれるようになります。
UWP 実装
Slider
の UWP 実装は UWP Slider
コントロールに基づいています。 UWP Slider
の StepFrequency
プロパティは、Maximum
と Minimum
のプロパティの差を 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 に制限されます Maximum
と Minimum
のプロパティの差が 10 以上の場合、StepFrequency
は 1 に設定され、Value
プロパティには整数値が含まれます。
StepSlider ソリューション
より汎用的な StepSlider
については、書籍『Xamarin.Forms を使用したモバイル アプリの作成』の「第 27 章 カスタム レンダラー」を参照してください。 StepSlider
は Slider
と似ていますが、Minimum
と Maximum
の間の値の数を指定するための 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
値を作成します。
スライダーの 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
要素が更新されます。
Binding
マークアップ拡張の StringFormat
コンポーネントは、小数点以下 2 桁を表示する "F2" 形式に設定されています (データ バインディングでの文字列の書式設定については、文字列の書式設定に関する記事で説明します)。ただし、プログラムの UWP バージョンの値は、0、0.1、0.2、...0.9、1.0 に制限されます。 これは、上記の「プラットフォーム実装の違い」セクションで説明したように、UWP Slider
の実装による直接的な結果です。