はじめに
ここで会ったが5年目、チャレンジは3回目。
掲題の、透明Activityへの動的変更というお代に対してやっと解決したので記事として残します。
透明Activityが動的指定で必要な理由
画面A(HogeActivity)から画面B(FugaActivity)へ遷移した状態で下スワイプ時、背景に画面Aが出てほしいという仕様を満たすために透明Activityが必要となりました。
ただ、ActivityのXMLは大体共通のものを使っているため、画面によってThemeを変えられないと無駄にXMLが増えてしまうことからOSバージョンを見て透明ActivityなThemeにOverride可能なことが必須でした。
実装方法と詳細
色々サイトにあるように、Activity#onCreateでsetContentViewする前に変更する必要があります。
以下で動作しています。
override fun getTheme(): Resources.Theme {
val theme: Resources.Theme = super.getTheme();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
theme.applyStyle(R.style.TranslucentTheme, true)
lifecycleScope.launch(Dispatchers.IO) {
// setTranslucentはメインスレッドで呼ぶとANRになるので注意!!
setTranslucent(true)
}
} else {
theme.applyStyle(R.style.Theme_AppCompat_DayNight_NoActionBar, true)
}
return theme
}
override fun getTheme()
を使いたくない場合は以下でもOKです(getThemeはActivity起動時複数回呼ばれる)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// 以下は透明なActivityにするための処理(OS11以上)
window.setBackgroundDrawableResource(android.R.color.transparent)
lifecycleScope.launch(Dispatchers.IO) {
// setTranslucentはメインスレッドで呼ぶとANRになるので注意!!
setTranslucent(true)
}
}
}
透明なTheme(TranslucentTheme)は以下
<style name="TranslucentTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
ポイントは以下3点です
- getThemeをoverrideし、所定のStyleを読み込むようにします(動的にThemeを変更するだけならこれのみでOK)
- 透明Activityにしたい場合はsetTranslucent(true)が必須ですがOS11以上でないと使えません
- 透明Activity使用時はOSバージョンに気をつける必要があります(OS8だとクラッシュの恐れがあります)
以上。