Android 沉浸式DrawerLayout(抽屉布局)案例

演示

《Android 沉浸式DrawerLayout(抽屉布局)案例》 device-2018-07-23-211847.gif

https://github.com/Mr-Cai/Drawer

实现步骤

  • 布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v4.widget.DrawerLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--主页面-->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#0ff"
            android:gravity="center"
            android:text="@string/app_name"
            android:textColor="#fff"
            android:textSize="50sp" />
        <!--左侧菜单-->
        <!--layout_gravity控制菜单显示的侧面位置-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="@color/colorPrimary"
            android:fitsSystemWindows="true"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/lift_menu" />
            <!--fitsSystemWindows控制布局在沉浸状态时保持内容在状态栏以下-->
            <com.example.m.draw.RoundImage
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/a" />
        </LinearLayout>

        <!--右侧菜单-->
        <!--如果是两个抽屉那么layout_gravity属性值不能相同,即一左一右-->
        <!--现在fitsSystemWindow属性并没有解决右侧菜单初始控件与状态栏重叠问题-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="end"
            android:background="@color/colorAccent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/right_menu"
                android:textColor="#fff" />
        </LinearLayout>

    </android.support.v4.widget.DrawerLayout>
</android.support.constraint.ConstraintLayout>
  • 沉浸式配置
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        window.statusBarColor = Color.TRANSPARENT
    }

圆角图片

  • 自定义圆角属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundImage">
        <attr name="borderRadius" format="dimension"/>
        <attr name="type">
            <enum name="circle" value="0"/>
            <enum name="round" value="1"/>
        </attr>
    </declare-styleable>
</resources>
  • kotlin文件
package com.example.m.draw

import android.content.Context
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Parcelable
import android.support.v7.widget.AppCompatImageView
import android.util.AttributeSet
import android.util.TypedValue
import android.util.TypedValue.COMPLEX_UNIT_DIP

class RoundImage(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) {
    private var mImgType: Int = 0//图片类型
    private var mBorderRadius: Int = 0//圆角大小
    private val mBitmapPaint: Paint = Paint()//绘图画笔
    private var mRadius: Int = 0//圆角半径
    private val mMatrix: Matrix = Matrix()//缩放3x3矩阵
    private var mBitmapShader: BitmapShader? = null//渲染图像颜色
    private var mWidth: Int = 0//图像宽度
    private var mRoundRect: RectF? = null//圆角矩形

    companion object {
        const val TYPE_CIRCLE = 0//圆形图片
        const val TYPE_ROUND = 1//圆角图片
        const val BORDER_RADIUS_DEFAULT = 10//圆角图片
        const val STATE_INSTANCE = "STATE_INSTANCE"
        const val STATE_TYPE = "STATE_TYPE"
        const val STATE_BORDER_RADIUS = "STATE_BORDER_RADIUS"
    }

    init {
        mBitmapPaint.isAntiAlias = true
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImage)
        mBorderRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImage_borderRadius,
                TypedValue.applyDimension(COMPLEX_UNIT_DIP, BORDER_RADIUS_DEFAULT.toFloat(),
                        resources.displayMetrics).toInt())
        mImgType = typedArray.getInt(R.styleable.RoundImage_type, TYPE_CIRCLE)//默认圆形图片
        typedArray.recycle()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (mImgType == TYPE_CIRCLE) {//如果改变图片类型为圆形,则强制图片宽高一致
            mWidth = Math.min(measuredWidth, measuredHeight)
            mRadius = mWidth / 2
            setMeasuredDimension(mWidth, mWidth)
        }
    }

    private fun setUpShader() {//设置渲染着色
        val drawable = drawable ?: return
        val bitmap = drawableToBitmap(drawable)//指定区域内绘制着色的位图
        mBitmapShader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        var scale = 1.0f
        if (mImgType == TYPE_CIRCLE) {
            val bitmapSize = Math.min(bitmap.width, bitmap.height)
            scale = mWidth * 1.0f / bitmapSize
        } else if (mImgType == TYPE_ROUND) {//如果图片宽高与自定义控件宽高不匹配,则计算缩放比例
            scale = Math.max(width * 1.0f / bitmap.width,
                    height * 1.0f / bitmap.height)
        }
        mMatrix.setScale(scale, scale)//缩放矩阵
        mBitmapShader!!.setLocalMatrix(mMatrix)//变换矩阵
        mBitmapPaint.shader = mBitmapShader//设置渲染器
    }

    private fun drawableToBitmap(drawable: Drawable): Bitmap {
        if (drawable is BitmapDrawable) {
            return drawable.bitmap
        }
        val width = drawable.intrinsicWidth
        val height = drawable.intrinsicHeight
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, width, height)
        drawable.draw(canvas)
        return bitmap
    }

    override fun onDraw(canvas: Canvas) {
        setUpShader()
        if (mImgType == TYPE_CIRCLE) {
            canvas.drawCircle(mRadius.toFloat(), mRadius.toFloat(),
                    mRadius.toFloat(), mBitmapPaint)
        } else {
            canvas.drawRoundRect(mRoundRect, mBorderRadius.toFloat(),
                    mBorderRadius.toFloat(), mBitmapPaint)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) {
        super.onSizeChanged(w, h, oldW, oldH)
        if (mImgType == TYPE_ROUND) {
            mRoundRect = RectF(0f, 0f, width.toFloat(), height.toFloat())
        }
    }

    override fun onSaveInstanceState(): Parcelable? {
        val bundle = Bundle()
        bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState())
        bundle.putInt(STATE_TYPE, mImgType)
        bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius)
        return bundle
    }

    override fun onRestoreInstanceState(state: Parcelable) {
        if (state is Bundle) {
            super.onRestoreInstanceState(state.getParcelable(STATE_INSTANCE))
            mImgType = state.getInt(STATE_TYPE)
            mBorderRadius = state.getInt(STATE_BORDER_RADIUS)
        } else {
            super.onRestoreInstanceState(state)
        }
    }
}

坑点:

  • 正常情况下,沉浸状态下状态栏是透明的,和布局融为一体,且布局内容和状态栏有界限.
    现在将fitSystemWindow(贴合窗口)属性写在根布局就造成了灰色状态栏

    《Android 沉浸式DrawerLayout(抽屉布局)案例》 图片.png

  • layout_gravity属性未设置,造成抽屉覆盖主页面

    《Android 沉浸式DrawerLayout(抽屉布局)案例》 device-2018-07-23-214104.png

  • layout_gravity属性相同时报错
    解决: 一左一右
IllegalStateException: Child drawer has absolute gravity LEFT 
but this DrawerLayout already has a drawer view along that edge
非法状态异常:子抽屉有了绝对向左的重力,但这个抽屉布局在边缘已有抽屉控件
    原文作者:蔡凯歌
    原文地址: https://www.jianshu.com/p/5ae3d9555853
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞