如何开发可发送Carousel轮播式推送通知的Android应用
嘿,我来帮你搞定这个需求!轮播推送能让用户在通知栏里直接滑动浏览多组内容,不管是推商品、资讯还是活动都挺实用的。下面分两种主流方案给你拆解清楚,还有一些踩过的坑也一并告诉你:
一、方案1:自定义RemoteViews实现单通知内的左右轮播
这是最贴合你需求的方案——在单个通知卡片里实现左右滑动的轮播视图。不过要先明确:Android原生通知模板没有自带轮播样式,得靠自定义布局来实现,而且要遵守RemoteViews的规则(毕竟通知是系统进程托管的,不是咱们APP自己的进程)。
1. 准备布局文件
首先做两个布局:一个是轮播的容器,一个是单个轮播项的样式。
容器布局 res/layout/notification_carousel.xml:
用HorizontalScrollView包裹LinearLayout,这样用户可以左右滑动浏览内容,而且都是系统原生控件,兼容性拉满:
<?xml version="1.0" encoding="utf-8"?> <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="200dp" android:scrollbars="none"> <LinearLayout android:id="@+id/carousel_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" android:showDividers="none" android:paddingHorizontal="8dp"/> </HorizontalScrollView>
单个轮播项布局 res/layout/carousel_item.xml:
根据你的需求自定义样式,比如展示图片、标题和描述:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/item_root" android:layout_width="280dp" android:layout_height="match_parent" android:orientation="vertical" android:padding="8dp" android:layout_marginEnd="8dp" android:background="@drawable/notification_item_round_bg"> <ImageView android:id="@+id/item_image" android:layout_width="match_parent" android:layout_height="120dp" android:scaleType="centerCrop"/> <TextView android:id="@+id/item_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="16sp" android:textStyle="bold" android:layout_marginTop="4dp"/> <TextView android:id="@+id/item_desc" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="12sp" android:textColor="@android:color/darker_gray"/> </LinearLayout>
2. 填充轮播数据并构建RemoteViews
在发送通知的代码里,咱们要动态生成每个轮播项的RemoteViews,然后添加到容器里:
// 先定义个数据类存轮播内容 data class CarouselItem(val title: String, val desc: String, val imageRes: Int) // 1. 初始化主容器的RemoteViews val carouselRemoteViews = RemoteViews(context.packageName, R.layout.notification_carousel) // 2. 准备轮播数据,比如3个商品 val carouselItems = listOf( CarouselItem("夏日T恤限时折", "全场5折起,手慢无", R.drawable.tshirt), CarouselItem("新款运动鞋上市", "透气缓震,跑步必备", R.drawable.shoes), CarouselItem("爆款背包热销", "大容量防水,通勤首选", R.drawable.bag) ) // 3. 逐个添加轮播项到容器 carouselItems.forEachIndexed { index, item -> val itemView = RemoteViews(context.packageName, R.layout.carousel_item) // 填充内容 itemView.setTextViewText(R.id.item_title, item.title) itemView.setTextViewText(R.id.item_desc, item.desc) itemView.setImageViewResource(R.id.item_image, item.imageRes) // 给每个轮播项设置点击事件(跳转详情页) val pendingIntent = PendingIntent.getActivity( context, index, // 注意请求码要唯一,不然点击事件会冲突 Intent(context, ProductDetailActivity::class.java).putExtra("product_id", index), PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) itemView.setOnClickPendingIntent(R.id.item_root, pendingIntent) // 添加到容器LinearLayout carouselRemoteViews.addView(R.id.carousel_container, itemView) }
3. 构建并发送通知
把自定义布局设置到通知里,这里要记得加DecoratedCustomViewStyle(),确保自定义布局适配系统通知栏的样式:
val notificationBuilder = NotificationCompat.Builder(context, CAROUSEL_CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) // 必须设置,不然通知发不出去 .setContentTitle("夏日特惠专场") .setContentText("滑动查看更多好物") .setPriority(NotificationCompat.PRIORITY_HIGH) .setStyle(NotificationCompat.DecoratedCustomViewStyle()) // 关键!适配通知栏样式 .setCustomBigContentView(carouselRemoteViews) // 设置展开后的自定义布局 .setAutoCancel(true) // 点击后自动消失 // 发送通知 val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(CAROUSEL_NOTIFICATION_ID, notificationBuilder.build())
4. 避坑提醒
- RemoteViews控件限制:只能用系统原生控件(比如TextView、ImageView、HorizontalScrollView),自定义View和AndroidX控件(比如ViewPager2)都不支持,别踩这个坑!
- 尺寸限制:通知栏高度有限,自定义布局高度建议控制在200dp以内,不然会被系统截断。
- 兼容性:Android 7.0(API 24)及以上才支持自定义大布局,低版本可以降级用普通通知或者BigPictureStyle。
二、方案2:用通知组模拟轮播(简单替代方案)
如果觉得自定义布局太繁琐,也可以用通知组来模拟类似效果——发送多个同组的通知,系统会自动聚合成一个组,用户可以上下滑动切换组内的单个通知(虽然是上下滑不是左右滑,但实现简单):
// 1. 先定义组Key private const val GROUP_KEY_CAROUSEL = "group_carousel" // 2. 创建组总结通知 val groupSummaryBuilder = NotificationCompat.Builder(context, CAROUSEL_CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle("夏日特惠专场") .setContentText("共3条好物推荐") .setStyle(NotificationCompat.InboxStyle() .addLine("夏日T恤限时折") .addLine("新款运动鞋上市") .addLine("爆款背包热销")) .setGroup(GROUP_KEY_CAROUSEL) .setGroupSummary(true) // 3. 发送组内的单个通知 carouselItems.forEachIndexed { index, item -> val itemNotification = NotificationCompat.Builder(context, CAROUSEL_CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(item.title) .setContentText(item.desc) .setLargeIcon(BitmapFactory.decodeResource(context.resources, item.imageRes)) .setGroup(GROUP_KEY_CAROUSEL) .build() notificationManager.notify(index + 100, itemNotification) // 通知ID要唯一 } // 4. 最后发送组总结通知 notificationManager.notify(GROUP_SUMMARY_ID, groupSummaryBuilder.build())
三、必备:通知渠道配置(Android 8.0+)
Android 8.0及以上必须创建通知渠道,不然通知发不出去,在APP启动的时候配置一下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( CAROUSEL_CHANNEL_ID, "轮播推送渠道", NotificationManager.IMPORTANCE_HIGH ).apply { description = "用于展示轮播样式的商品推送通知" enableVibration(true) vibrationPattern = longArrayOf(100, 200, 100) } val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) }
内容的提问来源于stack exchange,提问作者CuriousMind

