提示框是网络的一个固有的组成部分,它们的效用随其使用情况而变化。它们被用来显示消息、警告、警报和确认同意。
通过提醒对话框,用户通常可以得到同意、不同意和取消的按钮选项。有时警报也被用来记录用户的输入,但这取决于平台。
在这篇文章中,我们将学习如何在React Native中创建一个自定义的警报对话框,以满足你的项目的需要。
简介
React Native提供了一个Alert API,可以用来在Android和iOS上显示本地警报对话框。但本地警报对话框有一些限制。
例如,在Android上我们不能显示三个以上的按钮,也没有提供捕捉用户输入的选项。尽管iOS允许我们有很多按钮,并让用户输入数据,但我们仍然不能显示图片、图表,或者除了文字以外的任何形式的自定义。
为了处理这些限制,我们需要创建自定义警报对话框。一个自定义的警报对话框可以像模态一样行动,并且可以支持组件。
警报框的属性
在定制任何本地组件之前,我们应该对其架构和事件处理有清晰的了解。
例如,一个按钮拥有多个属性,如标签和膨胀度。一个按钮还拥有诸如按下、按住、释放、悬停等事件。当我们定制它时,我们需要考虑所有这些属性。否则,我们将失去外观、感觉和功能。
一个本地警报框有以下属性。
- 标题 - 一个文本标题,以表明该警报的目的。Android和iOS支持。
- 信息 - 解释通知或警告的文本信息。安卓和iOS支持
- 按钮--安卓支持最多三个按钮,而iOS支持无限的按钮。
- 外部敲击 - 安卓系统的警报可以通过敲击警报外部来关闭。
onPress- 按一下按钮就可以打电话的功能。安卓和iOS都支持这个功能onDismiss- 当警报关闭时呼叫的功能。只有安卓支持这个功能- Prompt - 允许用户在输入区域输入数据。只有iOS支持这个功能
- 后退按钮 - 默认情况下,在Android中,警报会在按下后退按钮时关闭。
在定制警报框时,我们需要考虑所有这些属性。
警报对话框的用户界面和架构
让我们看看本地Alert的外观和不同元素在上面的位置。Android和iOS的Alert在外观和感觉上都是不同的。

安卓规格
根据Material design的概念,Android警报对话框的排版和颜色如下。
| 元素 | 类别 | 属性 | 价值 |
| 容器 | 最大宽度 边框半径 背景颜色 | 280 2 #fafafa | |
| 标题文本 | 在表面上 | 颜色 不透明度 字体重量 大小 大小写 | #000000 100% 粗体 22 句子大小写 |
| 支持性文本 | 在表面上 | 颜色 不透明度 字体重量 大小 案例 | #000000 100% Regular 15 Sentence Case |
| 按钮文本 | 初级 | 颜色 不透明度 字体重量 大小 大小写 | #387ef5 100% 500 16 大写字母 |
| 刮擦 | 在表面上 | 颜色 不透明度 | #232F34 32% |
其他属性,如高度、宽度、填充、边距等,如下。
用于小的按钮动作。

来源:material.io
对于长的按钮动作。

来源:material.io
其他属性包括
仰角 - 24dp
位置 - 中心
从两侧的最小边距 - 48dp
iOS的规格
同样地,对于iOS,我们有以下规格。
| 元素 | 类别 | 属性 | 价值 |
| 容器 | 表面 | 边框半径 最大宽度 背景颜色 z-index | 13px 270px #f8f8f8 10 |
| 标题文本 | 在表面上 | 颜色 Padding Margin Top Align Font Size Case | #000000 12px 16px 7px 8px Center 600 17px Sentence Case |
| 支持性文本 | 在表面上 | 颜色 Align Padding Font Size Case | #000000 中心 0px 16px 21px 常规 13 句子大小写 |
| 按钮容器 | 普通属性 OK按钮 单行多按钮 - 普通 - 非OK按钮 | 右边距 最小高度 边框顶部 字体大小 颜色 行高 字体重量 最小宽度 右边框 | -0.55px 44px 0.55px solid #dbdbdf 17px #387ef5 20px 700 50% 0.55px solid #dbdbdf |
| 剪切 | 在表面上 | 颜色 不透明度 | #000000 30% |
这些信息收集自Ionic AlertController 文档。
自定义警报库和包
GitHub上有一些库可以让你创建自定义警报框。其中一些是 react-native-awesome-alerts, react-native-dialog, 和 react-native-modal。你可以试试这些库,但在这篇文章中,我们将在没有它们的情况下定制警报框。
警报和模态的区别
Alert和Modal在语义上是相同的东西,但在复杂性和可用性上有区别。
提醒对话框是为了以最简单的方式显示简短的信息,这就是为什么它们的功能有限。
另一方面,模态是用于复杂的显示。它们要求我们自己定义整个内容。默认情况下,它们提供事件监听器,如后退按钮处理程序。
定制警报对话框
让我们先看看我们要定制的东西。我们应该记住,警报是用来显示重要信息的。这可能是错误、警告或通知。它们不是用来显示图片或填写表格的。对于这一点,你应该使用模版。
在Alert中,我们将进行自定义。
- 对话框的背景颜色
- 标题和信息的字体颜色、大小、重量等。
- 按钮的字体颜色、背景颜色和边框样式
由于React Native调用了Android和iOS的本地Alert组件,它没有提供一个直接的方法来定制它们。警报是有明确用途的固定组件,因此在Android和iOS中不可定制。安卓开发者使用Dialog 类来实现这一点。
在我们的案例中,我们将使用React Native的Modal API。使用这个API的好处是。
- 我们不需要担心我们的自定义警报的位置。它将停留在整个应用程序的顶部
- Android的后退按钮和Apple TV的菜单按钮将被自动处理。
React Native Modal的简要介绍
React Native Modal API提供了一个容器,它被显示在其包围的View 。一个布尔道具visible 被传递给Modal 组件来显示或隐藏它。还有其他的道具,但我们不关心它们,因为它们对Alert没有用。
这就是Modal 的工作方式。
import React, { useState } from 'react';
import { Modal, Text, Pressable, View } from 'react-native';
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<View>
/**
* Anything here will display on Modal.
* We need to create background overlay and Alert box.
*/
</View>
</Modal>
<View>
/**
* Main App content. This will get hidden when modal opens up
*/
</View>
</View>
);
};
export default App;
modalVisible 是用于显示或隐藏Modal 的状态变量。你可以将模态保留在一个页面上,或者将整个应用包围在它的父View 。最好是使用像Redux这样的存储和状态管理库,因为它可以帮助你在应用程序的任何地方改变modalVisible 变量。
创建一个按钮来打开Alert
首先,我们将需要一个事件来改变modalVisible 的值。在我们的代码中,我们将使用一个按钮。在按下这个按钮时,modalVisible 将变成真,并显示一个Modal 。为了创建这个按钮,我们将使用Pressable 组件。
import React, { useState } from 'react';
import { Modal, Text, Pressable, View } from 'react-native';
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<View>
/**
* Anything here will display on Modal.
* We need to create background overlay and Alert box.
*/
</View>
</Modal>
<View>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.textStyle}>Show Modal</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
});
export default App;
在这段代码中,我们添加了一些造型,以改善按钮和应用程序的其他部分的外观和感觉。目前,它将显示一个按钮。点击这个按钮将打开模态。渲染后的输出将看起来像这样。

创建警报对话框的用户界面
下一步是创建模态UI。但首先,我们需要定义一种方法来区分两个操作系统的默认UI。iOS有一个与Android不同的视图。为了识别操作系统,React Native提供了平台API。
让我们从创建背景开始。正如我们在UI和架构部分所讨论的,Android上的背景色和不透明度分别为#232F34和0.32。对于iOS,这些值分别是#000000和0.3。
import React, { useState } from 'react';
import { Modal, Text, Pressable, View, Platform } from 'react-native';
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<Pressable style={[Platform.OS === "ios" ? styles.iOSBackdrop : styles.androidBackdrop, styles.backdrop]} onPress={() => setModalVisible(false)} />
<View>
/**
* Anything here will display on Modal.
* We need to create background overlay and Alert box.
*/
</View>
</Modal>
<View>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.textStyle}>Show Modal</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
iOSBackdrop: {
backgroundColor: "#000000",
opacity: 0.3
},
androidBackdrop: {
backgroundColor: "#232f34",
opacity: 0.32
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}
});
export default App;
渲染后的输出结果将看起来像这样。

请注意,我们使用Pressable 组件来创建背景。这是因为我们想添加在按下背景墙时关闭模态的功能。
接下来我们将在这个背景板上创建一个警报对话框。但首先,我们应该把Modal 放到一个单独的组件中。这将有助于以不同的风格调用我们的自定义Alert 。
import React, { useState } from "react";
import { Alert, Modal, StyleSheet, Text, Pressable, View, Platform } from "react-native";
const CustomAlert = (props) => {
return (
<Modal
animationType="fade"
transparent={true}
visible={props.modalVisible}
onRequestClose={() => {
props.setModalVisible(false);
}}
>
<Pressable style={[Platform.OS === "ios" ? styles.iOSBackdrop : styles.androidBackdrop, styles.backdrop]} onPress={() => props.setModalVisible(false)} />
<View>
</View>
</Modal>
)
}
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View style={styles.centeredView}>
<CustomAlert modalVisible={modalVisible} setModalVisible={setModalVisible} />
<View>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.textStyle}>Show Modal</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
iOSBackdrop: {
backgroundColor: "#000000",
opacity: 0.3
},
androidBackdrop: {
backgroundColor: "#232f34",
opacity: 0.32
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}
});
export default App;
我们已经创建了一个不同的组件,名称为CustomAlert ,并将我们的Modal 放在其中。
modalVisible 的状态在App.js ,但请记住,更好的方法是使用一个中央存储管理库,如Redux。Redux将使整个应用程序中的所有组件都能访问modalVisible 状态,而且不需要将modalVisible 作为道具传递。
现在是设置Modal 的默认值的时候了。这些值将设计出与Android和iOS的本地警报框类似的盒子。
我们已经在UI和架构部分定义了所有的值。让我们从安卓开始。
安卓定制的警报对话框
默认值是。
| 样式属性 | 值 |
| 箱子 背景颜色 最大宽度 边距 高度 边框半径 | 透明 280 48 24 2 |
| 标题 边距 颜色 字体大小 字体重量 | 24 #000000 22 粗体字 |
| 信息 左边的保证金 右边的保证金 底边的保证金 颜色 字体大小 字体重量 | 24 24 24 #000000 15 正常 |
| 按钮组 边距 | 0 0 8 24 |
| 按钮 边距顶部 边距右侧 填充物 颜色 字体大小 字体重量 文本转换 背景颜色 | 12 8 10 #387ef5 16 500 大写 透明 |
这些默认值是在CustomAlert 组件中定义的。在用户没有提供值的情况下,这些值会被使用。
CustomAlert 组件的不同道具是。
| 支持 | 价值 | 使用 | |
| modalVisible | true|false | 需要 | 要显示/隐藏模态 |
| setModalVisible | 功能 | 必需的 | 改变modalVisible的值 |
| 标题 | 符号 | 可选的 | 设置警报框的标题 |
| 消息 | 符号 | 可选的 | 设置消息 |
| 安卓 | {
container: {
backgroundColor: String
},
title: {
color: String,
fontFamily: String,
fontSize: Number,
fontWeight: String,
},
message: {
color: String,
fontFamily: String,
fontSize: Number,
fontWeight: String
},
} | 所有字段可选 | 设置安卓应用的提示框、标题和消息的样式 |
| ios | {
container: {
backgroundColor: String
},
title: {
color: String,
fontFamily: String,
fontSize: Number,
fontWeight: String,
},
message: {
color: String,
fontFamily: String,
fontSize: Number,
fontWeight: String
},
} | 所有字段可选 | 设置iOS应用的提示框、标题和信息的样式。 |
| 按钮 | [
{
text: String,
func: Function,
styles: {
color: String,
fontSize: Number,
fontWeight: String,
fontFamily: String,
textTransform: String,
backgroundColor: String
}
}
] | 所有字段可选 | 设置按钮的属性。这里有几个要点。
|
请看这段代码,了解CustomAlert 是如何定义默认值的。
const CustomAlert = (props) => {
const [androidDefaults, setAndroidDefaults] = useState({
container: {
backgroundColor: (props.android && props.android.container && props.android.container.backgroundColor) || '#FAFAFA',
},
title: {
color: (props.android && props.android.title && props.android.title.color) || '#000000',
fontFamily: (props.android && props.android.title && props.android.title.fontFamily) || 'initial',
fontSize: (props.android && props.android.title && props.android.title.fontSize) || 22,
fontWeight: (props.android && props.android.title && props.android.title.fontWeight) || 'bold',
},
message: {
color: (props.android && props.android.message && props.android.message.color) || '#000000',
fontFamily: (props.android && props.android.message && props.android.message.fontFamily) || 'initial',
fontSize: (props.android && props.android.message && props.android.message.fontSize) || 15,
fontWeight: (props.android && props.android.message && props.android.message.fontWeight) || 'normal',
},
button: {
color: '#387ef5',
fontFamily: 'initial',
fontSize: 16,
fontWeight: '500',
textTransform: 'uppercase',
backgroundColor: 'transparent',
},
});
return (
<Modal
animationType="fade"
transparent={true}
visible={props.modalVisible}
onRequestClose={() => {
props.setModalVisible(false);
}}
>
<Pressable style={[Platform.OS === "ios" ? styles.iOSBackdrop : styles.androidBackdrop, styles.backdrop]} onPress={() => props.setModalVisible(false)} />
<View style={styles.alertBox}>
{
Platform.OS === "ios" ?
null
:
<View style={[styles.androidAlertBox, androidDefaults.container]}>
<Text style={[styles.androidTitle, androidDefaults.title]}>{props.title || 'Message'}</Text>
<Text style={[styles.androidMessage, androidDefaults.message]}>{props.message || ''}</Text>
</View>
}
</View>
</Modal>
)
}
有些造型是为了布局,这就是为什么我们不提供选项来改变它们。这些是在StyleSheet 对象中声明的。
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
iOSBackdrop: {
backgroundColor: "#000000",
opacity: 0.3
},
androidBackdrop: {
backgroundColor: "#232f34",
opacity: 0.4
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
alertBox: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
androidAlertBox: {
maxWidth: 280,
width: '100%',
margin: 48,
elevation: 24,
borderRadius: 2,
},
androidTitle: {
margin: 24,
},
androidMessage: {
marginLeft: 24,
marginRight: 24,
marginBottom: 24,
},
androidButtonGroup: {
marginTop: 0,
marginRight: 0,
marginBottom: 8,
marginLeft: 24,
},
androidButton: {
marginTop: 12,
marginRight: 8,
},
androidButtonInner: {
padding: 10,
}
});
如果我们使用不同的设置来运行这个,我们会得到以下的输出。

是时候把按钮添加到警报对话框了。安卓系统有几个规格。
- 单个按钮总是OK
- 两个按钮是CANCEL和OK
- 三个按钮是ASK ME LATER、CANCEL和OK。
- 最多可支持三个按钮
- 两个按钮漂浮在盒子的右侧,而第三个按钮漂浮在左侧
- 长的按钮显示在不同的行里
为了满足所有这些条件,我们决定为一个按钮组单独声明一个组件。让我们把它叫做AndroidButtonBox 。看看这段代码吧。
const AndroidButtonBox = () => {
const [buttonLayoutHorizontal, setButtonLayoutHorizontal] = useState(1);
const buttonProps = props.buttons && props.buttons.length > 0 ? props.buttons : [{}]
return (
<View style={[styles.androidButtonGroup, {
flexDirection: buttonLayoutHorizontal === 1 ? "row" : "column",
}]} onLayout={(e) => {
if(e.nativeEvent.layout.height > 60)
setButtonLayoutHorizontal(0);
}}>
{
buttonProps.map((item, index) => {
if(index > 2) return null;
const alignSelfProperty = buttonProps.length > 2 && index === 0 && buttonLayoutHorizontal === 1 ? 'flex-start' : 'flex-end';
let defaultButtonText = 'OK'
if(buttonProps.length > 2){
if(index === 0)
defaultButtonText = 'ASK ME LATER'
else if(index === 1)
defaultButtonText = 'CANCEL';
} else if (buttonProps.length === 2 && index === 0)
defaultButtonText = 'CANCEL';
return (
<View style={[styles.androidButton, index === 0 && buttonLayoutHorizontal === 1 ? {flex: 1} : {}]}>
<Pressable onPress={() => {
props.setModalVisible(false)
if(item.func && typeof(item.func) === 'function')
item.func();
}} style={[{
alignSelf: alignSelfProperty,
}]}>
<View style={[styles.androidButtonInner, {backgroundColor: (item.styles && item.styles.backgroundColor) || androidDefaults.button.backgroundColor}]}>
<Text
style={{
color: (item.styles && item.styles.color) || androidDefaults.button.color,
fontFamily: (item.styles && item.styles.fontFamily) || androidDefaults.button.fontFamily,
fontSize: (item.styles && item.styles.fontSize) || androidDefaults.button.fontSize,
fontWeight: (item.styles && item.styles.fontWeight) || androidDefaults.button.fontWeight,
textTransform: (item.styles && item.styles.textTransform) || androidDefaults.button.textTransform,
}}
>{item.text || defaultButtonText}</Text>
</View>
</Pressable>
</View>
)
})
}
</View>
);
}
在这段代码中,我们声明了一个状态变量,buttonLayoutHorizontal 。这将被用来把按钮组的布局从列改为行。如果所有的按钮都是短的,那么它们将被显示在一个行中。
onLayout 事件被用来确定是否需要改变这个状态变量。然后,我们在通过props提供的按钮数组上运行一个循环,并创建具有适当风格的按钮。
整个代码(对于Android)看起来是这样的。
import React, { useState } from "react";
import { Alert, Modal, StyleSheet, Text, Pressable, View, Platform } from "react-native";
const CustomAlert = (props) => {
const [androidDefaults, setAndroidDefaults] = useState({
container: {
backgroundColor: (props.android && props.android.container && props.android.container.backgroundColor) || '#FAFAFA',
},
title: {
color: (props.android && props.android.title && props.android.title.color) || '#000000',
fontFamily: (props.android && props.android.title && props.android.title.fontFamily) || 'initial',
fontSize: (props.android && props.android.title && props.android.title.fontSize) || 22,
fontWeight: (props.android && props.android.title && props.android.title.fontWeight) || 'bold',
},
message: {
color: (props.android && props.android.message && props.android.message.color) || '#000000',
fontFamily: (props.android && props.android.message && props.android.message.fontFamily) || 'initial',
fontSize: (props.android && props.android.message && props.android.message.fontSize) || 15,
fontWeight: (props.android && props.android.message && props.android.message.fontWeight) || 'normal',
},
button: {
color: '#387ef5',
fontFamily: 'initial',
fontSize: 16,
fontWeight: '500',
textTransform: 'uppercase',
backgroundColor: 'transparent',
},
});
const AndroidButtonBox = () => {
const [buttonLayoutHorizontal, setButtonLayoutHorizontal] = useState(1);
const buttonProps = props.buttons && props.buttons.length > 0 ? props.buttons : [{}]
return (
<View style={[styles.androidButtonGroup, {
flexDirection: buttonLayoutHorizontal === 1 ? "row" : "column",
}]} onLayout={(e) => {
if(e.nativeEvent.layout.height > 60)
setButtonLayoutHorizontal(0);
}}>
{
buttonProps.map((item, index) => {
if(index > 2) return null;
const alignSelfProperty = buttonProps.length > 2 && index === 0 && buttonLayoutHorizontal === 1 ? 'flex-start' : 'flex-end';
let defaultButtonText = 'OK'
if(buttonProps.length > 2){
if(index === 0)
defaultButtonText = 'ASK ME LATER'
else if(index === 1)
defaultButtonText = 'CANCEL';
} else if (buttonProps.length === 2 && index === 0)
defaultButtonText = 'CANCEL';
return (
<View style={[styles.androidButton, index === 0 && buttonLayoutHorizontal === 1 ? {flex: 1} : {}]}>
<Pressable onPress={() => {
props.setModalVisible(false)
if(item.func && typeof(item.func) === 'function')
item.func();
}} style={[{
alignSelf: alignSelfProperty,
}]}>
<View style={[styles.androidButtonInner, {backgroundColor: (item.styles && item.styles.backgroundColor) || androidDefaults.button.backgroundColor}]}>
<Text
style={{
color: (item.styles && item.styles.color) || androidDefaults.button.color,
fontFamily: (item.styles && item.styles.fontFamily) || androidDefaults.button.fontFamily,
fontSize: (item.styles && item.styles.fontSize) || androidDefaults.button.fontSize,
fontWeight: (item.styles && item.styles.fontWeight) || androidDefaults.button.fontWeight,
textTransform: (item.styles && item.styles.textTransform) || androidDefaults.button.textTransform,
}}
>{item.text || defaultButtonText}</Text>
</View>
</Pressable>
</View>
)
})
}
</View>
);
}
return (
<Modal
animationType="fade"
transparent={true}
visible={props.modalVisible}
onRequestClose={() => {
props.setModalVisible(false);
}}
>
<Pressable style={[Platform.OS === "ios" ? styles.iOSBackdrop : styles.androidBackdrop, styles.backdrop]} onPress={() => props.setModalVisible(false)} />
<View style={styles.alertBox}>
{
Platform.OS === "ios" ?
null
:
<View style={[styles.androidAlertBox, androidDefaults.container]}>
<Text style={[styles.androidTitle, androidDefaults.title]}>{props.title || 'Message'}</Text>
<Text style={[styles.androidMessage, androidDefaults.message]}>{props.message || ''}</Text>
<AndroidButtonBox />
</View>
}
</View>
</Modal>
)
}
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View style={styles.centeredView}>
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Alert Title'}
message={'This is some message'}
android={{
container: {
backgroundColor: 'yellow'
},
title: {
color: 'red',
fontFamily: 'Roboto',
fontSize: 26,
fontWeight: 'regular',
},
message: {
color: 'blue',
fontFamily: 'Roboto',
fontSize: 16,
fontWeight: 'regular',
},
}}
buttons={[{
text: 'no'
},{
text: 'Yes',
func: () => {console.log('Yes Pressed')},
styles: {
color: '#FFFFFF',
fontSize: 18,
fontWeight: 'bold',
fontFamily: 'Roboto',
textTransform: 'none',
backgroundColor: '#000000'
}
}]}
/>
<View>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.textStyle}>Show Modal</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
iOSBackdrop: {
backgroundColor: "#000000",
opacity: 0.3
},
androidBackdrop: {
backgroundColor: "#232f34",
opacity: 0.4
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
alertBox: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
androidAlertBox: {
maxWidth: 280,
width: '100%',
margin: 48,
elevation: 24,
borderRadius: 2,
},
androidTitle: {
margin: 24,
},
androidMessage: {
marginLeft: 24,
marginRight: 24,
marginBottom: 24,
},
androidButtonGroup: {
marginTop: 0,
marginRight: 0,
marginBottom: 8,
marginLeft: 24,
},
androidButton: {
marginTop: 12,
marginRight: 8,
},
androidButtonInner: {
padding: 10,
}
});
export default App;
CustomAlert 的不同值的渲染输出是。

iOS自定义警报对话框
iOS警报框的代码将与Android类似,只是在样式上有所改变。
在iOS中,所有的实体如标题、信息和按钮都是居中对齐的。可以有任何数量的按钮。一个iOS和Android的CustomAlert 框的完整代码是。
import React, { useState } from "react";
import { Alert, Modal, StyleSheet, Text, Pressable, View, Platform } from "react-native";
const CustomAlert = (props) => {
const [androidDefaults, setAndroidDefaults] = useState({
container: {
backgroundColor: (props.android && props.android.container && props.android.container.backgroundColor) || '#FAFAFA',
},
title: {
color: (props.android && props.android.title && props.android.title.color) || '#000000',
fontFamily: (props.android && props.android.title && props.android.title.fontFamily) || 'initial',
fontSize: (props.android && props.android.title && props.android.title.fontSize) || 22,
fontWeight: (props.android && props.android.title && props.android.title.fontWeight) || 'bold',
},
message: {
color: (props.android && props.android.message && props.android.message.color) || '#000000',
fontFamily: (props.android && props.android.message && props.android.message.fontFamily) || 'initial',
fontSize: (props.android && props.android.message && props.android.message.fontSize) || 15,
fontWeight: (props.android && props.android.message && props.android.message.fontWeight) || 'normal',
},
button: {
color: '#387ef5',
fontFamily: 'initial',
fontSize: 16,
fontWeight: '500',
textTransform: 'uppercase',
backgroundColor: 'transparent',
},
});
const [iOSDefaults, setIOSDefaults] = useState({
container: {
backgroundColor: (props.ios && props.ios.container && props.ios.container.backgroundColor) || '#F8F8F8',
},
title: {
color: (props.ios && props.ios.title && props.ios.title.color) || '#000000',
fontFamily: (props.ios && props.ios.title && props.ios.title.fontFamily) || 'initial',
fontSize: (props.ios && props.ios.title && props.ios.title.fontSize) || 17,
fontWeight: (props.ios && props.ios.title && props.ios.title.fontWeight) || '600',
},
message: {
color: (props.ios && props.ios.message && props.ios.message.color) || '#000000',
fontFamily: (props.ios && props.ios.message && props.ios.message.fontFamily) || 'initial',
fontSize: (props.ios && props.ios.message && props.ios.message.fontSize) || 13,
fontWeight: (props.ios && props.ios.message && props.ios.message.fontWeight) || 'normal',
},
button: {
color: '#387ef5',
fontFamily: 'initial',
fontSize: 17,
fontWeight: '500',
textTransform: 'none',
backgroundColor: 'transparent',
},
});
const AndroidButtonBox = () => {
const [buttonLayoutHorizontal, setButtonLayoutHorizontal] = useState(1);
const buttonProps = props.buttons && props.buttons.length > 0 ? props.buttons : [{}]
return (
<View style={[styles.androidButtonGroup, {
flexDirection: buttonLayoutHorizontal === 1 ? "row" : "column",
}]} onLayout={(e) => {
if(e.nativeEvent.layout.height > 60)
setButtonLayoutHorizontal(0);
}}>
{
buttonProps.map((item, index) => {
if(index > 2) return null;
const alignSelfProperty = buttonProps.length > 2 && index === 0 && buttonLayoutHorizontal === 1 ? 'flex-start' : 'flex-end';
let defaultButtonText = 'OK'
if(buttonProps.length > 2){
if(index === 0)
defaultButtonText = 'ASK ME LATER'
else if(index === 1)
defaultButtonText = 'CANCEL';
} else if (buttonProps.length === 2 && index === 0)
defaultButtonText = 'CANCEL';
return (
<View style={[styles.androidButton, index === 0 && buttonLayoutHorizontal === 1 ? {flex: 1} : {}]}>
<Pressable onPress={() => {
props.setModalVisible(false)
if(item.func && typeof(item.func) === 'function')
item.func();
}} style={[{
alignSelf: alignSelfProperty,
}]}>
<View style={[styles.androidButtonInner, {backgroundColor: (item.styles && item.styles.backgroundColor) || androidDefaults.button.backgroundColor}]}>
<Text
style={{
color: (item.styles && item.styles.color) || androidDefaults.button.color,
fontFamily: (item.styles && item.styles.fontFamily) || androidDefaults.button.fontFamily,
fontSize: (item.styles && item.styles.fontSize) || androidDefaults.button.fontSize,
fontWeight: (item.styles && item.styles.fontWeight) || androidDefaults.button.fontWeight,
textTransform: (item.styles && item.styles.textTransform) || androidDefaults.button.textTransform,
}}
>{item.text || defaultButtonText}</Text>
</View>
</Pressable>
</View>
)
})
}
</View>
);
}
const IOSButtonBox = () => {
const buttonProps = props.buttons && props.buttons.length > 0 ? props.buttons : [{}]
const [buttonLayoutHorizontal, setButtonLayoutHorizontal] = useState(buttonProps.length === 2 ? 1 : 0);
return (
<View style={[styles.iOSButtonGroup, {
flexDirection: buttonLayoutHorizontal === 1 ? "row" : "column",
}]} onLayout={(e) => {
if(e.nativeEvent.layout.height > 60)
setButtonLayoutHorizontal(0);
}}>
{
buttonProps.map((item, index) => {
let defaultButtonText = 'OK'
if(buttonProps.length > 2){
if(index === 0)
defaultButtonText = 'ASK ME LATER'
else if(index === 1)
defaultButtonText = 'CANCEL';
} else if (buttonProps.length === 2 && index === 0)
defaultButtonText = 'CANCEL';
const singleButtonWrapperStyle = {}
let singleButtonWeight = iOSDefaults.button.fontWeight;
if(index === buttonProps.length - 1){
singleButtonWeight = '700';
}
if(buttonLayoutHorizontal === 1){
singleButtonWrapperStyle.minWidth = '50%';
if(index === 0){
singleButtonWrapperStyle.borderStyle = 'solid';
singleButtonWrapperStyle.borderRightWidth = 0.55;
singleButtonWrapperStyle.borderRightColor = '#dbdbdf';
}
}
return (
<View style={[styles.iOSButton, singleButtonWrapperStyle]}>
<Pressable onPress={() => {
props.setModalVisible(false)
if(item.func && typeof(item.func) === 'function')
item.func();
}}>
<View style={[styles.iOSButtonInner, {backgroundColor: (item.styles && item.styles.backgroundColor) || iOSDefaults.button.backgroundColor}]}>
<Text
style={{
color: (item.styles && item.styles.color) || iOSDefaults.button.color,
fontFamily: (item.styles && item.styles.fontFamily) || iOSDefaults.button.fontFamily,
fontSize: (item.styles && item.styles.fontSize) || iOSDefaults.button.fontSize,
fontWeight: (item.styles && item.styles.fontWeight) || singleButtonWeight,
textTransform: (item.styles && item.styles.textTransform) || iOSDefaults.button.textTransform,
textAlign: 'center'
}}
>{item.text || defaultButtonText}</Text>
</View>
</Pressable>
</View>
)
})
}
</View>
);
}
return (
<Modal
animationType="fade"
transparent={true}
visible={props.modalVisible}
onRequestClose={() => {
props.setModalVisible(false);
}}
>
<Pressable style={[Platform.OS === "ios" ? styles.iOSBackdrop : styles.androidBackdrop, styles.backdrop]} onPress={() => props.setModalVisible(false)} />
<View style={styles.alertBox}>
{
Platform.OS === "ios" ?
<View style={[styles.iOSAlertBox, iOSDefaults.container]}>
<Text style={[styles.iOSTitle, iOSDefaults.title]}>{props.title || 'Message'}</Text>
<Text style={[styles.iOSMessage, iOSDefaults.message]}>{props.message || ''}</Text>
<IOSButtonBox />
</View>
:
<View style={[styles.androidAlertBox, androidDefaults.container]}>
<Text style={[styles.androidTitle, androidDefaults.title]}>{props.title || 'Message'}</Text>
<Text style={[styles.androidMessage, androidDefaults.message]}>{props.message || ''}</Text>
<AndroidButtonBox />
</View>
}
</View>
</Modal>
)
}
const App = () => {
const [modalVisible, setModalVisible] = useState(false);
return (
<View style={styles.centeredView}>
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Alert Title'}
message={'This is some message'}
android={{
container: {
backgroundColor: 'yellow'
},
title: {
color: 'red',
fontFamily: 'Roboto',
fontSize: 26,
fontWeight: 'regular',
},
message: {
color: 'blue',
fontFamily: 'Roboto',
fontSize: 16,
fontWeight: 'regular',
},
}}
ios={{
container: {
backgroundColor: 'yellow'
},
title: {
color: 'red',
fontFamily: 'Roboto',
fontSize: 26,
fontWeight: 'regular',
},
message: {
color: 'blue',
fontFamily: 'Roboto',
fontSize: 16,
fontWeight: 'regular',
},
}}
buttons={[{
text: 'no'
},{
text: 'Yes',
func: () => {console.log('Yes Pressed')},
styles: {
color: '#FFFFFF',
fontSize: 18,
fontWeight: 'bold',
fontFamily: 'Roboto',
textTransform: 'none',
backgroundColor: '#000000'
}
}]}
/>
<View>
<Pressable
style={[styles.button, styles.buttonOpen]}
onPress={() => setModalVisible(true)}
>
<Text style={styles.textStyle}>Show Modal</Text>
</Pressable>
</View>
</View>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
button: {
borderRadius: 20,
padding: 10,
elevation: 2
},
buttonOpen: {
backgroundColor: "#F194FF",
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
iOSBackdrop: {
backgroundColor: "#000000",
opacity: 0.3
},
androidBackdrop: {
backgroundColor: "#232f34",
opacity: 0.4
},
backdrop: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
alertBox: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
androidAlertBox: {
maxWidth: 280,
width: '100%',
margin: 48,
elevation: 24,
borderRadius: 2,
},
androidTitle: {
margin: 24,
},
androidMessage: {
marginLeft: 24,
marginRight: 24,
marginBottom: 24,
},
androidButtonGroup: {
marginTop: 0,
marginRight: 0,
marginBottom: 8,
marginLeft: 24,
},
androidButton: {
marginTop: 12,
marginRight: 8,
},
androidButtonInner: {
padding: 10,
},
iOSAlertBox: {
maxWidth: 270,
width: '100%',
zIndex: 10,
borderRadius: 13,
},
iOSTitle: {
paddingTop: 12,
paddingRight: 16,
paddingBottom: 7,
paddingLeft: 16,
marginTop: 8,
textAlign: "center",
},
iOSMessage: {
paddingTop: 0,
paddingRight: 16,
paddingBottom: 21,
paddingLeft: 16,
textAlign: "center"
},
iOSButtonGroup: {
marginRight: -0.55
},
iOSButton: {
borderTopColor: '#dbdbdf',
borderTopWidth: 0.55,
borderStyle: 'solid',
},
iOSButtonInner: {
minHeight: 44,
justifyContent: 'center'
}
});
export default App;
不同的CustomAlert 值的渲染输出是。

现场演示
总结
在这篇文章中,我们了解了Android和iOS中的警报对话框。我们还看到了它们的用户界面、规格和属性之间的区别。
这些警报对话框有明确的目的,不应该被过度使用。只有当信息对用户来说是不可避免的时候才使用它们,因为它们会阻塞用户界面。
在我们的自定义警报中,有很多增强的范围。你可以改变填充物、边距、添加背景图片、图标、SVG等等。如果你在你的项目中试用这段代码,那么请通过评论让我知道它是如何工作的。谢谢你。
The postHow to create a custom alert dialog in React Nativeappeared first onLogRocket Blog.