iOS Swift中如何绘制角标并添加至通知图标
实现带动态红色角标的通知图标
核心思路
- 基于原通知图标,动态绘制红色角标(支持纯红点或带数字样式)
- 根据新通知状态,切换显示纯图标或带角标的合成图标
- 将最终生成的图标资源传入自定义组件
Android 端实现示例
1. 编写角标合成工具类
object BadgeUtils { fun addBadgeToIcon(context: Context, originalIconResId: Int, hasNewNotification: Boolean): Bitmap { val originalBitmap = BitmapFactory.decodeResource(context.resources, originalIconResId) // 创建可编辑的Bitmap副本 val editableBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true) val canvas = Canvas(editableBitmap) val paint = Paint().apply { color = Color.RED isAntiAlias = true style = Paint.Style.FILL } if (hasNewNotification) { // 绘制右上角红色圆形角标,尺寸占图标宽度的20% val badgeRadius = originalBitmap.width * 0.2f val badgeX = originalBitmap.width - badgeRadius val badgeY = badgeRadius canvas.drawCircle(badgeX, badgeY, badgeRadius, paint) // 如需显示未读数字,取消注释以下代码 // val textPaint = Paint().apply { // color = Color.WHITE // textSize = badgeRadius * 1.2f // textAlign = Paint.Align.CENTER // isAntiAlias = true // } // canvas.drawText("5", badgeX, badgeY + badgeRadius * 0.4f, textPaint) } // 释放原Bitmap资源 originalBitmap.recycle() return editableBitmap } }
2. 传入自定义组件
// 检查是否有新通知(自行实现业务逻辑) val hasNewNotification = checkUnreadNotifications() // 合成带角标的图标 val badgeIcon = BadgeUtils.addBadgeToIcon(this, R.drawable.ic_notification, hasNewNotification) // 传给自定义组件 customImageComponent.setIcon(badgeIcon)
iOS 端实现示例
1. 编写角标合成工具类
class BadgeHelper { static func addBadgeToIcon(originalImage: UIImage, hasNewNotification: Bool) -> UIImage { UIGraphicsBeginImageContextWithOptions(originalImage.size, false, UIScreen.main.scale) originalImage.draw(in: CGRect(x: 0, y: 0, width: originalImage.size.width, height: originalImage.size.height)) if hasNewNotification { // 绘制右上角红色圆形角标 let badgeRadius = originalImage.size.width * 0.2 let badgeFrame = CGRect( x: originalImage.size.width - badgeRadius, y: 0, width: badgeRadius * 2, height: badgeRadius * 2 ) UIColor.red.setFill() UIBezierPath(ovalIn: badgeFrame).fill() // 如需显示未读数字,取消注释以下代码 // let text = "5" // let textAttributes: [NSAttributedString.Key: Any] = [ // .font: UIFont.systemFont(ofSize: badgeRadius * 1.2), // .foregroundColor: UIColor.white // ] // let textSize = text.size(withAttributes: textAttributes) // let textRect = CGRect( // x: originalImage.size.width - badgeRadius - textSize.width/2, // y: badgeRadius - textSize.height/2, // width: textSize.width, // height: textSize.height // ) // text.draw(in: textRect, withAttributes: textAttributes) } let finalImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return finalImage } }
2. 传入自定义组件
// 检查是否有新通知(自行实现业务逻辑) let hasNewNotification = checkUnreadNotifications() if let originalImage = UIImage(named: "ic_notification") { let badgeImage = BadgeHelper.addBadgeToIcon(originalImage: originalImage, hasNewNotification: hasNewNotification) // 传给自定义组件 customImageView.image = badgeImage }
Flutter 端实现示例(无需合成图片)
直接通过Stack组件叠加实现状态切换,更灵活高效:
Widget buildNotificationIcon(bool hasNewNotification) { return Stack( alignment: Alignment.topRight, children: [ // 原通知图标 Image.asset("assets/ic_notification.png", width: 40, height: 40), // 有新通知时显示角标 if (hasNewNotification) Container( width: 16, height: 16, decoration: const BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), // 如需显示未读数字,取消注释以下代码 // child: const Text( // "5", // style: TextStyle(color: Colors.white, fontSize: 12), // textAlign: TextAlign.center, // ), ), ], ); }
传入自定义组件:
// 检查是否有新通知(自行实现业务逻辑) bool hasNewNotification = checkUnreadNotifications(); // 传给自定义组件 CustomImageComponent( icon: buildNotificationIcon(hasNewNotification), )
注意事项
- 角标的大小、位置可根据图标实际尺寸调整,保证视觉协调
- Android 端处理 Bitmap 时注意资源释放,避免内存泄漏
- 如果需要支持角标数字超过9时显示"9+",可在文本绘制逻辑中添加判断
内容的提问来源于stack exchange,提问作者Jayaseelan Kumarasamy
相关产品推荐
相关产品推荐

