3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

StatusBarに色を付けてNavigationBarを透明にしてCoordinatorLayoutを使おうとしたらハマった

Posted at

Materialデザイン風にStatusBarにcolorPrimaryDarkを付けて、なおかつNavigationBarを透明にしながらCoordinatorLayoutでToolbarをスクロールしたら隠したいってときに思った風にできずにハマったので、あまり綺麗ではない対処法を取ったので書いておきます

あとソースコードはXamarin使ってるのでC#ですけど簡単にJava翻訳できると思います
SupportLibraryはJavaで使われてるやつのXamarin版となるXamarin.Android.Support.**のv23.1.1.1を使ってます

最初

MainActivity.axml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/RootLayout"
    android:fitsSystemWindows="true">
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/CoordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">
            <android.support.v7.widget.Toolbar
                android:id="@+id/Toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
            <android.support.design.widget.TabLayout
                android:id="@+id/TabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary" />
        </android.support.design.widget.AppBarLayout>
        <android.support.v4.view.ViewPager
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:id="@+id/ViewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
Fragment.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:id="@+id/RootLayout">
       
        ~~~コンテンツ~~~

    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
values/Styles.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/ColorPrimary</item>
    <item name="colorPrimaryDark">@color/ColorPrimaryDark</item>
    <item name="colorAccent">@color/ColorAccent</item>
  </style>
  <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
  <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
</resources>
values-v21/Styles.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/ColorPrimary</item>
    <item name="colorPrimaryDark">@color/ColorPrimaryDark</item>
    <item name="colorAccent">@color/ColorAccent</item>
    <item name="android:statusBarColor">@color/ColorPrimaryDark</item>
    <item name="android:navigationBarColor">@android:color/transparent</item>
    <item name="android:windowTranslucentNavigation">true</item>
  </style>
</resources>

(android:navigationBarColorの設定は必要ないかもしれない)

ViewPagerの中にはFragmentがぶちこまれます

これでイケると思ったのですがandroid:fitsSystemWindows="true"はStatusBarだけでなくNavigationBarのとこもpaddingしちゃうみたいで透過したNavigationBarの下にコンテンツを見せるということができなかったのです :scream:

試行錯誤

android:fitsSystemWindows="true"の入れる場所を変えたり、android:fitsSystemWindows="true"を使わずにpaddingしたり、StatusBarの部分になにもないViewを追加したりしても希望通りの状態にはなりませんでした…

ぐーぐる大先生

とりあえずぐーぐる大先生に聞いてみようってことで調べていたらstackOverFlowにAndroid 4.4 — Translucent status/navigation bars — fitsSystemWindows/clipToPadding don't work through fragment transactionsという関係ありそうな記事を見つけました

そしてそこのリンク先のTHE MIND OF AN ANDROID DEV - MAKING THE STATUS BAR AND NAVIGATION BAR TRANSPARENT, WITH A LISTVIEW, ON ANDROID 4.4 KITKATを見るとどうやらandroid:clipToPadding="false"でScrollViewなどでViewからはみ出た部分を表示することができるということがわかりました

対策

なのでandroid:clipToPadding="false"とそれを使うのに必要らしいandroid:clipChildren="false"を使ったのですが、今度はViewPagerの高さがToolbarが表示されているときの高さのまま固定されToolbarが隠れたら下にToolbarの高さ分余白ができてしまいました :scream:

ということなので最初からViewPagerの高さをToolbarの高さ分大きくしておくことにしました

MainActivity.cs
private int originalViewPagerHeight = 0;

public override void OnWindowFocusChanged(bool hasFocus) {
    base.OnWindowFocusChanged(hasFocus);
    if(Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) {
        var viewpager = FindViewById<ViewPager>(Resource.Id.ViewPager);
        if(originalViewPagerHeight == 0) {
            originalViewPagerHeight = viewpager.Height;
        }
        viewpager.LayoutParameters.Height = originalViewPagerHeight + GetActionbarSize();
    }
}

public int GetActionbarSize() {
    var tv = new TypedValue();
    int result = 0;
    if(this.Theme.ResolveAttribute(Resource.Attribute.actionBarSize,tv,true)) {
        result = TypedValue.ComplexToDimensionPixelSize(tv.Data,this.Resources.DisplayMetrics);
    }
    return result;
}

そしたら今度はNestedScrollViewでToolbarの高さ分スクロールできる部分が減ってしまう事態に :scream:
(これはまじで原因わからなかった)

ということなのでスクロールできる部分が減るなら最初から多めに取っておけばいいじゃんってことでレイアウトを変更しました

Fragment.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clipToPadding="false">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:id="@+id/RootLayout">
        
        ~~~コンテンツ~~~

        <View
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:id="@+id/BottomView"
            android:visibility="gone" />
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
Fragment.cs
public override View OnCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
            
    ~~~いろいろ~~~

    if(Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) {
        view.FindViewById<View>(Resource.Id.BottomView).Visibility = ViewStates.Visible;
    }
    return view;
}

これで完璧wってなったのですが画面回転を試すと

  • 縦画面で起動←OK
  • 横画面で起動←OK
  • 縦画面で起動→横画面に←Toolbarの高さ分スクロールできない
  • 横画面で起動→縦画面に→横画面に→Toolbarの高さ分スクロールできない

という風に画面回転をすると横画面の時にまたToolbarの高さ分スクロールできないということに(なんでだよ…)

対策版

以上を踏まえたうえでの対策した完成版をあげておきます
下部に余計な余白がでてくる可能性はありますがまぁ大丈夫かと

(Styleはそのままです)

MainActivity.axml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/RootLayout"
    android:fitsSystemWindows="true"
    android:clipChildren="false"
    android:clipToPadding="false">
    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/CoordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false">
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">
            <android.support.v7.widget.Toolbar
                android:id="@+id/Toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|enterAlways"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
            <android.support.design.widget.TabLayout
                android:id="@+id/TabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary" />
        </android.support.design.widget.AppBarLayout>
        <android.support.v4.view.ViewPager
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:id="@+id/ViewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
Fragment.axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clipToPadding="false">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:id="@+id/RootLayout">

        ~~~コンテンツ~~~
        
        <View
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:id="@+id/BottomView"
            android:visibility="gone" />
        <View
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:id="@+id/BottomView2"
            android:visibility="gone" />
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
MainActivity.cs
private int originalViewPagerHeight = 0;

public override void OnWindowFocusChanged(bool hasFocus) {
    base.OnWindowFocusChanged(hasFocus);
    if(Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) {
        var viewpager = FindViewById<ViewPager>(Resource.Id.ViewPager);
        if(originalViewPagerHeight == 0) {
            originalViewPagerHeight = viewpager.Height;
        }
        viewpager.LayoutParameters.Height = originalViewPagerHeight + GetActionbarSize();
    }
}

public int GetActionbarSize() {
    var tv = new TypedValue();
    int result = 0;
    if(this.Theme.ResolveAttribute(Resource.Attribute.actionBarSize,tv,true)) {
        result = TypedValue.ComplexToDimensionPixelSize(tv.Data,this.Resources.DisplayMetrics);
    }
    return result;
}
Fragment.cs
public override View OnCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
            
    ~~~いろいろ~~~

    if(Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop) {
        view.FindViewById<View>(Resource.Id.BottomView).Visibility = ViewStates.Visible;
        if(view.Resources.Configuration.Orientation== global::Android.Content.Res.Orientation.Landscape) {
            view.FindViewById<View>(Resource.Id.BottomView2).Visibility = ViewStates.Visible;
        }
    }
    return view;
}

さいごに

もっと綺麗なやり方あったらコメントお願いします

画面はXperia Z4でしか確認していないので機種差はあるかもしれないです

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?