[android] 탐색 창 반투명 상태 표시 줄이 작동하지 않음

Android 프로젝트에서 작업 중이며 Navigation Drawer를 구현하고 있습니다. 새로운 머티리얼 디자인 사양머티리얼 디자인 체크리스트를 읽고 있습니다.
사양에 따르면 슬라이드 아웃 창은 상태 표시 줄을 포함한 다른 모든 것 위에 떠 있어야하며 상태 표시 줄 위에 반투명해야합니다.

내 탐색 패널이 상태 표시 줄 위에 있지만 투명성이 없습니다. Google 개발자 블로그 스팟, 위의 링크에서 제안한 대로이 SO 게시물 의 코드를 따랐습니다. DrawerLayout을 사용하여 ActionBar / Toolbar 및 상태 표시 줄 아래에 표시하려면 어떻게해야합니까? .

아래는 내 XML 레이아웃입니다.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <android.support.v7.widget.Toolbar
            android:id="@+id/my_awesome_toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:minHeight="?attr/actionBarSize"
            android:background="@color/appPrimaryColour" />
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout"
        android:layout_width="304dp"
        android:layout_height="match_parent"
        android:layout_gravity="left|start"
        android:fitsSystemWindows="true"
        android:background="#ffffff">
        <ListView android:id="@+id/left_drawer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:choiceMode="singleChoice"></ListView>
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

아래는 내 앱 테마입니다.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/appPrimaryColour</item>
        <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
        <item name="colorAccent">@color/appPrimaryColour</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>

    </style>

아래는 내 앱 v21 테마입니다.

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/appPrimaryColour</item>
    <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
    <item name="colorAccent">@color/appPrimaryColour</item>
    <item name="windowActionBar">false</item>
    <item name="windowActionModeOverlay">true</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

아래는 내 onCreate 메서드입니다.

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);

    mDrawerLayout = (DrawerLayout)findViewById(R.id.my_drawer_layout);
    mDrawerList = (ListView)findViewById(R.id.left_drawer);

    mDrawerLayout.setStatusBarBackgroundColor(
        getResources().getColor(R.color.appPrimaryColourDark));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        LinearLayout linearLayout = 
            (LinearLayout)findViewById(R.id.linearLayout);
        linearLayout.setElevation(30);
    }

아래는 상단이 반투명하지 않음을 보여주는 내 탐색 창 스크린 샷 입니다.

상태 표시 줄에 투명하지 않은 것을 보여주는 스크린 샷



답변

상태 표시 줄 배경은 흰색이며 서랍의 배경입니다 LinearLayout. 왜? 당신은 fitsSystemWindows="true"당신 DrawerLayout과 그 LinearLayout내부를 위한 설정 입니다 . 이로 인해 상태 표시 줄 (투명) 뒤로LinearLayout 확장 됩니다. 따라서 상태 표시 줄의 서랍 부분 배경을 흰색으로 만듭니다.

여기에 이미지 설명 입력
서랍을 상태 표시 줄 뒤로 확장하지 않으려면 (전체 상태 표시 줄에 반투명 배경을 사용하려는 경우) 다음 두 가지를 수행 할 수 있습니다.

1) 단순히 배경 값을 제거하고 그 LinearLayout안에있는 콘텐츠의 배경에 색을 지정할 수 있습니다 . 또는

2) 당신은 제거 할 수 있습니다 fitsSystemWindows="true"귀하의에서 LinearLayout. 나는 이것이 더 논리적이고 깨끗한 접근이라고 생각합니다. 또한 탐색 창이 확장되지 않는 상태 표시 줄 아래에 그림자가 드리워지지 않도록합니다.

여기에 이미지 설명 입력
서랍이 상태 표시 줄 뒤로 확장되고 반투명 상태 표시 줄 크기의 오버레이 ScrimInsetFrameLayout가 있도록하려면를 서랍 콘텐츠 ( ListView) 의 컨테이너로 사용하고 를 사용 하여 상태 표시 줄 배경을 설정할 수 app:insetForeground="#4000"있습니다. 물론 #4000원하는대로 변경할 수 있습니다 . fitsSystemWindows="true"여기 에 보관하는 것을 잊지 마세요 !

또는 콘텐츠를 오버레이하지 않고 단색 만 표시하려면 배경을 원하는대로 설정하면 LinearLayout됩니다. 그래도 콘텐츠의 배경을 별도로 설정하는 것을 잊지 마십시오!

편집 : 더 이상이 문제를 다룰 필요가 없습니다. 보다 쉬운 탐색 드로어 /보기 구현 은 설계 지원 라이브러리 를 참조하십시오 .


답변

상태 표시 줄에 반투명 색상을 사용하기 만하면됩니다. v21 테마에 다음 행을 추가하십시오.

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/desired_color</item>

잊지 마세요 color(자원) 항상의 형식이어야합니다 #AARRGGBB. 이것은 색상에 알파 값도 포함된다는 것을 의미합니다.


답변

이와 비슷한 것을 사용하지 않는 이유는 무엇입니까?

<android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

    <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    <ListView
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"
            android:background="#80111111"/>
</android.support.v4.widget.DrawerLayout>

위의 코드는 작업 android:background표시 줄 내에서 투명도를 표시 할 수 있도록 의 알파 리소스를 사용합니다 .

다른 답변에서 알 수 있듯이 코드를 통해이를 수행하는 다른 방법이 있습니다. 위의 내 대답은 xml 레이아웃 파일에서 필요한 작업을 수행하며 내 의견으로는 쉽게 편집 할 수 있습니다.


답변

여기에 언급 된 모든 답변은 너무 오래되고 길다. 최신 Navigationview와 함께 작동하는 가장 좋고 짧은 솔루션은

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
    super.onDrawerSlide(drawerView, slideOffset);

    try {
        //int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
            // Do something for lollipop and above versions

        Window window = getWindow();

        // clear FLAG_TRANSLUCENT_STATUS flag:
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

        // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        // finally change the color to any color with transparency

         window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDarktrans));}

    } catch (Exception e) {

        Crashlytics.logException(e);

    }
}

서랍을 열면 상태 표시 줄 색상이 투명으로 변경됩니다.

이제 서랍을 닫을 때 상태 표시 줄 색상을 다시 어둡게 변경해야하므로 이렇게 할 수 있습니다.

@Override
public void onDrawerClosed(View drawerView) {
   super.onDrawerClosed(drawerView);
    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            // Do something for lollipop and above versions

            Window window = getWindow();

            // clear FLAG_TRANSLUCENT_STATUS flag:
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

            // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

            // finally change the color again to dark
            window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
        }
    } catch (Exception e) {
        Crashlytics.logException(e);
    }
}

그런 다음 기본 레이아웃에서 한 줄을 추가하십시오.

            android:fitsSystemWindows="true"

서랍 레이아웃은 다음과 같습니다.

            <android.support.v4.widget.DrawerLayout     
            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:id="@+id/drawer_layout"
            android:fitsSystemWindows="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

내비게이션보기는 다음과 같습니다.

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer"
        />

나는 그것을 테스트하고 완벽하게 작동합니다. 누군가에게 도움이되기를 바랍니다. 이것은 최선의 접근 방식은 아니지만 원활하게 작동하고 구현하기 쉽습니다. 도움이된다면 표시해주세요. 해피 코딩 🙂


답변

탐색 창 레이아웃을 ScrimLayout.

A는 ScrimLayout기본적으로 탐색 서랍 레이아웃 위에 반투명 직사각형을 그립니다. 인 세트의 크기를 검색하려면 단순히 무시 fitSystemWindows당신에 ScrimLayout.

@Override
protected boolean fitSystemWindows(Rect insets) {
    mInsets = new Rect(insets);
    return true;
}

나중에 재정 의하여 onDraw반투명 직사각형을 그립니다.

예제 구현은 구글 IO 응용 프로그램 소스에서 찾을 수 있습니다.
여기 에서 레이아웃 xml에서 어떻게 사용되는지 볼 수 있습니다.


답변

원하는 경우 탐색 패널이 상태 표시 줄 위에 있고 상태 표시 줄 위에 반투명합니다. Google I / O Android App Source 는 좋은 솔루션을 제공합니다 ( Play 스토어의 APK는 최신 버전으로 업데이트되지 않음).

먼저 ScrimInsetFrameLayout 이 필요합니다 .

/*
* Copyright 2014 Google Inc.
*
* 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.
*/

/**
* A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
* (status and navigation bars, overlay action bars).
*/
public class ScrimInsetsFrameLayout extends FrameLayout {
    private Drawable mInsetForeground;

    private Rect mInsets;
    private Rect mTempRect = new Rect();
    private OnInsetsCallback mOnInsetsCallback;

    public ScrimInsetsFrameLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ScrimInsetsView, defStyle, 0);
        if (a == null) {
            return;
        }
        mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground);
        a.recycle();

        setWillNotDraw(true);
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        mInsets = new Rect(insets);
        setWillNotDraw(mInsetForeground == null);
        ViewCompat.postInvalidateOnAnimation(this);
        if (mOnInsetsCallback != null) {
            mOnInsetsCallback.onInsetsChanged(insets);
        }
        return true; // consume insets
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        int width = getWidth();
        int height = getHeight();
        if (mInsets != null && mInsetForeground != null) {
            int sc = canvas.save();
            canvas.translate(getScrollX(), getScrollY());

            // Top
            mTempRect.set(0, 0, width, mInsets.top);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Bottom
            mTempRect.set(0, height - mInsets.bottom, width, height);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Left
            mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Right
            mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            canvas.restoreToCount(sc);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(this);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(null);
        }
    }

    /**
     * Allows the calling container to specify a callback for custom processing when insets change (i.e. when
     * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
     * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
     * clipToPadding to false.
     */
    public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
        mOnInsetsCallback = onInsetsCallback;
    }

    public static interface OnInsetsCallback {
        public void onInsetsChanged(Rect insets);
    }
}

그런 다음 XML 레이아웃에서이 부분을 변경하십시오.

<LinearLayout android:id="@+id/linearLayout"
    android:layout_width="304dp"
    android:layout_height="match_parent"
    android:layout_gravity="left|start"
    android:fitsSystemWindows="true"
    android:background="#ffffff">
    <ListView android:id="@+id/left_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"></ListView>
</LinearLayout>

LinearLayout을 ScrimInsetFrameLayout으로 변경하십시오.

<com.boardy.util.ScrimInsetFrameLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearLayout"
    android:layout_width="304dp"
    android:layout_height="match_parent"
    android:layout_gravity="left|start"
    android:fitsSystemWindows="true"
    app:insetForeground="#4000">
    <ListView android:id="@+id/left_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"></ListView>
</com.boardy.util.ScrimInsetFrameLayout>


답변

내 프로젝트에서 구현할 유사한 기능이 있습니다. 그리고 내 서랍을 투명하게 만들기 위해 16 진수 색상에 투명도를 사용합니다 . 6 개의 16 진수를 사용하면 빨강, 녹색 및 파랑의 각 값에 대해 각각 2 개의 16 진수가 있습니다. 하지만 추가로 두 자리 (8 자리 16 진수)를 입력하면 ARGB (알파 값의 경우 두 자리) ( 여기를보세요 )를 갖게 됩니다.

16 진수 불투명도 값은 다음과 같습니다. 2 자리 추가

100%  FF
95%  F2
90%  E6
85%  D9
80%  CC
75%  BF
70%  B3
65%  A6
60%  99
55%  8C
50%  80
45%  73
40%  66
35%  59
30%  4D
25%  40
20%  33
15%  26
10%  1A
5%  0D
0%  00

예를 들어, 16 진수 색상 (# 111111)이있는 경우 불투명도 값 중 하나를 입력하면 투명도를 얻을 수 있습니다. 이렇게 : (# 11111100)

내 서랍은 (당신과 같은) 액션 바를 덮지 않지만 이러한 경우에도 투명성을 적용 할 수 있습니다. 내 코드는 다음과 같습니다.

     <ListView
          android:id="@+id/left_drawer"
          android:layout_width="240dp"
          android:layout_height="match_parent"
          android:layout_gravity="start"
          android:background="#11111100"
          android:choiceMode="singleChoice"
          android:divider="@android:color/transparent"
          android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>

그리고 여기 에 16 진 색상의 알파 코드를 이해하는 데 도움 이되는 또 다른 기사 가 있습니다.