介绍一个显示红点,及数字气泡的view

功能介绍

  1. 支持只显示一个红点
  2. 内部支持当数字为0时直接隐藏自身
  3. 支持当数字为1-9时气泡背景为圆形,当数字为10-99时气泡背景为椭圆
  4. 支持当数字超过99时显示...形式
  5. 支持此view中心显示为 其余View右上角的指定位置

配置支持

  1. 支持配置红点及数字气泡颜色
  2. 支持配置数字气泡数字的颜色大小
  3. 支持配置气泡及红点外面圆环的颜色圆环粗细

使用方法简介

xml中的使用

  1. xml中代码示例
<com.koolearn.android.view.RedDotView
        android:id="@+id/unread_cover"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:dotColor="@color/c_fa5740"
        app:dotHeight="@dimen/x14"
        app:dotTextColor="@color/white"
        app:dotTextSize="8sp"
        app:dotDiameter="@dimen/x10"
        app:dotShowRing="true"
        app:dotRingColor="@color/white"
        app:dotRingWidth="@dimen/x5"
        />
复制代码
  1. xml中配置介绍java

    1.dotColor 显示圆点时是圆点的颜色,显示数字气泡时是数字气泡的颜色
     2.dotHeight 显示数字气泡的的高度
     3.dotTextColor 数字气泡中数字的颜色
     4.dotTextSize 数字气泡中文字的size
     5.dotDiameter 圆点的直径
     6.dotShowRing 布尔类型 是否显示外圈圆环
     7.dotRingColor 外圈圆环的颜色
     8.dotRingWidth 外圈圆环的粗细、
    复制代码

java代码中的使用

  1. 此view在使用时对外界提供以下方法:
1) fun setText(text:Int)
    2) fun setOnlyDotMode(onlyDot:Boolean)
    3) fun setOffset(view:View)
    4) fun setOffset(view:View,x:Int,y:Int,x1:Int,y1:Int)
复制代码

2.使用说明android

  1. 设置气泡显示的数量。 为0时view自动会gone,为1-99时显示消息气泡及具体数字。设置为超过99时为显示···
  2. 设置只显示红点模式。 此模式(onlyDot=true)只显示一个小红点,里面不包含数字。
  3. 设置一个相对view,此方法提供一个默认偏移量。onlyDot(红点)模式下红点中心相对于此view右上角坐标 向左偏移5dp向下偏移5dp,气泡模式下气泡中心相对于此view向左偏移6dp,向下偏移7dp
  4. 设置指定view自定义偏移量的方法。此方法提供偏移量的自定义。onlyDot(红点)模式下红点中心相对于此view右上角坐标 向左偏移xdp向下偏移ydp,气泡模式下气泡中心相对于此view向左偏移x1dp,向下偏移y1dp

注意事项

因为此view在定位到指定view的右上角时有特殊要求,因此此view和指定view须要在同一个parent布局中。
复制代码

显示效果

  1. 只显示一个红点

  1. 显示单个数字

  1. 显示多个数字

  1. 显示超过99的数字

控件源码 kotlin编写

package com.koolearn.android.view

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import com.koolearn.android.R
import com.koolearn.android.utils.Utils

class RedDotView(context: Context, attr: AttributeSet) : View(context,attr),IRedDotView {
    private val threeDot:String="···"
    private var attrBean = DotViewAttr(context,attr)
    private var mOnlyDot:Boolean=false
    private var mText:Int=0
    private var paint = Paint()//画笔
    private val rect= Rect()//计算文字宽高的矩形

    private var textWidth  = 0
    private var textHeight = 0

    private var viewWidth = 0
    private var viewHeight = 0

    private var widthOffSet = 0 //文字在x轴上的偏移量,为负表示向左移动。由于数字1在圆点放在中心时显示过于靠右,因此设置此字段。让数字1时能在中心
    override fun draw(canvas: Canvas?) {
        super.draw(canvas)
        if (visibility==GONE){
            return
        }
        paint.isAntiAlias=true//设置抗锯齿
        if(mOnlyDot){//只画一个圆点   半径的一半为中心点
            paint.color = attrBean.dotColor
            if(attrBean.dotShowRing){
                paint.color=attrBean.dotRingColor
                canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,attrBean.dotDiameter.toFloat()/2,paint)
                paint.color=attrBean.dotColor
                canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,attrBean.dotDiameter.toFloat()/2-attrBean.dotRingWidth,paint)
            }else{
                paint.color=attrBean.dotColor
                canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,attrBean.dotDiameter.toFloat()/2,paint)
            }
        }else{
            if(mText==0){//等于0不显示此view因此不执行任何代码
                visibility = GONE
                return
            }
            if(mText in 1..9){//画圆
                //画圆
                if(attrBean.dotShowRing){
                    paint.color=attrBean.dotRingColor
                    canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,viewHeight.toFloat()/2,paint)
                    paint.color=attrBean.dotColor
                    canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,viewHeight.toFloat()/2-attrBean.dotRingWidth,paint)
                }else{
                    paint.color=attrBean.dotColor
                    canvas?.drawCircle(viewWidth.toFloat()/2,viewHeight.toFloat()/2,viewHeight.toFloat()/2,paint)
                }
                //写字
                paint.color = attrBean.dotTextColor
                paint.textSize = attrBean.dotTextSize.toFloat()
                canvas?.drawText(mText.toString(),(viewWidth-textWidth).toFloat()/2+widthOffSet,(viewHeight+textHeight).toFloat()/2-1,paint)
            }else{//画圆角矩形
                //计算文字宽高
                //画圆角矩形
                if(attrBean.dotShowRing){
                    paint.color = attrBean.dotRingColor
                    val oval = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())// 设置个新的长方形
                    canvas?.drawRoundRect(oval, viewHeight.toFloat()/2, viewHeight.toFloat()/2, paint)//第二个参数是x半径,第三个参数是y半径
                    paint.color = attrBean.dotColor
                    val oval2 = RectF(attrBean.dotRingWidth.toFloat(), attrBean.dotRingWidth.toFloat(), viewWidth.toFloat()-attrBean.dotRingWidth, viewHeight.toFloat()-attrBean.dotRingWidth)// 设置个新的长方形
                    canvas?.drawRoundRect(oval2, viewHeight.toFloat()/2-attrBean.dotRingWidth, viewHeight.toFloat()/2-attrBean.dotRingWidth, paint)//第二个参数是x半径,第三个参数是y半径
                }else{
                    paint.color = attrBean.dotColor
                    val oval = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())// 设置个新的长方形
                    canvas?.drawRoundRect(oval, viewHeight.toFloat()/2, viewHeight.toFloat()/2, paint)//第二个参数是x半径,第三个参数是y半径
                }
                //写字
                paint.color = attrBean.dotTextColor
                paint.textSize = attrBean.dotTextSize.toFloat()
                if(mText>99){
                    canvas?.drawText(threeDot,(viewWidth-textWidth).toFloat()/2-5,(viewHeight+textHeight).toFloat()/2+6,paint)
                }else{
                    canvas?.drawText(mText.toString(),(viewWidth-textWidth).toFloat()/2+widthOffSet,(viewHeight+textHeight).toFloat()/2-1,paint)
                }
            }
        }
    }

    override fun setText(text:Int){
        if (text==0){
            visibility = GONE
        }else{
            visibility = VISIBLE
            if(text==1){
                widthOffSet=-4
            }else{
                widthOffSet=-1
            }
        }
        mText = text
        initWidthAHeight()
        setOnlyDotMode(false)//设置数量时让只是红点模式为false
    }

    private fun initWidthAHeight(){
        paint.textSize = attrBean.dotTextSize.toFloat()
        if(mText>99){
            paint.getTextBounds(threeDot,0,threeDot.length,rect)
        }else{
            paint.getTextBounds(mText.toString(),0,"$mText".length,rect)
        }
        textWidth = rect.width()
        textHeight = rect.height()
        if(mText >9){
            viewWidth = attrBean.dotHeight+textWidth
        }else if(mText in 1..9){
            viewWidth = attrBean.dotHeight
        }
        viewHeight = attrBean.dotHeight
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        initParams()
    }

    override fun setOnlyDotMode(onlyDot:Boolean){
        mOnlyDot = onlyDot
        initParams()
        invalidate()
    }

    /**
     * 默认,
     */
    override fun setOffset(view:View){
        view.viewTreeObserver.addOnGlobalLayoutListener {
            var x=0
            var y=0
            if (mOnlyDot){
                x=Utils.dp2px(-5f)
                y= Utils.dp2px(5f)
            }else{
                x=Utils.dp2px(-6f)
                y=Utils.dp2px(7f)
            }
            setX(view.right.toFloat()-viewWidth/2+x)
            setY(view.top.toFloat()-viewHeight/2+y)
        }
    }

    //特殊定制,首页底部消息显示红点须要
    override fun setOffset(view:View,x:Int,y:Int,x1:Int,y1:Int){
        view.viewTreeObserver.addOnGlobalLayoutListener {
            var w=0
            var h=0
            if (mOnlyDot){
                w=Utils.dp2px(x.toFloat())
                h=Utils.dp2px(y.toFloat())
            }else{
                w=Utils.dp2px(x1.toFloat())
                h=Utils.dp2px(y1.toFloat())
            }
            setX(view.right.toFloat()-viewWidth/2+w)
            setY(view.top.toFloat()-viewHeight/2+h)
        }
    }

    private fun initParams(){
        if(mOnlyDot){
            visibility = VISIBLE
            layoutParams.width = attrBean.dotDiameter
            layoutParams.height = attrBean.dotDiameter
            viewHeight = attrBean.dotDiameter
            viewWidth = attrBean.dotDiameter
        }else{
            if(mText >9){
                layoutParams.width = attrBean.dotHeight+textWidth
                layoutParams.height = attrBean.dotHeight
            }else{
                layoutParams.width = attrBean.dotHeight
                layoutParams.height = attrBean.dotHeight
            }
        }
        requestLayout()
    }
}
class DotViewAttr(context:Context,attrs:AttributeSet){
    val dotColor: Int //绘制的圆圈颜色
    val dotTextSize: Int //绘制的文本颜色
    val dotHeight: Int //绘制的圆环view高度 ,由于宽度是自适应的,因此不须要写
    var dotDiameter:Int=0 //当只显示小红点时绘制的点的直径
    val dotTextColor: Int //绘制的文本的颜色
    val dotShowRing:Boolean //当须要外部显示边时,设置此项为true
    val dotRingColor:Int//要显示边的颜色
    val dotRingWidth:Int//外圆环粗细程度  默认4像素
    init {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.RedDotView)
        dotColor = ta.getColor(R.styleable.RedDotView_dotColor,Color.RED)
        dotTextSize = ta.getDimensionPixelSize(R.styleable.RedDotView_dotTextSize, 15)
        dotDiameter = ta.getDimensionPixelSize(R.styleable.RedDotView_dotDiameter, 10)
        dotHeight = ta.getDimensionPixelSize(R.styleable.RedDotView_dotHeight, 10)
        dotTextColor = ta.getColor(R.styleable.RedDotView_dotTextColor, Color.WHITE)
        dotRingColor = ta.getColor(R.styleable.RedDotView_dotRingColor, Color.WHITE)
        dotShowRing = ta.getBoolean(R.styleable.RedDotView_dotShowRing,false)
        dotRingWidth = ta.getDimensionPixelSize(R.styleable.RedDotView_dotRingWidth,4)
        ta.recycle()
    }
}

/**
 * 红点显示接口,
 */
interface IRedDotView{
    fun setText(text:Int)
    fun setOnlyDotMode(onlyDot:Boolean)
    fun setOffset(view:View)
    fun setOffset(view:View,x:Int,y:Int,x1:Int,y1:Int)
}
复制代码

属性源码

把此段代码直接放到attrs.xml文件中便可canvas

<declare-styleable name="RedDotView">
        <attr name="dotColor" format="color"/>
        <attr name="dotHeight" format="dimension"/>
        <attr name="dotShowRing" format="boolean"/>
        <attr name="dotTextSize"/>
        <attr name="dotRingWidth" format="dimension"/>
        <attr name="dotDiameter" format="dimension"/>
        <attr name="dotTextColor" format="color"/>
        <attr name="dotRingColor" format="color"/>
    </declare-styleable>
复制代码
相关文章
相关标签/搜索