Material Slider

Googleは2020年7月16日にMaterial Components 1.3.0-alpha02 をリリースしました。 今回のリリースで多くの愛を受けているコンポーネントの1つが、地味なスライダーです。 基本的な機能の上にいくつかの素晴らしい機能が追加されており、この投稿ではそれらを少し掘り下げてみます。

Image Source
Licensed under CC 2.0

キーボードなしでユーザーが値を指定できる便利なコントロールが Slider です。 基本的な使用方法は、Android Framework の SeekBarAppCompatSeekBar ウィジェットに非常によく似ています。 オーディオやビデオの再生中に特定の場所にスクラブしたり、指定した範囲内の値を指定したりと、さまざまな使い方があります。 しかし、この記事の後半で説明するように、Slider が提供するいくつかの追加のユースケースがあります。

まず、非常に単純なスライダー コントロールを作成し、その外観と動作を確認します。

基本的な動作

マテリアル スライダーの作成は非常に簡単です:

res/layout/activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

<?xml version=”1.0″ encoding=”utf-8″?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:tools=”http://schemas.android.com/tools”です。
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:padding=”32dp”
tools:context=”.MainActivity”>
android:id=”@+id/seek_bar”
android:layout_width=”0dp”

+roid:layout_height=”wrap_content”

android:valueFrom=”0″
android:valueTo=”100″
app.CompatSeekBAR(androidのアプリ)

android:android:layout=”0″(アンドロイド・ライト)
android:layout=”0″(アンドロイド・ライト)

app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
<com.Layer.com.Layer.com.Layer.com_Layer.com_Layer.com_Layer.com

app:layout_constraintTop_toStartOf=”parent”
android:id=”@+id/continuous_slider”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android.Continuous_slider:valueFrom=”0″
android:valueTo=”100″
app:layout_constraintBottom_toTopOf=”@id/discrete_slider”
app:layout_constraintEnd_toEndOf=”@id/seek_bar”
app:layout_constraintStart_toStartOf=”@id/seek_bar”
app:layout_constraintEnd_toEndOf=”@id/seek_bar”
</ConstraintLayout>

valueFrom および valueTo 属性を使用して両方のコントロールに 0 ~ 100 の範囲を指定します。 これを実行すると、次のような動作になります (AppCompatSeekBar が上、Slider が下):

これらは非常に似ていますが、いくつかの重要な違いがあります。 まず、Slider は私のテーマで定義された色を使ってスタイル付けされているのに対し、AppCompatSeekBar は AppCompat ライブラリのデフォルトの色を使っています。 次に、Sliderは少し大きくなっていて、ユーザーにとって少し分かりやすくなっています。 おそらく最も重要な違いは、ユーザーが位置をドラッグしたときに Slider にラベルが追加されたことです。 これにより、ユーザーは選択中の値を正確に把握しやすくなります。 確かにこの値を表示するためにレイアウトに別のViewを追加することはできますが、ツールチップ・ラベルはUIをより雑然とさせません。 もし必要なければ、それを無効にすることができます。

しかし、他に 2 つのラベル動作があります。 1 つ目は、前の例で見たデフォルトで、app:labelBehaviour="floating" で、ラベルをビューにフロートさせます。 もう1つのオプションは app:labelBehaviour="withinBounds" です。 これは floating と同じレンダリングですが、Slider のサイズにどのように影響するかが異なります。 floating では、コントロールの高さの測定値にラベルが含まれませんが、withinBounds では、高さの測定値にラベルが含まれます。

Discrete Slider

これまでに見てきた Slider のバリエーションは、連続スライダとして知られています。 つまり、それが返す値は範囲内のどのような値でもよいということです。 しかし、これを制限したい場合があります。 たとえば、この連続的な Slider は小数値を返しますが、整数値やもっと大きなステップに値を限定する必要があるかもしれません。 これを実現するには、値の離散的なセットを返す離散スライダを使用します。 1つの属性を追加することで、連続的な Slider を離散的なものに変更することができます。

1
2
3
4
5
6
7
8
9
10
11

<com.NET Framework 2.0

android:id=”@+id/continuous_slider”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android.Material.Slider()
android.Continuous_slider(スライダ-)

android.Continuous_id(スライダ-)stepSize=”10″

android:valueFrom=”0″
android:valueTo=”100″
app:layout_constraintBottom_toTopOf=”@id/discrete_slider”
app.layout_constraintBottom=”100″
app.layout_content=”0″
android:valueFrom=”100″

app:layout_constraintStart_toStartOf=”@id/seek_bar”
app:layout_constraintTop_toBottomOf=”@id/seek_bar” />

app:stepSize="10" を追加すると、Slider は10の倍数の値だけを返します。 これは UX を少し変更します。

まず最初に、返される離散値を示す目盛りがあります。 これらは非常に微妙ですが、トラック上ではっきりと見ることができます。 2 番目の違いは、ラベル値でわかるように、選択がスムーズではなく、離散値の間でジャンプしていることです。

RangeSlider

また、Slider の別のバリエーションを使用することもできます。 これまで、Slider を使用して単一の値を選択する方法を見てきましたが、ユーザーは RangeSlider を使用して範囲を選択できます。

Slider を最初に設定したとき、スライダーが返す値の範囲を指定するために valueFromvalueTo を使用しました。 たとえば、ショッピング アプリで検索機能を提供する場合、ユーザーが価格範囲を指定できるようにしたいと思うかもしれません。 連続モードと離散モードの両方をサポートする RangeSlider を使用して、これを実現することができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

<com.google.android.material.slider。RangeSlider
android:id=”@+id/continuous_range”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android.Material.RangeSlider.RangeSlider
android.Continuous_range:レンジスライダ

android.Continuous_range:レンジスライダ :valueFrom=”0″

android:valueTo=”100″
app:layout_constraintBottom_toTopOf=”@id/discrete_range”
app:layout_constraintEnd_toEndOf=”@id/continuous_slider”
app:layout_constraintStart_toStartOf=”@id/continuous_slider”
app:layout_constraintEnd_toEndOf=”parent”
app.Continuous_sliderlayout_constraintEnd_toStartOf=”@id/continuous_slider” app::layout_constraintTop_toBottomOf=”@id/discrete_slider”
app:values=”@array/double_slider_values”/>
<com.google.android.material.slider.DoubleSlider。RangeSlider
android:id=”@+id/discrete_range”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android.RangeSlider:stepSize=”10″
android:valueFrom=”0″
android:valueTo=”100″
app:layout_constraintBottom_toBottomOf=”parent”
app.layout_constraintBottom=”parent” app.layout_constraintBottom=”parent” app.layout_constraintBottom=”parent” app.layout_contentlayout_constraintEnd_toEndOf=”@id/continuous_slider”
app:layout_constraintStart_toStartOf=”@id/continuous_slider”
app:layout_constraintTop_toBottomOf=”@id/continuous_range”
app:values=”@array/triple_slider_values” />

ここに必須属性がある。 app:values – これがないと、RangeSlider は標準の Slider の動作に戻ります。 この属性に値の配列を指定する必要があります:

res/values/arrays.xml

1
2
3
4
5
6
7
8
9
10
11
12
13

<?xml version=”1.0″ encoding=”utf-8″?>
<resources>
<array name=”double_slider_values”>
<item>20</item>?
<item>60</item>
</array>
<array name=”triple_slider_values”>
<item>20</item>
<item>60</item>
<item>100</item>
</array>
</resources>

これらの配列はそれぞれ2値と3値を持っています。 で、連続値RangeSliderは2つの値を持つ範囲を取得し、離散値RangeSliderは3つの値を持つ範囲を取得します。

上の例は、ユーザーが上限と下限のある範囲を指定することができる単純な 2 つの値の範囲を示しています。 RangeSlider に設定した全体の範囲は、ユーザーが指定できる最大値と最小値を制限します。

下の例はさらに興味深いものです。 離散的な RangeSlider であると同時に、配列内の 3 つの値により、コントロール内に 3 つのサムポイントが作成されます。 範囲の上限と下限だけでなく、ユーザーは上限と下限の間のどこかにポイントを指定することもできる。 真ん中のサムポイントをドラッグしても、上下限の境界線から外れることはありません。 ドラッグされたサムポイントのラベルは、常に他のラベルの上に描かれ、そのラベルが重なる可能性があります。

RangeSlidergetValues()メソッドを呼び出すことで、選択された値を取得することができる。 これは、app:valuesで指定した配列のサイズと同じサイズの値の配列を返します。

ラベルのフォーマット

より注意深い人は、2値および3値のRangeSlidersのラベルフォーマットに違いがあることに気付いたかもしれません。 連続した2値 RangeSlider はデフォルトのラベルフォーマットを使っているのに対し、 離散した3値 Value: は接頭辞を付けている。 このことから、ラベルをカスタマイズすることができることがわかります。kt

1
2
3
4
5
6
78
9
10
11
12
13
14
15

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.Bundle(savedInstanceState: Bundle?) {
binding = ActivityMainBinding(savedInstanceState: Bundle?inflate(layoutInflater)
setContentView(binding.root)
binding.discreteRange.setLabelFormatter {
getString(R.string.label_format, it)
} ←クリックすると拡大表示されます。
}
}

LabelFormatter はSAMインターフェースで、単一のgetFormattedValue()メソッドを持ち、この場合ラムダに変換されます。 私はこのためにフォーマット文字列リソースを使用しました:

res/values/strings.xml

1
2
3
4

<resources>
<string name=”app_name”>Material Slider</string>
<string name=”label_format”>Value.Of.Pirates> <string name=”app_name”>Material Slider>/string

</resources>

これをプログラム的に行う必要があります。 このようなフォーマット文字列はほとんどのユースケースに適合すると思いますので、XML 属性を使用してフォーマット文字列を指定できるとよいでしょう。

Conclusion

SliderRangeSliderSeekBar の本当に素晴らしい反復です。 同じ機能に加えて、もっと多くのことを提供しています。 特に、アクティブなラベルをパッシブなラベルの上に描画するなど、細部への配慮に感心させられる。 これはよく設計され、実装されたコントロールで、私はこれを完全に使うつもりです!