美文网首页android
Android自定义未读消息提示View

Android自定义未读消息提示View

作者: Anieal | 来源:发表于2017-08-23 08:10 被阅读768次

先上图

未读消息View

介绍

1.可根据文本长度动态改变view的宽度,数字10以下的显示为圆形,10以上的显示为上述效果
2.使用方便,引用到xml中后,直接显示高度即可,即可根据高度自动生成最佳显示效果
3.直接在代码中调用setText()即可

分析

其实完成这样的效果还是很简单的,主要我是通过画一个圆角矩形来实现这样的效果,圆角矩形很轻松就能实现这两种效果的切换,至于怎样子写,之后会有介绍。
关于自适应宽度的实现,我只要是通过重写onMeasure方法,对其进行拦截。

开始实现

实现步骤其实很简单,因为功能上不是很多,对于我现在的需求,只要能显示未读数量并做好适配就好了。所以只要写好onMeasure和onDraw就好了,方法很简单。因为本人实力有限,实现起来肯定还是使用很简单的方法的。

现在我们先看onMeasure,这里主要是是为了做好实现自适应宽度
 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取控件高度
        height = MeasureSpec.getSize(heightMeasureSpec);
        //定义字体大小,自测了一下,与高度相差6dp的字体大小看着还是挺舒服的
        textSize = height - getResources().getDimensionPixelSize(R.dimen.dp6);
        textPaint.setTextSize(textSize);
        //获取文本宽度
        int textWidth = (int) textPaint.measureText(text);
        //区分画圆的是圆形还是圆角矩形
        if (text.length() > 1) {
            roundWidth = textWidth + height - textWidth / text.length();
        } else {
            roundWidth = height;
        }
        //重新测量控件
        setMeasuredDimension(roundWidth, height);
    }

上述方法还是很简单的也标号注释了,不用一句句来讲了。
roundWidth = textWidth + height - textWidth / text.length();实现上述效果的核心就是这段代码,我想应该看得懂的。逻辑不是很强。

现在我们再看onDraw,也是最后一步画矩形与画字
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画矩形
        canvas.setDrawFilter(paintFlagsDrawFilter);
        roundRectF.set(0, 0, roundWidth, height);
        canvas.drawRoundRect(roundRectF, height / 2, height / 2, roundRectPaint);

        //画字
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float top = fontMetrics.top;
        float bottom = fontMetrics.bottom;
        int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);
        canvas.drawText(text, roundRectF.centerX(), baseLintY, textPaint);
    }

对于画矩形和画字不是这篇的重点,不懂的可以自己百度一下,我也是百度慢慢学起来的。主要是画字需要居中,关键在于int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);这边代码,获取字体的基线,来实现居中效果。

最后上所有代码,不是很难,代码量也不多,很容易懂

package com.demo.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.demo.R;

public class MyTextView extends View {

    private Paint roundRectPaint;
    private RectF roundRectF;
    private int height;
    private int roundWidth;

    private Paint textPaint;
    private float textSize;
    private String text;
    private PaintFlagsDrawFilter paintFlagsDrawFilter;

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

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    private void initView() {
        text = "2";
        roundRectPaint = new Paint();
        roundRectPaint.setStyle(Paint.Style.FILL);
        roundRectPaint.setAntiAlias(true);
        roundRectPaint.setColor(Color.RED);
        roundRectF = new RectF();

        //设置字体为粗体
        textPaint = new Paint(Paint.LINEAR_TEXT_FLAG);
        textPaint.setColor(Color.WHITE);
        textPaint.setAntiAlias(true);
        textPaint.setTextAlign(Paint.Align.CENTER);
        //实现抗锯齿
        paintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取控件高度
        height = MeasureSpec.getSize(heightMeasureSpec);
        //定义字体大小,自测了一下,与高度相差6dp的字体大小看着还是挺舒服的
        textSize = height - getResources().getDimensionPixelSize(R.dimen.dp6);
        textPaint.setTextSize(textSize);
        //获取文本宽度
        int textWidth = (int) textPaint.measureText(text);
        //区分画圆的是圆形还是圆角矩形
        if (text.length() > 1) {
            roundWidth = textWidth + height - textWidth / text.length();
        } else {
            roundWidth = height;
        }
        //重新测量控件
        setMeasuredDimension(roundWidth, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画矩形
        canvas.setDrawFilter(paintFlagsDrawFilter);
        roundRectF.set(0, 0, roundWidth, height);
        canvas.drawRoundRect(roundRectF, height / 2, height / 2, roundRectPaint);

        //画字
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float top = fontMetrics.top;
        float bottom = fontMetrics.bottom;
        int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);
        canvas.drawText(text, roundRectF.centerX(), baseLintY, textPaint);
    }

    public void setText(String text) {
        this.text = text;
        //重走onMeasure
        requestLayout();
    }
}

代码真的很少,看不懂的查一下也很快能看懂的。
最后在xml中

<com.demo.view.MyTextView
        android:layout_marginTop="20dp"
        android:layout_marginLeft="20dp"
        android:layout_width="wrap_content"
        android:layout_height="30dp"/>

好了,就这样结束了,这里android:layout_width不管设什么值都是自适应的,因为在onMeasure中直接定死了。若要区分开来,可重写onMeasure做判断。

相关文章

网友评论

  • 琛宝老爸:请问,能不能扩展一下接口呢?
    比如动态设置字体大小、颜色、背景的颜色、形状等。
    谢谢!

本文标题:Android自定义未读消息提示View

本文链接:https://www.haomeiwen.com/subject/fsmldxtx.html