【安卓/Android】自定义控件之小红点消息提醒控件

开头必水,这一次水一个小红点,我是用draw绘制的方式实现。小红点的思路也很简单,就是在开头和结尾绘制两个圆,中间绘制一个矩形(滑稽.jpg)。

 效果大概长这样:

小红点所有效果

分别是:无内容、短内容、长内容。

为了比较直观和方便使用,我做了一个小红点布局控件用来展示,效果大概这样:

   小红点布局

小红点布局控件

实现方式是在左右两边绘制圆,中间绘制矩形,如图:

示意图

本篇我们只展示小红点的核心代码,内容不是很多。

为了减少文本这块的工作量,小红点继承的是 AppCompatTextView。

基本的初始化设置

private void init() {
        //绘制小红点的画笔
        mPaint = new Paint();
        //测量文本内容长度的画笔(拓展内容中会用到)
        mMeasurePaint = new Paint();
        mRect = new Rect();      //绘制矩形
        mRectF = new RectF();    //绘制圆
        //设置抗锯齿
        mPaint.setAntiAlias( true );
        //背景颜色( redDotBackgroundColor色值为:#eb2700 )
        setRedDotBackgroundColor( redDotBackgroundColor );
        //文本内容居中
        setGravity( Gravity.CENTER );
        //只能显示一行
        setMaxLines(1);
    }

重写onDraw方法绘制小红点

这里需要讲的是中间部分(矩形)left参数用高度是因为小红点的宽度会根据内容发生改变。

    @Override
    protected void onDraw(Canvas canvas) {
        //绘制左边的圆
        mRectF.set(0, 0,getHeight(), getHeight());
        canvas.drawOval(mRectF, mPaint);
        //绘制右边的圆
        mRectF.set(getWidth() - getHeight(), 0, getWidth(), getHeight());
        canvas.drawOval(mRectF, mPaint);
        //绘制中间部分
        mRect.set(getHeight() / 2,0, getWidth() - getHeight() / 2, getHeight());
        canvas.drawRect(mRect, mPaint);
        super.onDraw(canvas);
    }

到这里就结束了。但是!既然要水我们就水长一点。上边我们说到了矩形的left由控件的实际高度控制,因为宽度会发生改变。但实际上内容时...

小红点

实际效果

实际效果的小红点

emmmmm好像哪里不对???所以在此基础上我们要在内容改变时重新绘制控件的宽度,这里我用的办法是先测量文本内容的宽度,然后在原有控件的宽度基础上在加上文本宽度。

先测量文本宽度

这里用到之前提到的测量画笔

    /**
     * 获取测量的文本长度
     * @return  文本的实际长度
     */
    public int getMeasureText() {
        mMeasurePaint.setTextSize( getTextSize() );
        return (int) mMeasurePaint.measureText(getText().toString());
    }

 处理改变的宽度

    private int initWidth, redDotMinWidth, redDotMinHeight;

    /**
     * 根据内容改变宽度
     */
    private void doChangeWidth() {
        ViewGroup.LayoutParams lp;
        int len;
        if( initWidth == - 1 ) return;
        lp = getLayoutParams();
        len = getText().length();
        if( len == 0 ) {
            //没有内容时设置为小红点,这里的最小宽高度为:10
            lp.width = redDotMinWidth;
            lp.height = redDotMinHeight;
        }else {
            //短内容:默认宽度(初始化时设置的宽度,接下来的代码片段会说到)
            //长内容:默认宽度 + 测量的文本宽度
            lp.width = len <= 1 ? initWidth : initWidth + getMeasureText();
        }
        setLayoutParams( lp );
    }

最后我们重写dispatchDraw()方法调用doChangeWidth()

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        //先记录最开始设置的宽度,短内容时还原原始宽度
        if( initWidth == -1 && getWidth() != 0 ) initWidth = getWidth();
        //根据内容改变宽度
        doChangeWidth();
    }

上述一顿操作后基本上就解决了宽度不改变的问题。 

最后!完整代码在我的码云仓库里边,因为后期进行了迭代,代码量稍微有点多,需要的可以去看看。

疯狂暗示
疯狂暗示!!!

猜你喜欢

转载自blog.csdn.net/u013599928/article/details/98393311
今日推荐