我在去年曾经写过一篇类似的《使用 Drawable 实现小红点》,但是小红点的具体实现是在这个类里面的。这次是在其思路上进行扩展,使得小红点或者说是角标的样式更加灵活。

在一些图标的右上角添加小红点,是我们开发中很常见的场景,比如下图所示,底部 TAB 会有小红点,上面的功能图标也会有小红点。

对于这种需求,我们以往的解决方式通常是使用一个 RelativeLayout,里面再放置一个 TextView,一个 ImageView 和一个表示小红点的普通的 View,并且,我们还需要根据小红点的大小,写死这个 View 的外边距参数以让它的中心能够“正好”位于图标的右上角。

这种实现它有如下缺点:

  • 增加了布局的层次,原本只需要一个 TextView 的 Tab 或 item,现在需要用一个布局容器和三个 View 的组合。
  • 需要根据小红点的大小去设置布局参数,当它扩展成更大的带数字的小红点时,我们还需要去修改布局。

Drawable 正是解决这些问题的利器。

Drawable 是对可绘制对象的抽象,再具体下来会有画图片的 BitmapDrawable 或者是纯色的 ColorDrawable,而且 Drawable 会在回调方法里提供一个 Canvas,这使得对它的利用有了很大的可能性。所以,我们可以继承自 Drawable 类,对原本的图标包装一下,并实现自己对小红点的绘制。
与我之前所写的《使用 Drawable 实现小红点》不同的是,这里的小红点,并不由我们的 Drawable 本身来绘制,它是可以从外面传入的。

这也就是说:我们只需要在 Drawable 里实现将小红点的 Drawable 画到我们图标上的对应位置上即可。具体的小红点的表现形式,是一个小红点,还是外面有一层描边,还是带数字,我们都不需要关心,由调用者处理。而且,这个小红点的 Drawable,可以通过 xml 定义,也可以自己再继承 Drawable 类来实现绘制(如带数字的小红点),这使得它也有很大的扩展性。我们只需要提供设置是否显示小红点以及设置小红点的位置的方法即可。完整代码如下:

class BadgeDrawable(private val mOrigin: Drawable, val badge: Drawable) : Drawable() {var showBadge: Boolean = falseset(show) {field = showinvalidateSelf()}var gravity = Gravity.CENTERinit {badge.setBounds(0, 0, badge.intrinsicWidth, badge.intrinsicHeight)}override fun draw(canvas: Canvas) {mOrigin.draw(canvas)if (showBadge) {val radiusX = badge.intrinsicWidth / 2.0fval radiusY = badge.intrinsicHeight / 2.0fvar x = bounds.right - radiusXvar y = bounds.top - radiusYif (Gravity.LEFT.and(gravity) == Gravity.LEFT) {x -= radiusX} else if (Gravity.RIGHT.and(gravity) == Gravity.RIGHT) {x += radiusX}if (Gravity.TOP.and(gravity) == Gravity.TOP) {y -= radiusY} else if (Gravity.BOTTOM.and(gravity) == Gravity.BOTTOM) {y += radiusY}canvas.save()canvas.translate(x, y)badge.draw(canvas)canvas.restore()}}override fun getState(): IntArray {return mOrigin.state}override fun setState(stateSet: IntArray?): Boolean {return mOrigin.setState(stateSet)}override fun getConstantState(): ConstantState {return mOrigin.constantState}override fun isStateful(): Boolean {return mOrigin.isStateful}override fun jumpToCurrentState() {mOrigin.jumpToCurrentState()}override fun setAlpha(alpha: Int) {mOrigin.alpha = alpha}override fun getOpacity(): Int {return mOrigin.opacity}override fun setColorFilter(colorFilter: ColorFilter?) {mOrigin.colorFilter = colorFilter}override fun getIntrinsicHeight(): Int {return mOrigin.intrinsicHeight}override fun getIntrinsicWidth(): Int {return mOrigin.intrinsicWidth}override fun setBounds(bounds: Rect?) {super.setBounds(bounds)mOrigin.bounds = bounds}override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {super.setBounds(left, top, right, bottom)mOrigin.setBounds(left, top, right, bottom)}
}

那么,如何使用呢?
以上面的图片的 Tab 为例。我们的 Tab 自定义布局如下:

<com.githang.drawablewidget.DrawableTextView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:skin="http://schemas.android.com/android/skin"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/tab_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true"android:drawablePadding="2dp"android:gravity="center"android:paddingBottom="6dp"android:paddingTop="8dp"android:textColor="@color/skin_tab_text"android:textSize="10sp"app:drawableHeight="22dp"skin:enable="true"tools:drawableTop="@drawable/ic_username"tools:ignore="MissingPrefix"tools:text="123123" />

然后我们在 kotlin 代码中创建对应的 Tab,并以一个变量保存这个包装了小红点的 Drawable,代码如下:

private lateinit var mOperatingBadge: BadgeDrawable
//... 中间代码省略private fun initTabs() {mOperatingBadge = getBadgeDrawable(resources, R.drawable.ic_tab_operation)val operation = newTab(mOperatingBadge, R.string.operation)mTabLayout.addTab(operation)
// ... 其他Tab,代码省略
}private fun getBadgeDrawable(resources: Resources, @DrawableRes drawableId: Int): BadgeDrawable {// 获取原来的图标val icon = ResourcesCompat.getDrawable(resources, drawableId, null)!!// 获取我们在 xml 定义的小红点val badge = ResourcesCompat.getDrawable(resources, R.drawable.badge_stroke_white, null)!!// 包装成我们的 BadgeDrawable 对象return BadgeDrawable(icon, badge)
}private fun newTab(drawable: Drawable, @StringRes textId: Int): TabLayout.Tab {val tab = mTabLayout.newTab()tab.setCustomView(R.layout.widget_tab_view)tab.customView?.let {val textView = it.findViewById<TextView>(R.id.tab_text)// 将包装的 Drawable 对象设置到 TextView 的 drawableTop 上textView.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null)textView.setText(textId)}return tab
}

xml 定义的小红点也很简单,它的形状是这样的:

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"android:shape="oval"><size android:width="11dp" android:height="11dp"/><solid android:color="@color/text_red"/><stroke android:width="2dp" android:color="@android:color/white"/>
</shape>

那么,当我们需要显示或隐藏这个小红点的时候需要怎么做呢?这很简单,调用一下我们的 BadgeDrawable 对象就可以了:

mOperatingBadge.showBadge = true

然后它就会更新自身的绘制。不会带来布局的变化,没有布局代码的入侵,而且小红点可以扩展成其他任意的角标实现,不管是三角还是数字,看你传进来的 Drawable 的具体表现。

本文相关项目地址:
badge-drawable:https://github.com/msdx/badge-drawable

使用 Drawable 实现图标角标相关推荐

  1. Launcher图标角标

    前言 桌面图标的角标,看着是个很简单的功能,就是在应用的右上角显示当前有几个未读消息:在网上查了资料之后,发现很多同行说,Android原生是没有此功能,平时使用的手机都有该功能,其实是国内手机厂商自 ...

  2. 跨平台应用开发进阶(十二) :uni-app 实现应用桌面图标角标提示及应用跳转

    文章目录 一.前言 二.实现 2.1 集成极光实现 2.1.1 通道支持 2.1.2 iOS 角标 2.1.3 华为角标 2.1.4 小米角标 2.1.5 vivo 角标 2.2 H5+实现 三.遇到 ...

  3. android 应用图标 角标 显示未读消息

    Android桌面角标的适配确实是非常坑爹的需求.原生系统根本就没有这个功能,国内很多厂家效仿ios都自己定义了该功能.Android程序员就很苦逼,要适配很多机型.建议万不得已情况下还是不要进行这项 ...

  4. php 友盟推送角标,android集成友盟推送实现离线在线推送及桌面图标角标设置

    本人亲测有效,有问题欢迎评论,互相学习 1.集成友盟推送-根据友盟文档集成即可实现在线推送 2.集成后想要实现点击跳转到指定页面,那么就要根据后台返回的数据进行跳转 (1)在线推送-在applicat ...

  5. 华为手机设置桌面图标角标提醒的实现

    华为手机用户占有率已经很大,有必要为华为手机支持角标提醒. 首先,要参考官网文档. 实现 1. 申请权限,这里有点多,还包含了其他手机的.官方文档的权限是不够的. <uses-permissio ...

  6. uni-app(plus设计app图标角标)

    //#ifdef APP-PLUSplus.runtime.setBadgeNumber(10); //添加角标 //#endif

  7. app图标角标产品设计_新手如何设计App的图标Logo?

    想要设计一款App图标logo,却不知道从何下手,也不清楚尺寸规范.针对新手,如何快速搞定app logo图标设计?今天和大家分享移动App 的logo图标设计,现学现用容易上手的4个小套路! 一.品 ...

  8. app图标角标产品设计_一枚app图标的设计文化

    启动图标是每一个iOS中应用软件的关键组成部分. 它能传达给你应用程序的基础信息,并能够给用户带来第一印象感受. 它是一个非常重要的软件入口,能直接引导用户下载并使用应用程序.它的重要性在这个智能手机 ...

  9. app图标角标产品设计_APP图标风格与创意设计的方法分享

    本篇文章分享了一些如何确定.把控图标风格,以及图标设计的创意方法,对于刚入职场的设计师们来说非常实用. 图标是用户在应用中接触最多的视觉符号,它既承载了引导用户操作的功能,也是构成产品视觉风格的重要元 ...

最新文章

  1. 白盒测试黑盒测试和单元测试集成测试和系统测试的关系
  2. SENet双塔模型:在推荐领域召回粗排的应用及其它
  3. 小工匠聊架构 - 分布式缓存技术_缓存设计
  4. boost::hash_range相关的测试程序
  5. 汇编-debug结果正确与执行结果错误
  6. javascript关键字_让我们揭开JavaScript的“ new”关键字的神秘面纱
  7. 2020云计算,是四强争霸还是赢家通吃?
  8. treemap比较器_Java TreeMap比较器()方法与示例
  9. python安装方法及运行_Python下载及其安装步骤
  10. python小游戏-16行代码实现3D撞球小游戏!-源码下载
  11. ubuntu12.04 qtcreate支持中文输入
  12. 抓包工具之fiddler
  13. 中国生态城市规划行业“十四五”规划与前景规模预测报告2022-2028年版
  14. 抖音矩阵系统源码搭建,抖音矩阵系统开发原理,抖音矩阵系统搭建
  15. 跟父亲一样伟大的程序员,请照顾好自己!
  16. 移动oa咋显示无法连接服务器,移动oa办公系统管理维护技巧:让本地连接不再受限的方法...
  17. 微信查好友单删检测方法,无打扰,快来学
  18. 投资的收益与风险的数学建模
  19. 获取pc微信信息_如何获取有关您的PC的详细信息
  20. ​【汇总】CV 图像分类常见的 36 个模型

热门文章

  1. Java版碰撞球游戏
  2. 手机相机里面的m_如何使用手机相机的专业模式
  3. 3D打印品牌的康复骨科支具有何特别之处?
  4. 完整的游戏数据包下载安装教程
  5. jQuery放大镜实现
  6. HTML实战案例3:制作易趣网商品列表页面
  7. 0x000000f怎么修复 win10_win10错误代码0xc000000f 修复方法
  8. 一劳永逸部署项目:通过tomcat加载环境变量
  9. 物联网时代,物联感知技术将如何发展?
  10. 句柄无效及拒绝访问错误;