将导航抽屉放置在状态栏下方。

9 浏览
0 Comments

将导航抽屉放置在状态栏下方。

我正在尝试让我的导航抽屉在状态栏下面显示。我已经广泛阅读了关于ScrimInsetsFrameLayout视图的资料,并尝试实现它,但出于某种原因它不会在状态栏下面显示。

以下是我使用/编写的代码。

XML DrawerLayout:


    
        
        
    
    
        
    

ScrimInsetsFrameLayout.java:

package com.andrewq.planets.util;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.andrewq.planets.R;
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);
        }
    }
    public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
        mOnInsetsCallback = onInsetsCallback;
    }
    public interface OnInsetsCallback {
        void onInsetsChanged(Rect insets);
    }
}

最后,这是我用于values-v21的styles.xml:



    

我查看了2014年I/O应用程序的源代码以及这个问题:这里,但我不知道有什么不同。

这是我目前的截图,去掉了状态栏下的抽屉:

Screenshot

除了状态栏下的抽屉,其他都运行得很完美。非常感谢您的帮助!

编辑:

澄清一下,我想要让图像在状态栏下面的地方变成半透明,就像大多数谷歌应用和Google Now一样。

0
0 Comments

问题的出现原因:在旧版本的Android设备中,无法使用状态栏透明的方法。

解决方法:

1. 创建一个新的styles.xml文件,并将其放在style-v19文件夹中。

2. 在styles.xml文件中添加以下代码:


3. 创建一个dimen-v19文件夹,并在其中添加以下代码:

24dp

4. 在ToolBar中使用这个dimen:



以上就是解决问题的方法。

0
0 Comments

问题的出现原因:

想要将导航抽屉放在状态栏下方,需要启用透明状态栏。可以通过样式或代码来实现。另外,还需要在布局中添加顶部的填充。

问题的解决方法:

1. 启用透明状态栏需要至少在API v19上操作,或者为v19+创建一个单独的样式文件。

2. 在样式文件中添加以下代码:


3. 在布局中为抽屉内容和正常视图内容添加24dp的顶部填充。

4. 可以使用ScrimInsetsLayout来实现更好的效果。详细的使用方法可以参考链接:https://stackoverflow.com/a/26932228

5. 如果需要在代码中处理,可以按照以下代码示例进行操作:

if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
    // 启用透明状态栏
    setTranslucentStatusFlag(true);
}
if (Build.VERSION.SDK_INT >= 19) {
    mActivity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
    // 无需透明标志,主题已处理
    setTranslucentStatusFlag(false);
    // 将状态栏颜色设置为透明以去除黑色阴影
    mActivity.getWindow().setStatusBarColor(Color.TRANSPARENT);
}
// 在抽屉内容上添加填充(api v19+设备上的25dp)
mDrawerContentRoot.setPadding(0, mActivity.getResources().getDimensionPixelSize(R.dimen.tool_bar_top_padding), 0, 0);
// 定义statusBar的颜色
mDrawerContentRoot.setInsetForeground(mStatusBarColor);
private void setTranslucentStatusFlag(boolean on) {
    if (Build.VERSION.SDK_INT >= 19) {
        Window win = mActivity.getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        if (on) {
            winParams.flags |= bits;
        } else {
            winParams.flags &= ~bits;
        }
        win.setAttributes(winParams);
    }
}

文章中的其他内容为问题的完整解决方案和相关讨论,不属于问题的原因和解决方法。

0
0 Comments

问题的原因是在状态栏下方放置导航抽屉时出现的布局问题。解决方法是向DrawerLayout添加android:fitsSystemWindows="false"属性。添加android:fitsSystemWindows="false"属性到NavigationView也可以解决该问题。这个方法对我来说很有效。感谢!这个方法很好用。谢谢!这个方法非常简单 🙂 但是为什么这样做会起作用呢?NavigationView的实现中,fitsSystemWindows的默认值是false,所以如果不声明它,它应该默认为false。但为什么必须显式地将其设置为false才能起作用呢?在API19设备上不需要这样做,但对于我来说,在我的27 + 28上起作用。

0