介紹一個顯示紅點,及數字氣泡的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>
複製代碼
相關文章
相關標籤/搜索