rn_for_openharmony商城项目app实战-消息通知设置实现
本文介绍了消息通知设置页面的实现方法,使用React Native的Switch组件控制推送通知开关。页面包含一个总开关(控制所有推送)和三个分类开关(订单通知、促销活动、系统通知)。当总开关关闭时,分类开关会自动禁用并变灰。所有设置数据通过全局状态管理,便于其他页面调用。这种设计既满足了用户对通知管理的需求,又保持了应用的灵活性。
案例开源地址:https://atomgit.com/nutpi/rn_openharmony_buy
写在前面
消息通知设置这个功能,说实话用户不会经常用,但一定要有。为什么?因为有些用户真的很烦推送通知。
我自己手机上装了几十个 App,如果每个都疯狂推送,一天能收到上百条通知,根本看不过来。所以我会把大部分 App 的通知关掉,只留几个重要的。
作为开发者,我们当然希望用户开着通知,这样能提高用户活跃度。但如果不给用户关闭的选项,用户可能直接把整个 App 的通知权限关掉,或者干脆卸载。所以,给用户控制权反而是更好的选择。
这篇文章记录一下消息通知设置页面的实现过程,主要是用 Switch 组件来控制各种通知的开关。
页面要实现什么功能
消息通知设置页面需要控制这些开关:
总开关:
- 推送通知:控制是否接收任何推送
分类开关:
- 订单通知:订单状态变更提醒
- 促销活动:优惠活动和促销信息
- 系统通知:系统公告和服务通知
逻辑上,如果总开关关了,分类开关应该全部禁用。这个交互很常见,微信、支付宝的通知设置都是这么做的。
引入需要的依赖
import React from 'react';
这个页面不需要 useState,因为设置数据存在全局状态里,直接用全局状态的读写方法就行。
import {View, Text, StyleSheet, Switch} from 'react-native';
Switch是 React Native 内置的开关组件,就是那种左右滑动的开关。iOS 和 Android 上的样式会有点不一样,但功能是一样的。
import {useApp} from '../store/AppContext';
import {Header} from '../components/Header';
useApp 里有 settings 对象和 updateSettings 方法,用来读取和更新设置。
获取设置数据
export const NotificationsScreen = () => {
const {settings, updateSettings} = useApp();
从全局状态里取两个东西:
settings:当前的设置数据,是个对象,里面有各种设置项的值
updateSettings:更新设置的方法,传入 key 和 value 就能更新对应的设置项
这种设计的好处是,设置数据是全局的,在任何页面都能读取到。比如首页要根据 pushEnabled 判断是否显示通知提示,直接从 settings 里取就行。
页面整体结构
return (
<View style={styles.container}>
<Header title="消息通知" />
<View style={styles.content}>
{/* 总开关 */}
{/* 分类开关 */}
{/* 底部提示 */}
</View>
</View>
);
结构很简单,一个 Header,下面是设置项列表。
总开关
<View style={styles.item}>
<View style={styles.itemInfo}>
<Text style={styles.itemTitle}>推送通知</Text>
<Text style={styles.itemDesc}>开启后可接收推送消息</Text>
</View>
<Switch
value={settings.pushEnabled}
onValueChange={(value) => updateSettings('pushEnabled', value)}
trackColor={{false: '#ddd', true: '#3498db'}}
thumbColor="#fff"
/>
</View>
这是最重要的开关,控制是否接收任何推送。
value:开关的当前状态,从
settings.pushEnabled读取onValueChange:状态变化时的回调,把新值更新到全局状态
trackColor:轨道颜色,
false是关闭时的颜色,true是开启时的颜色thumbColor:滑块颜色,我们用白色
Switch 组件的样式在不同平台上有差异。iOS 上开启是绿色的,Android 上是蓝色的。通过 trackColor 可以统一成我们想要的颜色。
item: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#fff',
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#f0f0f0'
},
每个设置项是一行,左边是文字说明,右边是开关。用
justifyContent: 'space-between'让它们分布在两端。
itemInfo: {flex: 1, marginRight: 16},
itemTitle: {fontSize: 16, color: '#333'},
itemDesc: {fontSize: 12, color: '#999', marginTop: 4},
标题用 16 号字,描述用 12 号灰色字,层次分明。
分类开关的标题
<View style={styles.section}>
<Text style={styles.sectionTitle}>通知类型</Text>
分类开关上面加个小标题,让用户知道下面这些是具体的通知类型。
section: {marginTop: 24},
sectionTitle: {fontSize: 14, color: '#999', paddingHorizontal: 16, paddingVertical: 12},
标题用灰色小字,和设置项区分开。
订单通知开关
<View style={[styles.item, !settings.pushEnabled && styles.disabledItem]}>
<View style={styles.itemInfo}>
<Text style={[styles.itemTitle, !settings.pushEnabled && styles.disabledText]}>
订单通知
</Text>
<Text style={[styles.itemDesc, !settings.pushEnabled && styles.disabledText]}>
订单状态变更提醒
</Text>
</View>
<Switch
value={settings.orderNotify}
onValueChange={(value) => updateSettings('orderNotify', value)}
trackColor={{false: '#ddd', true: '#3498db'}}
thumbColor="#fff"
disabled={!settings.pushEnabled}
/>
</View>
这里有几个关键点:
条件样式:如果总开关关了(
!settings.pushEnabled),整个 item 加上disabledItem样式,文字加上disabledText样式,看起来是灰色禁用状态。disabled 属性:Switch 组件的
disabled属性设为!settings.pushEnabled,总开关关了这个开关就不能点击。
disabledItem: {opacity: 0.5},
disabledText: {color: '#ccc'},
禁用状态用 opacity: 0.5 让整个 item 变淡,文字变成浅灰色。这样用户一眼就能看出这些开关现在不可用。
促销活动开关
<View style={[styles.item, !settings.pushEnabled && styles.disabledItem]}>
<View style={styles.itemInfo}>
<Text style={[styles.itemTitle, !settings.pushEnabled && styles.disabledText]}>
促销活动
</Text>
<Text style={[styles.itemDesc, !settings.pushEnabled && styles.disabledText]}>
优惠活动和促销信息
</Text>
</View>
<Switch
value={settings.promoNotify}
onValueChange={(value) => updateSettings('promoNotify', value)}
trackColor={{false: '#ddd', true: '#3498db'}}
thumbColor="#fff"
disabled={!settings.pushEnabled}
/>
</View>
和订单通知一样的结构,只是 key 不同(promoNotify)。
促销活动这个开关,说实话很多用户会关掉。因为促销推送太多了,用户会觉得烦。但对于运营来说,这是触达用户的重要渠道。所以我们把它做成可选的,让用户自己决定。
系统通知开关
<View style={[styles.item, !settings.pushEnabled && styles.disabledItem]}>
<View style={styles.itemInfo}>
<Text style={[styles.itemTitle, !settings.pushEnabled && styles.disabledText]}>
系统通知
</Text>
<Text style={[styles.itemDesc, !settings.pushEnabled && styles.disabledText]}>
系统公告和服务通知
</Text>
</View>
<Switch
value={settings.systemNotify}
onValueChange={(value) => updateSettings('systemNotify', value)}
trackColor={{false: '#ddd', true: '#3498db'}}
thumbColor="#fff"
disabled={!settings.pushEnabled}
/>
</View>
系统通知一般是比较重要的信息,比如服务升级、安全提醒等。建议默认开启。
底部提示
<Text style={styles.tip}>
💡 关闭推送通知后,您将无法收到订单状态变更、促销活动等重要消息
</Text>
在页面底部加一个提示,告诉用户关闭通知的后果。
这个提示的目的是"劝退"用户不要关闭通知。但我们不是强制,只是告知。用户看了这个提示,如果还是要关,那就关吧。
tip: {fontSize: 13, color: '#999', padding: 16, lineHeight: 20},
提示用灰色小字,不要太醒目,但要让用户能看到。
关于 Switch 组件的一些经验
用 Switch 组件有几个注意事项:
1. 平台差异
iOS 和 Android 上的 Switch 样式不一样。iOS 是圆形滑块,Android 是方形滑块。如果想要完全一致的样式,可以自己用 TouchableOpacity + Animated 实现一个。
2. 颜色自定义
trackColor 可以分别设置开启和关闭时的轨道颜色。thumbColor 设置滑块颜色。但在 iOS 上,thumbColor 可能不生效,这是 React Native 的一个已知问题。
3. disabled 状态
Switch 的 disabled 属性可以禁用开关,但禁用后的样式可能不够明显。建议像我们这样,额外加上 opacity 或者改变文字颜色,让禁用状态更明显。
4. 受控 vs 非受控
Switch 应该是受控组件,也就是 value 由外部状态控制。不要用非受控的方式(不传 value),不然状态会乱。
设置数据的存储
我们的设置数据存在全局状态里,但这只是内存中的数据,App 关闭后就没了。实际项目中,设置数据应该持久化存储。
常用的方案有:
1. AsyncStorage
React Native 提供的本地存储方案,类似于 Web 的 localStorage。简单易用,适合存储少量数据。
// 保存设置
await AsyncStorage.setItem('settings', JSON.stringify(settings));
// 读取设置
const data = await AsyncStorage.getItem('settings');
const settings = data ? JSON.parse(data) : defaultSettings;
2. MMKV
比 AsyncStorage 快很多的存储方案,微信团队开源的。如果设置项很多或者读写频繁,建议用这个。
3. 后端同步
如果用户在多个设备上使用 App,设置数据应该同步到后端。用户在手机上改了设置,平板上也能生效。
我们这里为了演示简化了,只用内存存储。实际项目中要根据需求选择合适的方案。
通知权限的问题
这个页面只是控制 App 内部的通知开关,但还有一个更上层的开关:系统的通知权限。
如果用户在系统设置里关闭了 App 的通知权限,不管我们这里怎么设置都没用。所以有些 App 会在这个页面检测系统通知权限,如果关闭了就提示用户去系统设置里打开。
// 伪代码,实际需要用 react-native-permissions 等库
const checkPermission = async () => {
const status = await checkNotificationPermission();
if (status === 'denied') {
Alert.alert(
'通知权限已关闭',
'请在系统设置中开启通知权限',
[{text: '去设置', onPress: openSettings}, {text: '取消'}]
);
}
};
这个功能我们这里没实现,但值得了解。
一些产品层面的思考
1. 默认值的选择
通知开关默认应该是开还是关?从用户体验角度,应该让用户自己选择。但从运营角度,默认开启能触达更多用户。
我的建议是:重要通知(订单、系统)默认开启,营销通知(促销)默认关闭或者让用户首次使用时选择。
2. 通知频率控制
除了开关,还可以加上频率控制。比如促销通知,用户可以选择"每天最多1条"或者"每周最多3条"。这样既能触达用户,又不会太打扰。
3. 免打扰时段
让用户设置免打扰时段,比如晚上 10 点到早上 8 点不推送。这个功能很贴心,但实现起来需要后端配合。
4. 通知预览
在设置页面展示各种通知的样例,让用户知道开启后会收到什么样的通知。这样用户能做出更明智的选择。
小结
消息通知设置页面的核心是 Switch 组件的使用:
- 总开关控制是否接收任何推送
- 分类开关控制具体类型的通知
- 总开关关闭时,分类开关要禁用
- 禁用状态要有明显的视觉反馈
几个关键点:
- Switch 的
value和onValueChange实现受控组件 disabled属性配合样式实现禁用效果trackColor自定义开关颜色- 底部提示告知用户关闭通知的后果
设置类页面看着简单,但细节很多。做好了用户会觉得这个 App 很专业。
下一篇写账号安全页面,敬请期待。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)