功能介绍
- 支持只显示一个红点
- 内部支持当数字为0时直接隐藏自身
- 支持当数字为1-9时气泡背景为圆形,当数字为10-99时气泡背景为椭圆
- 支持当数字超过99时显示...形式
- 支持此view中心显示为 其他View右上角的指定位置
配置支持
- 支持配置红点及数字气泡颜色
- 支持配置数字气泡数字的颜色大小
- 支持配置气泡及红点外面圆环的颜色圆环粗细
使用方法简介
xml中的使用
- xml中代码示例
<com.k.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"
/>
-
xml中配置介绍
1.dotColor 显示圆点时是圆点的颜色,显示数字气泡时是数字气泡的颜色 2.dotHeight 显示数字气泡的的高度 3.dotTextColor 数字气泡中数字的颜色 4.dotTextSize 数字气泡中文字的size 5.dotDiameter 圆点的直径 6.dotShowRing 布尔类型 是否显示外圈圆环 7.dotRingColor 外圈圆环的颜色 8.dotRingWidth 外圈圆环的粗细、
java代码中的使用
- 此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.使用说明
- 设置气泡显示的数量。 为0时view自动会gone,为1-99时显示消息气泡及具体数字。设置为超过99时为显示···
- 设置只显示红点模式。 此模式(onlyDot=true)只显示一个小红点,里面不包含数字。
- 设置一个相对view,此方法提供一个默认偏移量。onlyDot(红点)模式下红点中心相对于此view右上角坐标 向左偏移5dp向下偏移5dp,气泡模式下气泡中心相对于此view向左偏移6dp,向下偏移7dp
- 设置指定view自定义偏移量的方法。此方法提供偏移量的自定义。onlyDot(红点)模式下红点中心相对于此view右上角坐标 向左偏移xdp向下偏移ydp,气泡模式下气泡中心相对于此view向左偏移x1dp,向下偏移y1dp
注意事项
由于此view在定位到指定view的右上角时有特殊要求,所以此view和指定view需要在同一个parent布局中。
显示效果
- 只显示一个红点
- 显示单个数字
- 显示多个数字
- 显示超过99的数字
控件源码 kotlin编写
package com.k.android.view
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import com.k.android.R
import com.k.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文件中即可
<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>