Android 仿微信底部渐变颜色导航栏

2019-01-03  本文已影响10人  wuchao226

运行效果图

preview.gif

完整项目地址

Github:仿微信底部渐变导航栏

顶部标题栏地址

简书:顶部标题栏

自定义View

自定义View命名为 ChangeColorIconWithText,在values目录中创建attr.xml文件并自定义四个属性分别为图标、背景色、底部文本、底部文本大小

 <declare-styleable name="ChangeColorIconWithText">
        <attr name="icon" format="reference"/>
        <attr name="text" format="string"/>
        <attr name="color" format="color"/>
        <attr name="text_size" format="dimension"/>
   </declare-styleable>

ChangeColorIconWithText 类进行绘图操作,并向外提供改变透明度和图标的方法

/**
 * @desciption: 自定义图标和文本颜色渐变 进行绘图操作,并向外提供改变透明度和图标的方法
 */
public class ChangeColorIconWithText extends View {

    private static final String INSTANCE_STATUS = "instance_status";
    private static final String STATUS_ALPHA = "status_alpha";
    /**
     * 图标默认背景色
     */
    private final int DEFAULT_ICON_BACKGROUND_COLOR = 0xFF45C01A;
    /**
     * 图标背景色
     */
    private int mColor = 0xFF45C01A;
    /**
     * 图标
     */
    private Bitmap mIconBitmap;
    /**
     * 图标底部文本
     */
    private String mText = "微信";
    /**
     * 默认字体12sp
     */
    private int mTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
            12, getResources().getDisplayMetrics());
    private Bitmap mBitmap;
    /**
     * 透明度(0.0-1.0)
     */
    private float mAlpha;
    /**
     * 图标绘制区域
     */
    private Rect mIconRect;
    /**
     * 文本绘制区域
     */
    private Rect mTextRect;
    /**
     * 文本画笔
     */
    private Paint mTextPaint;

    public ChangeColorIconWithText(Context context) {
        this(context, null);
    }

    public ChangeColorIconWithText(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ChangeColorIconWithText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ChangeColorIconWithText);
        mColor = typedArray.getColor(R.styleable.ChangeColorIconWithText_color, DEFAULT_ICON_BACKGROUND_COLOR);
        BitmapDrawable bitmapDrawable = (BitmapDrawable) typedArray.getDrawable(R.styleable.ChangeColorIconWithText_icon);
        if (bitmapDrawable != null) {
            mIconBitmap = bitmapDrawable.getBitmap();
        }
        mText = typedArray.getString(R.styleable.ChangeColorIconWithText_text);
        //默认字体大小12sp
        mTextSize = (int) typedArray.getDimension(R.styleable.ChangeColorIconWithText_text_size,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                        12, getResources().getDisplayMetrics()));
        typedArray.recycle();

        init();
    }

    /**
     * 初始化画笔、文本显示范围
     */
    private void init() {
        mTextRect = new Rect();
        mTextPaint = new Paint();
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(mColor);
        //将TextView 的文本放入一个矩形中, 测量TextView的高度和宽度
        mTextPaint.getTextBounds(mText, 0, mText.length(), mTextRect);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制原图标
        canvas.drawBitmap(mIconBitmap, null, mIconRect, null);
        //math.ceil(x)返回大于等于参数x的最小整数,即对浮点数向上取整(math.ceil(8.4)=9)
        int alpha = (int) Math.ceil(255 * mAlpha);
        //内存去准备mBitmap,setAlpha,纯色,xfermode,图标
        setupTargetBitmap(alpha);
        // 1、绘制原文本 ; 2、绘制变色的文本
        drawSourceText(canvas, alpha);
        drawTargetText(canvas, alpha);
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }

    /**
     * 在内存中绘制可变色的Icon
     * 在mBitmap上绘制以mColor颜色为Dst,DST_IN模式下的图标
     *
     * @param alpha Src颜色的透明度
     */
    private void setupTargetBitmap(int alpha) {
        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(mBitmap);

        Paint paint = new Paint();
        paint.setColor(mColor);
        //抗锯齿
        paint.setAntiAlias(true);
        //防抖动
        paint.setDither(true);
        //设置画笔的透明度,取值范围为0~255,数值越小越透明
        paint.setAlpha(alpha);
        //在图标背后先绘制一层mColor颜色的背景
        canvas.drawRect(mIconRect, paint);
        //过度模式
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        paint.setAlpha(255);
        //在mBitmap上绘制以iconBackgroundColor颜色为Dst,DST_IN模式下的图标
        canvas.drawBitmap(mIconBitmap, null, mIconRect, paint);
    }

    /**
     * 绘制默认状态下的字体
     *
     * @param canvas Canvas
     * @param alpha  字体颜色透明度
     */
    private void drawSourceText(Canvas canvas, int alpha) {
        mTextPaint.setColor(0xff333333);
        mTextPaint.setAlpha(255 - alpha);
        int x = getMeasuredWidth() / 2 - mTextRect.width() / 2;
        int y = mIconRect.bottom + mTextRect.height();
        canvas.drawText(mText, x, y, mTextPaint);

    }

    /**
     * 绘制滑动到该标签时的字体
     *
     * @param canvas Canvas
     * @param alpha  字体颜色透明度
     */
    private void drawTargetText(Canvas canvas, int alpha) {
        mTextPaint.setColor(mColor);
        mTextPaint.setAlpha(alpha);
        int x = getMeasuredWidth() / 2 - mTextRect.width() / 2;
        int y = mIconRect.bottom + mTextRect.height();
        canvas.drawText(mText, x, y, mTextPaint);

    }

    /**
     * 保存状态
     *
     * @return Parcelable
     */
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(INSTANCE_STATUS, super.onSaveInstanceState());
        bundle.putFloat(STATUS_ALPHA, mAlpha);
        return bundle;
    }

    /**
     * 恢复状态
     *
     * @param state Parcelable
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            mAlpha = bundle.getFloat(STATUS_ALPHA);
            super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATUS));
            return;
        }
        super.onRestoreInstanceState(state);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //因为图标是正方形且需要居中显示的,所以View的大小去掉padding和文字所占空间后,
        //剩余的空间的宽和高的最小值才是图标的边长
        int iconWidth = Math.min(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom() - mTextRect.height());
        int left = getMeasuredWidth() / 2 - iconWidth / 2;
        int top = getMeasuredHeight() / 2 - (mTextRect.height() + iconWidth) / 2;
        //获取图标的绘制范围
        mIconRect = new Rect(left, top, left + iconWidth, top + iconWidth);
    }

    /**
     * 设置图标透明度并重绘
     *
     * @param alpha 透明度
     */
    public void setIconAlpha(float alpha) {
        this.mAlpha = alpha;
        invalidateView();
    }

    /**
     * 判断当前是否为UI线程,是则直接重绘,否则调用postInvalidate()利用Handler来重绘
     */
    private void invalidateView() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            invalidate();
        } else {
            postInvalidate();
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读