【问题标题】:Blur background of Navigation Drawer导航抽屉背景模糊
【发布时间】:2014-09-05 14:35:29
【问题描述】:

我将如何在导航抽屉上创建实时模糊,所以当你拉出抽屉时,列表的背景是它后面显示的片段的模糊背景?

我看过,但主要是发现位图模糊,没有任何实时的。

【问题讨论】:

  • 你真的想模糊背景而不只是让它半透明吗?模糊是一项昂贵的操作,并且在没有技巧的情况下即时进行可能成本太高!
  • 你能创建一个透明的.png图像,上面有一些模糊吗?然后将抽屉背景设置为等于那个?
  • 您不能使用模糊 .png,因为要创建模糊,它需要对图像进行采样然后模糊

标签: android blur navigation-drawer


【解决方案1】:

该过程涉及以下阶段:

  1. 获取整个抽屉布局的快照。
  2. 将其裁剪为您的菜单的确切大小。
  3. 将其缩小很多(8 倍非常好)。
  4. 模糊该图像。
  5. 拥有一个自定义视图,可在您的菜单出现位置的正后方显示部分图像。
  6. 当您滑动抽屉时,会显示该图像的较大部分。

这是一个代码示例(全部在 BlurActionBarDrawerToggle 和 BlurAndDimView 中完成):

public class BlurActionBarDrawerToggle extends ActionBarDrawerToggle {

    private static final int DOWNSAMPLING = 8;

    private final DrawerLayout drawerLayout;
    private final BlurAndDimView blurrer;
    private Bitmap drawerSnapshot;
    private final ColorDrawable imageBackgroundDrawable;

    public BlurActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes, BlurAndDimView blurrer) {
        super(activity, drawerLayout, drawerImageRes, openDrawerContentDescRes, closeDrawerContentDescRes);

        //this should be roughly the same color as your window background
        imageBackgroundDrawable = new ColorDrawable(activity.getResources().getColor(R.color.dark_blue_2));
        this.drawerLayout = drawerLayout;
        this.blurrer = blurrer;
    }

    @Override
    public void onDrawerSlide(final View drawerView, final float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
        if (slideOffset > 0.0f) {
            setBlurAlpha(slideOffset);
        } else {
            clearBlurImage();
        }
    }

    @Override
    public void onDrawerClosed(View view) {
        clearBlurImage();
    }

    private void setBlurAlpha(float slideOffset) {
        if (!blurrer.hasImage()) {
            setBlurImage();
        }
        blurrer.handleScroll(slideOffset);
    }

    public void setBlurImage() {
        blurrer.setVisibility(View.VISIBLE);
        drawerSnapshot = drawViewToBitmap(drawerSnapshot, drawerLayout, DOWNSAMPLING, imageBackgroundDrawable);
        blurrer.setImage(drawerSnapshot, DOWNSAMPLING);
    }

    public void clearBlurImage() {
        blurrer.clearImage();
        blurrer.setVisibility(View.INVISIBLE);
    }

    private Bitmap drawViewToBitmap(Bitmap dest, View view, int downSampling, Drawable background) {
        float scale = 1f / downSampling;
        int viewWidth = view.getWidth();
        int viewHeight = view.getHeight();
        int bmpWidth = (int) (viewWidth * scale);
        int bmpHeight = (int) (viewHeight * scale);
        if (dest == null || dest.getWidth() != bmpWidth || dest.getHeight() != bmpHeight) {
            dest = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
        }
        Canvas c = new Canvas(dest);
        background.setBounds(new Rect(0, 0, viewWidth, viewHeight));
        background.draw(c);
        if (downSampling > 1) {
            c.scale(scale, scale);
        }

        view.draw(c);
        view.layout(0, 0, viewWidth, viewHeight);
        return dest;
    }
}

BlurAndDim 视图模糊菜单下方的部分,并使其余部分变暗(您可以调整数字以获得所需的确切效果):

public class BlurAndDimView extends View {

    private static final int BLUR_RADIUS = 4;
    private static final int BLUE_ALPHA = 178;
    private static final int MAX_DIM_ALPHA = 127;
    private Paint bitmapPaint;
    private Paint dimPaint;
    private Paint blueSemiTransparentPaint;
    private int menuWidth;
    private int titleHeight;

    private Bitmap image;
    private Rect rectDst;
    private Rect rectSrc;
    private int downSampling;
    private Rect rectRest;

    public BlurAndDimView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        postConstruct();
    }

    public BlurAndDimView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        postConstruct();
    }

    public BlurAndDimView(Context context) {
        this(context, null);
        postConstruct();
    }

    private void postConstruct() {
        bitmapPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        dimPaint = new Paint();
        blueSemiTransparentPaint = new Paint();
        //You might want to also have a semitransparent overlay over your blurred image, since you can't control what's behind your menu.
        blueSemiTransparentPaint.setColor(getResources().getColor(R.color.dark_blue));
        blueSemiTransparentPaint.setAlpha(BLUE_ALPHA);
        menuWidth = getResources().getDimensionPixelSize(R.dimen.browse_menu_width);
    }
}

    @Override
    protected void onDraw(Canvas canvas) {
        if (image != null) {
            canvas.drawBitmap(image, rectSrc, rectDst, bitmapPaint);
            canvas.drawRect(rectDst, blueSemiTransparentPaint);
            canvas.drawRect(rectRest, dimPaint);
        }
    }

    public void handleScroll(float xOffset) {
        if(image != null) {
            rectSrc.right = (int) (image.getWidth() * xOffset);
            rectDst.right = rectSrc.right * downSampling;
            rectRest.left = rectDst.right;
            dimPaint.setAlpha((int) (xOffset * MAX_DIM_ALPHA));
            invalidate();
        }
    }

    public void setImage(Bitmap bmp, int downSampling) {
        Bitmap cropped = Bitmap.createBitmap(bmp, 0, 0, menuWidth / downSampling, getHeight() / downSampling);
        this.image = Blur.blur(getContext(), cropped, BLUR_RADIUS);
        rectSrc = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
        rectDst = new Rect(0, 0, menuWidth, getHeight());
        rectRest = new Rect(menuWidth, 0, getWidth(), getHeight());
        this.downSampling = downSampling;
        invalidate();
    }

    public boolean hasImage() {
        return image != null;
    }

    public void clearImage() {
        image = null;
    }
}

对于良好的模糊算法(尽可能使用 Renderscript),您可以使用this

布局应该是这样的:

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.widget.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.bla.bla.BlurAndDimView
        android:id="@+id/blurrer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?android:attr/actionBarSize"
        android:visibility="invisible" />

    <ListView
        android:id="@+id/menu_list"
        android:layout_width="@dimen/browse_menu_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice" />
</android.support.v4.widget.DrawerLayout>

【讨论】:

  • 请记住,根据您进行的缩小/模糊程度,在某些设备上这可能需要超过 40-50 毫秒的时间。但是,如果你坚持我给出的数字,你应该可以在大多数情况下毫无问题地使用它。
  • 我试过这个。但无法显示抽屉。我如何从 MainActivity 使用它(打开抽屉)?
  • 你从哪里得到“Blur.blur”你能指定你使用的库或类吗?谢谢
  • 如何在从右侧打开的导航抽屉中使用它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-10
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
相关资源
最近更新 更多