高级进阶 React Native 鸿蒙跨平台开发:react-native-shadow-2 立体效果

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📋 前言
react-native-shadow-2 是一个功能强大的阴影效果库,它为 React Native 应用提供了丰富多样的立体阴影效果。该库基于 SVG 技术实现,支持渐变阴影、自定义阴影方向、选择性阴影渲染等高级特性,能够轻松创建出精美的立体视觉效果。该库支持 Android、iOS 和 HarmonyOS 三端,为跨平台应用开发提供了统一的阴影效果解决方案,特别适合需要增强 UI 视觉深度的场景,如粒子立体效果、卡片悬浮、按钮立体感等。
🎯 库简介
基本信息
-
库名称: react-native-shadow-2
-
版本信息:
7.0.8: 支持 RN 0.72 版本7.1.1: 支持 RN 0.77 版本
-
官方仓库: https://github.com/SrBrahma/react-native-shadow-2
-
主要功能:
- 渐变阴影:支持 startColor 和 endColor 实现渐变阴影效果
- 自定义距离:精确控制阴影的延伸距离
- 阴影偏移:支持水平和垂直方向的阴影偏移
- 选择性渲染:可选择性渲染特定边或角的阴影
- 内部阴影:支持内容内部的阴影效果
- 安全渲染:处理特殊形状的首屏渲染问题
- 动态控制:支持动态启用/禁用阴影效果
-
依赖关系: 依赖
react-native-svg库,需要先配置 SVG 支持 -
兼容性验证: 该第三方库支持直接从 npm 下载,完整支持 HarmonyOS 平台
为什么需要这个库?
- 视觉效果: 提供丰富的立体阴影效果,增强 UI 视觉深度
- 渐变支持: 支持渐变阴影,比原生 shadowColor 更灵活
- 精确控制: 精确控制阴影的方向、距离、颜色等属性
- 跨平台: 支持 Android、iOS、HarmonyOS 三端,统一的 API
- 高性能: 基于 SVG 实现,性能优异
- 易于使用: API 设计简洁明了,易于集成和使用
- 鸿蒙支持: 完整支持 HarmonyOS 平台,实现真正的跨平台
📦 安装步骤
1. 使用 npm 安装
根据您的 RN 版本选择对应的包名:
RN 0.72 版本:
npm install react-native-shadow-2@7.0.8
RN 0.77 版本:
npm install react-native-shadow-2@7.1.1
2. 验证安装
安装完成后,检查 package.json 文件,应该能看到新增的依赖:
{
"dependencies": {
"react-native-shadow-2": "^7.0.8",
// ... 其他依赖
}
}
🔧 HarmonyOS 平台配置 ⭐
1. 配置 react-native-svg(必需依赖)⭐⭐⭐
[!WARNING] react-native-shadow-2 依赖 react-native-svg,必须先配置 react-native-svg!
本库 HarmonyOS 侧实现依赖 react-native-svg 的原生端代码,如已在 HarmonyOS 工程中引入过该库,则无需再次引入,可跳过本章节步骤,直接使用。
如未引入请参照这篇文章进行配置:
2. 无需额外配置
[!TIP] react-native-shadow-2 是纯 JavaScript 库,无需额外的原生端配置!
配置完 react-native-svg 后,react-native-shadow-2 可以直接使用,无需额外的原生端配置。
💻 完整代码示例
下面是一个完整的示例,展示了如何使用 react-native-shadow-2 实现粒子立体效果:
import React, { useState } from 'react';
import {
View,
StyleSheet,
Text,
ScrollView,
TouchableOpacity,
SafeAreaView,
Animated,
} from 'react-native';
import { Shadow } from 'react-native-shadow-2';
interface ShadowConfig {
startColor: string;
endColor: string;
distance: number;
offset: [number, number];
paintInside: boolean;
sides: {
start: boolean;
end: boolean;
top: boolean;
bottom: boolean;
};
corners: {
topStart: boolean;
topEnd: boolean;
bottomStart: boolean;
bottomEnd: boolean;
};
}
function ShadowDemo() {
const [activeTab, setActiveTab] = useState<'particles' | 'cards' | 'buttons'>('particles');
return (
<SafeAreaView style={styles.container}>
{/* 标题区域 */}
<View style={styles.header}>
<Text style={styles.headerTitle}>立体效果演示</Text>
<Text style={styles.headerSubtitle}>react-native-shadow-2</Text>
</View>
{/* 标签切换 */}
<View style={styles.tabContainer}>
<TouchableOpacity
style={[styles.tab, activeTab === 'particles' && styles.activeTab]}
onPress={() => setActiveTab('particles')}
>
<Text style={[styles.tabText, activeTab === 'particles' && styles.activeTabText]}>
粒子立体
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tab, activeTab === 'cards' && styles.activeTab]}
onPress={() => setActiveTab('cards')}
>
<Text style={[styles.tabText, activeTab === 'cards' && styles.activeTabText]}>
卡片悬浮
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tab, activeTab === 'buttons' && styles.activeTab]}
onPress={() => setActiveTab('buttons')}
>
<Text style={[styles.tabText, activeTab === 'buttons' && styles.activeTabText]}>
按钮立体
</Text>
</TouchableOpacity>
</View>
{/* 内容区域 */}
<ScrollView style={styles.content}>
{activeTab === 'particles' && <ParticleShadows />}
{activeTab === 'cards' && <CardShadows />}
{activeTab === 'buttons' && <ButtonShadows />}
</ScrollView>
</SafeAreaView>
);
}
// 粒子立体效果
const ParticleShadows = () => {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>粒子立体效果</Text>
{/* 基础粒子 */}
<View style={styles.demoRow}>
<Text style={styles.label}>基础粒子</Text>
<Shadow
distance={10}
startColor="#409EFF40"
endColor="#409EFF00"
>
<View style={styles.particle} />
</Shadow>
</View>
{/* 渐变粒子 */}
<View style={styles.demoRow}>
<Text style={styles.label}>渐变粒子</Text>
<Shadow
distance={15}
startColor="#67C23A80"
endColor="#67C23A00"
>
<View style={[styles.particle, { backgroundColor: '#67C23A' }]} />
</Shadow>
</View>
{/* 大距离粒子 */}
<View style={styles.demoRow}>
<Text style={styles.label}>大距离粒子</Text>
<Shadow
distance={25}
startColor="#E6A23C60"
endColor="#E6A23C00"
>
<View style={[styles.particle, { backgroundColor: '#E6A23C' }]} />
</Shadow>
</View>
{/* 底部阴影 */}
<View style={styles.demoRow}>
<Text style={styles.label}>底部阴影</Text>
<Shadow
distance={20}
sides={{ start: false, end: false, top: false, bottom: true }}
startColor="#F56C6C80"
endColor="#F56C6C00"
>
<View style={[styles.particle, { backgroundColor: '#F56C6C' }]} />
</Shadow>
</View>
{/* 强阴影粒子 */}
<View style={styles.demoRow}>
<Text style={styles.label}>强阴影粒子</Text>
<Shadow
distance={15}
startColor="#90939960"
endColor="#90939900"
>
<View style={[styles.particle, { backgroundColor: '#909399' }]} />
</Shadow>
</View>
{/* 轻阴影粒子 */}
<View style={styles.demoRow}>
<Text style={styles.label}>轻阴影粒子</Text>
<Shadow
distance={5}
startColor="#409EFF20"
endColor="#409EFF00"
>
<View style={[styles.particle, { backgroundColor: '#409EFF' }]} />
</Shadow>
</View>
</View>
);
};
// 卡片悬浮效果
const CardShadows = () => {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>卡片悬浮效果</Text>
{/* 基础卡片 */}
<View style={styles.cardContainer}>
<Text style={styles.label}>基础卡片</Text>
<Shadow
distance={20}
startColor="#00000020"
endColor="#00000000"
>
<View style={styles.card}>
<Text style={styles.cardTitle}>基础卡片</Text>
<Text style={styles.cardText}>这是一个基础的悬浮卡片效果</Text>
</View>
</Shadow>
</View>
{/* 彩色卡片 */}
<View style={styles.cardContainer}>
<Text style={styles.label}>彩色卡片</Text>
<Shadow
distance={25}
startColor="#409EFF60"
endColor="#409EFF00"
>
<View style={[styles.card, { backgroundColor: '#409EFF' }]}>
<Text style={[styles.cardTitle, { color: '#FFFFFF' }]}>彩色卡片</Text>
<Text style={[styles.cardText, { color: '#FFFFFF' }]}>这是一个彩色的悬浮卡片</Text>
</View>
</Shadow>
</View>
{/* 大阴影卡片 */}
<View style={styles.cardContainer}>
<Text style={styles.label}>大阴影卡片</Text>
<Shadow
distance={40}
startColor="#00000030"
endColor="#00000000"
>
<View style={styles.card}>
<Text style={styles.cardTitle}>大阴影卡片</Text>
<Text style={styles.cardText}>这是一个大阴影的悬浮卡片</Text>
</View>
</Shadow>
</View>
{/* 绿色卡片 */}
<View style={styles.cardContainer}>
<Text style={styles.label}>绿色卡片</Text>
<Shadow
distance={20}
startColor="#67C23A60"
endColor="#67C23A00"
>
<View style={[styles.card, { backgroundColor: '#67C23A' }]}>
<Text style={[styles.cardTitle, { color: '#FFFFFF' }]}>绿色卡片</Text>
<Text style={[styles.cardText, { color: '#FFFFFF' }]}>这是一个绿色的悬浮卡片</Text>
</View>
</Shadow>
</View>
</View>
);
};
// 按钮立体效果
const ButtonShadows = () => {
return (
<View style={styles.section}>
<Text style={styles.sectionTitle}>按钮立体效果</Text>
{/* 基础按钮 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>基础按钮</Text>
<Shadow
distance={8}
startColor="#409EFF40"
endColor="#409EFF00"
>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>基础按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
{/* 强阴影按钮 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>强阴影按钮</Text>
<Shadow
distance={12}
startColor="#409EFF60"
endColor="#409EFF00"
>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>强阴影按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
{/* 轻阴影按钮 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>轻阴影按钮</Text>
<Shadow
distance={5}
startColor="#00000020"
endColor="#00000000"
>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>轻阴影按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
{/* 渐变按钮 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>渐变按钮</Text>
<Shadow
distance={15}
startColor="#E6A23C60"
endColor="#E6A23C00"
>
<TouchableOpacity style={[styles.button, { backgroundColor: '#E6A23C' }]}>
<Text style={styles.buttonText}>渐变按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
{/* 红色按钮 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>红色按钮</Text>
<Shadow
distance={10}
startColor="#F56C6C50"
endColor="#F56C6C00"
>
<TouchableOpacity style={[styles.button, { backgroundColor: '#F56C6C' }]}>
<Text style={styles.buttonText}>红色按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
{/* 禁用状态 */}
<View style={styles.buttonContainer}>
<Text style={styles.label}>禁用状态</Text>
<Shadow
distance={8}
startColor="#409EFF40"
endColor="#409EFF00"
disabled={true}
>
<TouchableOpacity style={[styles.button, styles.disabledButton]} disabled={true}>
<Text style={[styles.buttonText, { color: '#C0C4CC' }]}>禁用按钮</Text>
</TouchableOpacity>
</Shadow>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5F7FA',
},
header: {
padding: 20,
backgroundColor: '#FFFFFF',
borderBottomWidth: 1,
borderBottomColor: '#EBEEF5',
},
headerTitle: {
fontSize: 24,
fontWeight: '700',
color: '#303133',
textAlign: 'center',
marginBottom: 8,
},
headerSubtitle: {
fontSize: 16,
fontWeight: '500',
color: '#909399',
textAlign: 'center',
},
tabContainer: {
flexDirection: 'row',
backgroundColor: '#FFFFFF',
borderBottomWidth: 1,
borderBottomColor: '#EBEEF5',
},
tab: {
flex: 1,
paddingVertical: 16,
alignItems: 'center',
},
activeTab: {
borderBottomWidth: 2,
borderBottomColor: '#409EFF',
},
tabText: {
fontSize: 16,
fontWeight: '500',
color: '#909399',
},
activeTabText: {
color: '#409EFF',
fontWeight: '600',
},
content: {
flex: 1,
padding: 16,
},
section: {
marginBottom: 20,
},
sectionTitle: {
fontSize: 20,
fontWeight: '600',
color: '#303133',
marginBottom: 16,
},
demoRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 20,
backgroundColor: '#FFFFFF',
padding: 16,
borderRadius: 8,
},
label: {
fontSize: 14,
fontWeight: '500',
color: '#606266',
width: 80,
},
particle: {
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: '#409EFF',
},
cardContainer: {
marginBottom: 20,
},
card: {
backgroundColor: '#FFFFFF',
borderRadius: 12,
padding: 20,
shadowColor: '#000000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4,
},
cardTitle: {
fontSize: 18,
fontWeight: '600',
color: '#303133',
marginBottom: 8,
},
cardText: {
fontSize: 14,
color: '#606266',
lineHeight: 20,
},
buttonContainer: {
marginBottom: 20,
},
button: {
backgroundColor: '#409EFF',
borderRadius: 8,
paddingVertical: 12,
paddingHorizontal: 24,
alignItems: 'center',
},
roundButton: {
width: 80,
height: 80,
borderRadius: 40,
justifyContent: 'center',
},
disabledButton: {
backgroundColor: '#F5F7FA',
},
buttonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
});
export default ShadowDemo;
🎨 实际应用场景
完整示例代码已展示了以下实际应用场景:
- 粒子立体效果: 为粒子添加立体阴影,增强视觉深度
- 卡片悬浮效果: 为卡片添加悬浮阴影,提升交互体验
- 按钮立体效果: 为按钮添加立体阴影,增强可点击感
- 渐变阴影: 使用 startColor 和 endColor 实现渐变阴影效果
- 选择性阴影: 使用 sides 和 corners 属性选择性渲染阴影
- 内部阴影: 使用 paintInside 实现内部阴影效果
- 安全渲染: 使用 safeRender 处理特殊形状的首屏渲染
⚠️ 注意事项与最佳实践
1. 配置 react-native-svg(重要)
[!WARNING] react-native-shadow-2 依赖 react-native-svg,必须先配置 react-native-svg!
# 安装 react-native-svg
npm install react-native-svg
# 按照 react-native-svg 文档配置原生端代码
2. 阴影颜色使用
使用带透明度的颜色值,避免阴影过于突兀:
// 正确:使用带透明度的颜色
<Shadow
startColor="#409EFF40"
endColor="#409EFF00"
>
<View style={styles.box} />
</Shadow>
// 错误:使用不透明颜色
<Shadow
startColor="#409EFF"
endColor="#409EFF"
>
<View style={styles.box} />
</Shadow>
3. distance 参数配置
合理设置 distance 参数,避免阴影过大或过小:
// 小阴影:适合小元素
<Shadow distance={8}>
// 中等阴影:适合卡片、按钮
<Shadow distance={15}>
// 大阴影:适合强调元素
<Shadow distance={30}>
4. offset 参数使用
使用 offset 参数实现特定方向的阴影效果:
// 向下偏移:悬浮效果
<Shadow offset={[0, 4]} distance={8}>
// 向上偏移:凹陷效果
<Shadow offset={[0, -4]} distance={8}>
// 对角偏移:立体效果
<Shadow offset={[5, 5]} distance={12}>
5. 鸿蒙端限制(重要)
[!WARNING] 由于 react-native-shadow-2 强依赖 react-native-svg,但 react-native-svg 鸿蒙端目前仅实现少部分属性,导致以下属性在鸿蒙端不可用:
- ❌ offset: 阴影偏移(水平和垂直)
- ❌ paintInside: 内部阴影
- ❌ corners: 角落选择性渲染
解决方案: 仅使用以下鸿蒙端支持的属性:
// ✅ 鸿蒙端支持的属性
<Shadow
distance={10} // ✅ 支持
startColor="#409EFF40" // ✅ 支持
endColor="#409EFF00" // ✅ 支持
sides={{...}} // ✅ 支持(不含 corners)
style={{...}} // ✅ 支持
containerStyle={{...}} // ✅ 支持
stretch={true} // ✅ 支持
safeRender={true} // ✅ 支持
disabled={false} // ✅ 支持
>
<View style={styles.box} />
</Shadow>
// ❌ 鸿蒙端不支持的属性
<Shadow
offset={[5, 5]} // ❌ 不可用
paintInside={true} // ❌ 不可用
corners={{...}} // ❌ 不可用
>
<View style={styles.box} />
</Shadow>
6. sides 选择性渲染
使用 sides 属性选择性渲染特定边的阴影:
// 仅底部阴影
<Shadow
sides={{ start: false, end: false, top: false, bottom: true }}
>
// 左右阴影
<Shadow
sides={{ start: true, end: true, top: false, bottom: false }}
>
// 顶部和底部阴影
<Shadow
sides={{ start: false, end: false, top: true, bottom: true }}
>
7. corners 选择性渲染
使用 corners 属性选择性渲染特定角的阴影:
// 对角阴影
<Shadow
corners={{
topStart: true,
topEnd: false,
bottomStart: false,
bottomEnd: true,
}}
>
// 顶部阴影
<Shadow
corners={{
topStart: true,
topEnd: true,
bottomStart: false,
bottomEnd: false,
}}
>
7. corners 选择性渲染(鸿蒙端不可用)
[!WARNING] corners 属性在鸿蒙端不可用,请勿使用!
// ❌ 鸿蒙端不可用
<Shadow
corners={{
topStart: true,
topEnd: false,
bottomStart: false,
bottomEnd: true,
}}
>
<View style={styles.box} />
</Shadow>
如需实现类似效果,可以考虑使用原生 shadow 属性或等待 react-native-svg 鸿蒙端完整实现。
8. safeRender 使用
对于圆形或其他特殊形状,使用 safeRender 避免首屏渲染问题:
<Shadow
safeRender={true}
distance={10}
>
<View style={styles.circle} />
</Shadow>
9. disabled 状态
使用 disabled 属性动态控制阴影效果:
const [disabled, setDisabled] = useState(false);
<Shadow disabled={disabled}>
<TouchableOpacity style={styles.button}>
<Text>按钮</Text>
</TouchableOpacity>
</Shadow>
10. 性能优化
避免在列表中使用过多的 Shadow 组件,影响性能:
// 不推荐:每个列表项都使用 Shadow
<FlatList
data={items}
renderItem={({ item }) => (
<Shadow>
<View style={styles.item} />
</Shadow>
)}
/>
// 推荐:仅对重要元素使用 Shadow
<FlatList
data={items}
renderItem={({ item }) => (
<View style={styles.item} />
)}
/>
11. 版本兼容性
根据 RN 版本选择对应的库版本:
| RN 版本 | 库版本 |
|---|---|
| 0.72 | 7.0.8 |
| 0.77 | 7.1.1 |
📊 对比:原生 shadow vs react-native-shadow-2
| 特性 | 原生 shadow | react-native-shadow-2 |
|---|---|---|
| 渐变阴影 | ❌ 不支持 | ✅ 支持 |
| 选择性渲染 | ❌ 不支持 | ✅ 支持 |
| 内部阴影 | ❌ 不支持 | ✅ 支持 |
| 阴影偏移 | ⚠️ 仅支持垂直 | ✅ 支持水平和垂直 |
| 角落控制 | ❌ 不支持 | ✅ 支持 |
| 性能 | ✅ 最佳 | ✅ 优秀 |
| 使用复杂度 | ✅ 简单 | ⚠️ 中等 |
| 视觉效果 | ⚠️ 基础 | ✅ 丰富 |
📝 总结
通过集成 react-native-shadow-2,我们为项目添加了强大的立体阴影效果能力。这个库基于 SVG 技术实现,提供了丰富多样的阴影效果,可以轻松创建出精美的立体视觉效果,大大提升了应用的视觉体验。
关键要点回顾
- ✅ 安装依赖:
npm install react-native-shadow-2 - ✅ 配置 SVG: 必须先配置 react-native-svg
- ✅ 集成代码: 使用 Shadow 组件提供的各种属性
- ✅ 支持功能: 渐变阴影、选择性渲染、内部阴影、安全渲染等
- ✅ 测试验证: 确保三端表现一致
- ✅ 重要提醒: 本库依赖 react-native-svg,必须先配置 SVG 支持
常用属性快速参考
// 基础阴影
<Shadow distance={10}>
<View style={styles.box} />
</Shadow>
// 渐变阴影
<Shadow
startColor="#409EFF40"
endColor="#409EFF00"
distance={15}
>
<View style={styles.box} />
</Shadow>
// 大距离阴影
<Shadow
distance={25}
>
<View style={styles.box} />
</Shadow>
// 注意:offset 属性在鸿蒙端不可用
// 选择性边阴影
<Shadow
sides={{ start: false, end: false, top: false, bottom: true }}
>
<View style={styles.box} />
</Shadow>
// 选择性边阴影
<Shadow
sides={{ start: false, end: false, top: false, bottom: true }}
>
<View style={styles.box} />
</Shadow>
// 注意:corners 属性在鸿蒙端不可用
// 安全渲染
<Shadow
safeRender={true}
distance={10}
>
<View style={styles.circle} />
</Shadow>
// 禁用阴影
<Shadow disabled={true}>
<View style={styles.box} />
</Shadow>
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)