效果图:
自定义角标控件:
package com.example.mytest.widget
import android.content.Context
import android.graphics.Color
import android.graphics.RectF
import android.graphics.Typeface
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateInterpolator
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.animation.DecelerateInterpolator
import android.widget.FrameLayout
import android.widget.TabWidget
class BadgeView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyle: Int = 16842884,
target: View? = null,
tabIndex: Int = 0
) :
androidx.appcompat.widget.AppCompatTextView(context!!, attrs, defStyle) {
private var context: Context? = null
var target: View? = null
private set
var badgePosition = 0
var horizontalBadgeMargin = 0
private set
var verticalBadgeMargin = 0
private set
private var badgeColor = 0
private var isShown = false
private var badgeBg: ShapeDrawable? = null
private var targetTabIndex = 0
constructor(context: Context?, target: View?) : this(
context,
null as AttributeSet?,
16842884,
target,
0
) {
}
constructor(context: Context?, target: TabWidget?, index: Int) : this(
context,
null as AttributeSet?,
16842884,
target,
index
) {
}
init {
init(context, target, tabIndex)
}
private fun init(context: Context?, target: View?, tabIndex: Int) {
this.context = context
this.target = target
targetTabIndex = tabIndex
badgePosition = 2
horizontalBadgeMargin = dipToPixels(5)
verticalBadgeMargin = horizontalBadgeMargin
badgeColor = DEFAULT_BADGE_COLOR
this.typeface = Typeface.DEFAULT_BOLD
val paddingPixels = dipToPixels(5)
setPadding(paddingPixels, 0, paddingPixels, 0)
this.setTextColor(-1)
fadeIn = AlphaAnimation(0.0f, 1.0f)
fadeIn!!.setInterpolator(DecelerateInterpolator())
fadeIn!!.setDuration(200L)
fadeOut = AlphaAnimation(1.0f, 0.0f)
fadeOut!!.setInterpolator(AccelerateInterpolator())
fadeOut!!.setDuration(200L)
isShown = false
if (this.target != null) {
applyTo(this.target)
} else {
this.show()
}
}
private fun applyTo(target: View?) {
var target = target
val lp = target!!.layoutParams
val parent = target.parent
val container = FrameLayout(context!!)
if (target is TabWidget) {
target = target.getChildTabViewAt(targetTabIndex)
this.target = target
(target as ViewGroup?)!!.addView(container, ViewGroup.LayoutParams(-1, -1))
this.visibility = GONE
container.addView(this)
} else {
val group = parent as ViewGroup
val index = group.indexOfChild(target)
group.removeView(target)
group.addView(container, index, lp)
container.addView(target)
this.visibility = GONE
container.addView(this)
group.invalidate()
}
}
fun show() {
this.show(false, null as Animation?)
}
fun show(animate: Boolean) {
this.show(animate, fadeIn)
}
fun show(anim: Animation?) {
this.show(true, anim)
}
fun hide() {
this.hide(false, null as Animation?)
}
fun hide(animate: Boolean) {
this.hide(animate, fadeOut)
}
fun hide(anim: Animation?) {
this.hide(true, anim)
}
fun toggle() {
this.toggle(false, null as Animation?, null as Animation?)
}
fun toggle(animate: Boolean) {
this.toggle(animate, fadeIn, fadeOut)
}
fun toggle(animIn: Animation?, animOut: Animation?) {
this.toggle(true, animIn, animOut)
}
private fun show(animate: Boolean, anim: Animation?) {
if (this.background == null) {
if (badgeBg == null) {
badgeBg = defaultBackground
}
setBackgroundDrawable(badgeBg)
}
applyLayoutParams()
if (animate) {
startAnimation(anim)
}
this.visibility = VISIBLE
isShown = true
}
private fun hide(animate: Boolean, anim: Animation?) {
this.visibility = GONE
if (animate) {
startAnimation(anim)
}
isShown = false
}
private fun toggle(animate: Boolean, animIn: Animation?, animOut: Animation?) {
if (isShown) {
this.hide(animate && animOut != null, animOut)
} else {
this.show(animate && animIn != null, animIn)
}
}
fun increment(offset: Int): Int {
val txt = this.text
var i: Int
i = if (txt != null) {
try {
txt.toString().toInt()
} catch (var5: NumberFormatException) {
0
}
} else {
0
}
i += offset
this.text = i.toString()
return i
}
fun decrement(offset: Int): Int {
return increment(-offset)
}
private val defaultBackground: ShapeDrawable
private get() {
val r = dipToPixels(8)
val outerR = floatArrayOf(
r.toFloat(),
r.toFloat(),
r.toFloat(),
r.toFloat(),
r.toFloat(),
r.toFloat(),
r.toFloat(),
r.toFloat()
)
val rr = RoundRectShape(outerR, null as RectF?, null as FloatArray?)
val drawable = ShapeDrawable(rr)
drawable.paint.color = badgeColor
return drawable
}
private fun applyLayoutParams() {
val lp = FrameLayout.LayoutParams(-2, -2)
when (badgePosition) {
1 -> {
lp.gravity = 51
lp.setMargins(horizontalBadgeMargin, verticalBadgeMargin, 0, 0)
}
2 -> {
lp.gravity = 53
lp.setMargins(0, verticalBadgeMargin, horizontalBadgeMargin, 0)
}
3 -> {
lp.gravity = 83
lp.setMargins(horizontalBadgeMargin, 0, 0, verticalBadgeMargin)
}
4 -> {
lp.gravity = 85
lp.setMargins(0, 0, horizontalBadgeMargin, verticalBadgeMargin)
}
5 -> {
lp.gravity = 17
lp.setMargins(0, 0, 0, 0)
}
}
this.layoutParams = lp
}
override fun isShown(): Boolean {
return isShown
}
fun setBadgeMargin(badgeMargin: Int) {
horizontalBadgeMargin = badgeMargin
verticalBadgeMargin = badgeMargin
}
fun setBadgeMargin(horizontal: Int, vertical: Int) {
horizontalBadgeMargin = horizontal
verticalBadgeMargin = vertical
}
var badgeBackgroundColor: Int
get() = badgeColor
set(badgeColor) {
this.badgeColor = badgeColor
badgeBg = defaultBackground
}
private fun dipToPixels(dip: Int): Int {
val r = this.resources
val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip.toFloat(), r.displayMetrics)
return px.toInt()
}
companion object {
const val POSITION_TOP_LEFT = 1
const val POSITION_TOP_RIGHT = 2
const val POSITION_BOTTOM_LEFT = 3
const val POSITION_BOTTOM_RIGHT = 4
const val POSITION_CENTER = 5
private const val DEFAULT_MARGIN_DIP = 5
private const val DEFAULT_LR_PADDING_DIP = 5
private const val DEFAULT_CORNER_RADIUS_DIP = 8
private const val DEFAULT_POSITION = 2
private val DEFAULT_BADGE_COLOR = Color.parseColor("#CCFF0000")
private const val DEFAULT_TEXT_COLOR = -1
private var fadeIn: AlphaAnimation? = null
// private var fadeOut: Animation? = null
private var fadeOut: AlphaAnimation? = null
}
}
使用:
val btff = findViewById<TextView>(R.id.bt_ff) // 添加在TextView右上角
var badge = BadgeView(this, btff)
badge.text = "12"
//设置文本颜色
// badge.setTextColor(Color.WHITE)
// //设置背景颜色
// badge.badgeBackgroundColor = Color.RED
// //显示
badge.show()