2015年1月13日火曜日

AppCompat v7 で tint 処理しているクラスとか

メモ

Android 5.0 で EditText の normal 時の色を独自に変える

以前のエントリ「Android 5.0 でのカラーカスタマイズと属性名の関係」で書いたように、EditText の normal 時の線の色は colorControlNormal になります。

colorControlNormal にはデフォルトでは textColorSecondary が指定されており、Theme.Material では @color/secondary_text_material_dark、Theme.Material.Light では @color/secondary_text_material_light になります。
これらの normal 時の色は最終的に以下になります。 #b3ffffff #8a000000 つまり、Theme.Material.Light では線の色は #8a000000 です。

実際にこの色の EditText を配置してみると、Material Design の Components > Text fields で例としてあげられている画像の色より、かなり濃いことがわかります。

colorControlNormal に薄いグレーを指定すれば、EditText の normal 時の色を変えられますが、この属性はさまざまなところで使われており、例えば CheckBox の normal 時の色も薄くなってしまいます。

colorControlNormal ではなく独自に色を指定したい場合、残念ながら用意されている属性値ではできません。 EditText の背景を独自のリソースに変える必要があります。

EditText の 5.0 でのデフォルト背景は次のようになっています。

android:drawable/edit_text_material.xml <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="@dimen/control_inset_material"> <ripple android:color="?attr/colorControlActivated"> <item> <selector> <item android:state_enabled="false"> <nine-patch android:src="@drawable/textfield_default_mtrl_alpha" android:tint="?attr/colorControlNormal" android:alpha="?attr/disabledAlpha" /> </item> <item> <nine-patch android:src="@drawable/textfield_default_mtrl_alpha" android:tint="?attr/colorControlNormal" /> </item> </selector> </item> <item android:id="@+id/mask" android:drawable="@drawable/textfield_activated_mtrl_alpha" /> </ripple> </inset>

これを参考に、AppCompat の画像リソースを利用して次のようにします。

drawable-v21/my_edit_text_material.xml <?xml version="1.0" encoding="utf-8"?> <inset xmlns:android="http://schemas.android.com/apk/res/android" android:inset="@dimen/control_inset_material"> <ripple android:color="?attr/colorControlActivated"> <item> <selector> <item android:state_enabled="false"> <nine-patch android:src="@drawable/abc_textfield_default_mtrl_alpha" android:tint="?attr/colorEditTextNormal" android:alpha="?android:attr/disabledAlpha" /> </item> <item> <nine-patch android:src="@drawable/abc_textfield_default_mtrl_alpha" android:tint="?attr/colorEditTextNormal" /> </item> </selector> </item> <item android:id="@android:id/mask" android:drawable="@drawable/abc_textfield_activated_mtrl_alpha" /> </ripple> </inset> ここでは、?attr/colorControlNormal の代わりに ?attr/colorEditTextNormal を指定しています。

values/attr.xml <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="colorEditTextNormal" format="color|reference" /> </resources> values-v21/styles.xml <?xml version="1.0" encoding="utf-8"?> <resources> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="editTextBackground">@drawable/my_edit_text_material</item> <item name="colorEditTextNormal">#1f000000</item> </style> </resources> Material Design の Resources > Sticker sheets & icons で配布されている stickersheet_general.ai では、EditText の色は divider と同じ #000000 の alpha 12% でした。


Android 5.0 でのカラーカスタマイズと属性名の関係

CheckBox
  • normal : colorControlNormal
  • checked: colorControlActivated
btn_check_material_anim.xml


RadioButton
  • normal : colorControlNormal
  • checked: colorControlActivated
btn_radio_material_anim.xml


Switch

thumb
  • normal : colorSwitchThumbNormal
  • checked: colorControlActivated
switch_thumb_material_anim.xml

track
  • normal : colorForeground, alpha=0.3
  • checked: colorControlActivated, alpha=0.3
switch_track_material.xml


RatingBar
  • normal : colorControlNormal
  • pressed: colorControlActivated
ratingbar_full_empty_material.xml
ratingbar_full_filled_material.xml


EditText
  • normal : colorControlNormal
  • focused: colorControlActivated
edit_text_material.xml


Text選択
  • ハンドル : colorControlActivated
  • カーソル : colorControlActivated
text_cursor_material.xml
text_select_handle_left_material.xml
text_select_handle_middle_material.xml
text_select_handle_right_material.xml


Button

ベース
  • normal : colorButtonNormal
  • pressed : colorControlHighlight
btn_default_material.xml
btn_borderless_material.xml


ToggleButton

ベース
  • normal : colorButtonNormal
  • pressed : colorControlHighlight
インディケータ
  • normal : colorControlNormal
  • checked: colorControlActivated
btn_toggle_material.xml


ProgressBar

  • くるくる : colorControlActivated
vector_drawable_progress_indeterminate_horizontal.xml

Horizontal
  • ベース : colorControlNormal, alpha=disabledAlpha
  • Progress : colorControlActivated
  • SecondaryProgress : colorControlActivated, alpha=disabledAlpha
progress_horizontal_material.xml


SeekBar
  • ベース : colorControlNormal
  • Progress : colorControlActivated
  • 取手 : colorControlActivated
scrubber_control_selector_material.xml
scrubber_control_material_anim.xml
scrubber_progress_horizontal_material.xml


Spinner
  • normal : colorControlNormal
  • pressed : colorControlActivated
  • checked : colorControlActivated
spinner_background_material.xml


ScrollBar
  • handle : colorControlNormal
scrollbar_handle_material.xml


FastScroll

thumb
  • normal : colorControlNormal
  • pressed : colorControlActivated
fastscroll_thumb_material.xml

track
  • 常時 : colorControlNormal
fastscroll_track_material.xml


TimePicker のヘッダー
  • normal : colorAccent
  • pressed: colorControlHighlight
time_picker_header_material.xml


ExpandableListView
  • expander : colorControlNormal
expander_group_material.xml


selectableItemBackground
  • pressed: colorControlHighlight
item_background_material.xml
item_background_borderless_material.xml


■ 参考 <style name="Theme.Material"> ... <!-- Color palette --> <item name="colorPrimaryDark">@color/primary_dark_material_dark</item> <item name="colorPrimary">@color/primary_material_dark</item> <item name="colorAccent">@color/accent_material_dark</item> <item name="colorEdgeEffect">?attr/colorPrimary</item> <item name="colorControlNormal">?attr/textColorSecondary</item> <item name="colorControlActivated">?attr/colorAccent</item> <item name="colorControlHighlight">@color/ripple_material_dark</item> <item name="colorButtonNormal">@color/btn_default_material_dark</item> <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item> </style> <style name="Theme.Material.Light" parent="Theme.Light"> ... <!-- Color palette --> <item name="colorPrimaryDark">@color/primary_dark_material_light</item> <item name="colorPrimary">@color/primary_material_light</item> <item name="colorAccent">@color/accent_material_light</item> <item name="colorControlNormal">?attr/textColorSecondary</item> <item name="colorControlActivated">?attr/colorAccent</item> <item name="colorControlHighlight">@color/ripple_material_light</item> <item name="colorButtonNormal">@color/btn_default_material_light</item> <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item> </style>
  • support/v7/appcompat/src/android/support/v7/internal/widget/TintManager.java
  • support/v7/appcompat/src/android/support/v7/internal/widget/TintDrawableWrapper.java



2015年1月2日金曜日

Theme.Material の SeekBar は setProgress() で
secondaryProgress の描画が消えてしまう

SeekBar は ProgressBar を継承しているので、setSecondaryProgress() で2番目のプログレスを設定することができます。

下記の動画は setSecondaryProgress() を呼んだ後に setProgress() を呼んだものです。



Holo テーマのスタイルの SeekBar(一番上)では、setProgress() を呼ぶと secondary progress のバーの描画はそのままで progress のバーがセットされます。

一方、Material テーマのスタイルの SeekBar(真ん中)では、setProgress() を呼ぶと secondary progress のバーの描画が消えてしまいます。ちなみにこの時点で getSecondaryProgress() を呼ぶと、描画は消えていますがセットされている値が返ってきます。

Material テーマのスタイルの ProgressBar(一番下)では、secondary progress のバーの描画は消えません。

そこで、SeekBar に style="@android:style/Widget.Material.ProgressBar.Horizontal" を指定してみたところ、Progress Bar と同じような見た目になり、secondary progress のバーの描画は消えなくなりました。 <SeekBar style="@android:style/Widget.Material.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" /> Widget.Material.ProgressBar.Horizontal は次のようになっており、progressDrawable の指定が作用していると予想しました。 <style name="Widget.Material.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal"> <item name="progressDrawable">@drawable/progress_horizontal_material</item> <item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material</item> <item name="minHeight">16dip</item> <item name="maxHeight">16dip</item> </style> そこで、@android:drawable/progress_horizontal_material をプロジェクト内に持ってきて次のように指定したところ、secondary progress のバーの描画は消えなくなりました。 <SeekBar android:layout_width="match_parent" android:layout_height="wrap_content" android:progressDrawable="@drawable/progress_horizontal_material" /> progress_horizontal_material.xml <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background"> <nine-patch android:src="@drawable/progress_mtrl_alpha" android:tint="?attr/colorControlNormal" android:alpha="?android:attr/disabledAlpha" /> </item> <item android:id="@android:id/secondaryProgress"> <scale android:scaleWidth="100%"> <nine-patch android:src="@drawable/progress_mtrl_alpha" android:tint="?attr/colorControlActivated" android:alpha="?android:attr/disabledAlpha" /> </scale> </item> <item android:id="@android:id/progress"> <scale android:scaleWidth="100%"> <nine-patch android:src="@drawable/progress_mtrl_alpha" android:tint="?android:attr/colorControlActivated" /> </scale> </item> </layer-list> Material テーマの SeekBar のデフォルトスタイルは Widget.Material.SeekBar です。このスタイルでは progressDrawable に @android:drawable/scrubber_progress_horizontal_material が指定されています。 <style name="Widget.Material.SeekBar"> <item name="indeterminateOnly">false</item> <item name="progressDrawable">@drawable/scrubber_progress_horizontal_material</item> <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_material</item> <item name="thumb">@drawable/scrubber_control_material_anim</item> <item name="splitTrack">true</item> <item name="focusable">true</item> <item name="paddingStart">16dip</item> <item name="paddingEnd">16dip</item> <item name="mirrorForRtl">true</item> <item name="background">?attr/selectableItemBackgroundBorderless</item> </style> scrubber_progress_horizontal_material.xml は progress_horizontal_material.xml と違い、ルートタグが <selector> です。

@android:drawable/scrubber_progress_horizontal_material <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false"> <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha" android:tint="?attr/colorControlNormal" /> </item> <item> <layer-list> <item android:id="@id/background"> <nine-patch android:src="@drawable/scrubber_track_mtrl_alpha" android:tint="?attr/colorControlNormal" /> </item> <item android:id="@id/secondaryProgress"> <scale android:scaleWidth="100%"> <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha" android:tint="?attr/colorControlNormal" /> </scale> </item> <item android:id="@id/progress"> <scale android:scaleWidth="100%"> <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha" android:tint="?attr/colorControlActivated" /> </scale> </item> </layer-list> </item> </selector> これの <layer-list> 部分だけを取り出して progressDrawable に指定したところ、secondary progress のバーの描画が消えなくなりました。
なぜ selector の中に入れると描画が変になるのかよくわかりませんが、style="@android:style/Widget.Material.ProgressBar.Horizontal" を指定するのが手っ取り早そうです。