defaultConfig {
...
buildConfigField "String", "GIT_BRANCH", "\"${'git rev-parse --abbrev-ref HEAD'.execute([], project.rootDir).text.trim()}\""
}
とすると、コードから BuildConfig.GIT_BRANCH でブランチ名を取得できる。
2015年10月29日木曜日
Android ビルド時に git のブランチ名を埋め込む方法
ざきさんに教えてもらった。ありがとうざきさん。
2015年9月15日火曜日
AppCompat でカラーの Raised Button を設定する正しい方法
http://www.google.com/design/spec/components/buttons.html#buttons-flat-raised-buttons
まとめ
1. 背景が Light でボタンのテキストが Dark
2. 背景が Light でボタンのテキストが Dark(Disabled 時はグレー)
3. 背景が Dark でボタンのテキストが Light
4. 背景が Dark でボタンのテキストが Light(Disabled 時はグレー)
5. 背景が Light でボタンのテキストが Light
6. 背景が Light でボタンのテキストが Light(Disabled 時はグレー)
7. 背景が Light でボタンのテキストが Light(Disabled 時は文字もグレー)
解説
Widget.AppCompat.Button
values.xml
Base.Widget.AppCompat.Button
values.xml
textAppearanceButton
values.xml
values-v21.xml
btn_default_material
btn_default_mtrl_shape
まとめ
- ボタンの文字は android:textAppearanceButton(文字サイズは 14sp、文字色は textColorPrimary)
- ボタンの色は colorButtonNormal
- 4以下にも適用される
- テーマ直下の属性なので、全部のボタンに適用されてしまうのが難点
1. 背景が Light でボタンのテキストが Dark
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">#2196F3</item>
</style>
2. 背景が Light でボタンのテキストが Dark(Disabled 時はグレー)
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">@color/button_color</item>
</style>
res/color/button_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#1E000000" android:state_enabled="false" />
<item android:color="#2196F3" />
</selector>
3. 背景が Dark でボタンのテキストが Light
<style name="AppTheme" parent="Theme.AppCompat">
<item name="colorButtonNormal">#2196F3</item>
</style>
4. 背景が Dark でボタンのテキストが Light(Disabled 時はグレー)
<style name="AppTheme" parent="Theme.AppCompat">
<item name="colorButtonNormal">@color/button_color</item>
</style>
res/color/button_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#1EFFFFFF" android:state_enabled="false" />
<item android:color="#2196F3" />
</selector>
5. 背景が Light でボタンのテキストが Light
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">#2196F3</item>
<item name="android:textAppearanceButton">@style/TextAppearance.Button</item>
</style>
<style name="TextAppearance.Button" parent="Base.TextAppearance.AppCompat.Button">
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
6. 背景が Light でボタンのテキストが Light(Disabled 時はグレー)
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">@color/button_color</item>
<item name="android:textAppearanceButton">@style/TextAppearance.Button</item>
</style>
<style name="TextAppearance.Button" parent="Base.TextAppearance.AppCompat.Button">
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
res/color/button_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#1E000000" android:state_enabled="false" />
<item android:color="#2196F3" />
</selector>
7. 背景が Light でボタンのテキストが Light(Disabled 時は文字もグレー)
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="colorButtonNormal">@color/button_color</item>
<item name="android:textAppearanceButton">@style/TextAppearance.Button</item>
</style>
<style name="TextAppearance.Button" parent="Base.TextAppearance.AppCompat.Button">
<item name="android:textColor">@color/button_text_color</item>
</style>
res/color/button_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#1E000000" android:state_enabled="false" />
<item android:color="#2196F3" />
</selector>
res/color/button_text_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/primary_text_disabled_material_light" android:state_enabled="false" />
<item android:color="@color/primary_text_default_material_dark" />
</selector>
解説
Widget.AppCompat.Button
values.xml
<style name="Widget.AppCompat.Button" parent="Base.Widget.AppCompat.Button"/>
Base.Widget.AppCompat.Button
values.xml
<style name="Base.Widget.AppCompat.Button" parent="android:Widget">
<item name="android:background">@drawable/abc_btn_default_mtrl_shape</item>
<item name="android:textAppearance">?android:attr/textAppearanceButton</item>
<item name="android:minHeight">48dip</item>
<item name="android:minWidth">88dip</item>
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
values-v21.xml
<style name="Base.Widget.AppCompat.Button" parent="android:Widget.Material.Button"/>
<style name="Widget.Material.Button">
<item name="background">@drawable/btn_default_material</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="minHeight">48dip</item>
<item name="minWidth">88dip</item>
<item name="stateListAnimator">@anim/button_state_list_anim_material</item>
<item name="focusable">true</item>
<item name="clickable">true</item>
<item name="gravity">center_vertical|center_horizontal</item>
</style>
これを見ると、ボタンの文字は ?attr/textAppearanceButton を参照していることがわかる
textAppearanceButton
values.xml
<style name="Theme.AppCompat" parent="Base.Theme.AppCompat"/>
<style name="Base.Theme.AppCompat" parent="Base.V7.Theme.AppCompat">
<style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">
<item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Button</item>
...
</style>
<style name="Base.V7.Theme.AppCompat.Light" parent="Platform.AppCompat.Light">
<item name="android:textAppearanceButton">@style/TextAppearance.AppCompat.Button</item>
</style>
<style name="TextAppearance.AppCompat.Button" parent="Base.TextAppearance.AppCompat.Button"/>
<style name="Base.TextAppearance.AppCompat.Button">
<item name="android:textSize">@dimen/abc_text_size_button_material</item>
<item name="textAllCaps">true</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
values-v14.xml
<style name="Base.TextAppearance.AppCompat.Button">
<item name="android:textSize">@dimen/abc_text_size_button_material</item>
<item name="android:textAllCaps">true</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
文字サイズは @dimen/abc_text_size_button_material (=14sp)、文字色は ?attr/textColorPrimary である。
values-v21.xml
<style name="Base.Theme.AppCompat" parent="Base.V21.Theme.AppCompat"/>
<style name="Base.V21.Theme.AppCompat" parent="Base.V7.Theme.AppCompat">
...
</style>
<style name="Base.TextAppearance.AppCompat.Button" parent="android:TextAppearance.Material.Button"/>
styles_material.xml
<style name="TextAppearance.Material.Widget.Button" parent="TextAppearance.Material.Button" />
<style name="TextAppearance.Material.Button">
<item name="textSize">@dimen/text_size_button_material</item>
<item name="fontFamily">@string/font_family_button_material</item>
<item name="textAllCaps">true</item>
<item name="textColor">?attr/textColorPrimary</item>
</style>
文字サイズは @dimen/text_size_button_material (=14sp)、文字色は ?attr/textColorPrimary である。
btn_default_material
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/btn_default_mtrl_shape" />
</ripple>
btn_default_mtrl_shape
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Used as the canonical button shape. -->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/button_inset_horizontal_material"
android:insetTop="@dimen/button_inset_vertical_material"
android:insetRight="@dimen/button_inset_horizontal_material"
android:insetBottom="@dimen/button_inset_vertical_material">
<shape android:shape="rectangle">
<corners android:radius="@dimen/control_corner_material" />
<solid android:color="?attr/colorButtonNormal" />
<padding android:left="@dimen/button_padding_horizontal_material"
android:top="@dimen/button_padding_vertical_material"
android:right="@dimen/button_padding_horizontal_material"
android:bottom="@dimen/button_padding_vertical_material" />
</shape>
</inset>
これを見ると ?attr/colorButtonNormal が solid の color に指定されていることがわかる
AndroidJUnitRunner で Toast や PopupWindow を表示するには
Toast、Dialog、PopupWindow など別の Window を使う操作をテストメソッド内で行うと、Handler が作れないと言われてエラーになります
(PopupWindow を内包したユーティリティクラスのテストで困りました)。
例えば以下のテストを実行すると、Toast 部分で
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
になります。
このような Handler の生成が必要な操作では Instrumentation.runOnMainSync() を利用します。
Dialog の場合、InstrumentationRegistry.getTargetContext() では Window Token が無いと言われてエラーになるので、ActivityTestRule から取得した Activity とかを使います。
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
Espresso のコードはテストメソッドの方に書きます。
参考
例えば以下のテストを実行すると、Toast 部分で
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
になります。
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SimpleMenuPopupTest {
@Test
public void showToastTest() {
Context context = InstrumentationRegistry.getTargetContext();
Toast.makeText(context, "Hello Android.", Toast.LENGTH_SHORT).show();
}
}
このような Handler の生成が必要な操作では Instrumentation.runOnMainSync() を利用します。
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SimpleMenuPopupTest {
@Test
public void showToastTest() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
Context context = InstrumentationRegistry.getTargetContext();
Toast.makeText(context, "Hello Android.", Toast.LENGTH_SHORT).show();
}
});
}
}
これでエラーにならなくなりました。
Dialog の場合、InstrumentationRegistry.getTargetContext() では Window Token が無いと言われてエラーになるので、ActivityTestRule から取得した Activity とかを使います。
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
Espresso のコードはテストメソッドの方に書きます。
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SimpleMenuPopupTest {
@Test
public void showPopupTest() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
Context context = activityRule.getActivity();
new AlertDialog.Builder(context)
.setMessage("Hello Android.")
.show();
}
});
onView(withText("Hello Android.")).check(matches(isDisplayed()));
}
}
参考
登録:
投稿 (Atom)