ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-waterfall-flow — 瀑布流布局组件
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net📌:本文基于 React Native 0.72.90 版本进行开发适配。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配

🚀 一、开篇引言
瀑布流布局是现代移动应用中常见的展示方式,广泛应用于图片社交、电商商品展示、新闻资讯等场景。react-native-waterfall-flow 是 React Native 社区中轻量级的瀑布流组件,支持多列布局、下拉刷新、上拉加载等核心功能。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用这个实用的布局组件。
1.1 你将学到什么?
- ✅ waterfall-flow 的核心概念与工作原理
- ✅ HarmonyOS 平台的完整集成流程
- ✅ 瀑布流布局与数据渲染
- ✅ API 的深度解析
- ✅ 实际应用场景的最佳实践
1.2 适用人群
- 正在进行 React Native 鸿蒙化迁移的开发者
- 需要实现瀑布流布局的开发者
- 对跨平台列表组件开发感兴趣的技术爱好者
1.3 为什么选择 waterfall-flow?
| 特点 | 说明 |
|---|---|
| 轻量级 | 专注瀑布流布局,无冗余功能 |
| 跨平台一致 | iOS、Android、HarmonyOS 表现一致 |
| 简单易用 | API 类似 FlatList,学习成本低 |
| 功能实用 | 支持多列、刷新、加载更多 |
| 性能优秀 | 虚拟化列表,大数据量表现良好 |
📦 二、库概览
2.1 基本信息
| 项目 | 内容 |
|---|---|
| 库名称 | react-native-waterfall-flow |
| 版本信息 | 1.1.5 (RN 0.72/0.77) |
| 官方仓库 | https://github.com/axerjs/react-native-waterfall-flow |
| 开源协议 | MIT |
2.2 版本兼容性
| 三方库版本 | 支持RN版本 | 是否支持Autolink |
|---|---|---|
| 1.1.5 | 0.72/0.77 | Yes |
2.3 核心能力矩阵
| 能力项 | 描述 | HarmonyOS 支持 |
|---|---|---|
| 多列布局 | numColumns 属性 | ✅ 完全支持 |
| 列表渲染 | renderItem 方法 | ✅ 完全支持 |
| 下拉刷新 | onRefresh 属性 | ✅ 完全支持 |
| 上拉加载 | onEndReached 属性 | ✅ 完全支持 |
| 滚动控制 | scrollTo 系列方法 | ✅ 完全支持 |
| 头部/尾部组件 | ListHeader/Footer | ✅ 完全支持 |
2.4 技术架构图
2.5 典型应用场景
| 场景 | 描述 | 示例 |
|---|---|---|
| 图片社交 | 不规则图片展示 | 📷 小红书、Pinterest |
| 电商商品 | 商品列表展示 | 🛒 淘宝、京东商品列表 |
| 新闻资讯 | 图文混排资讯 | 📰 新闻客户端、博客 |
| 素材资源 | 设计素材展示 | 🎨 图标库、壁纸应用 |
🔧 三、环境准备
3.1 安装依赖
在项目根目录执行以下命令:
npm install react-native-waterfall-flow@1.1.5
或使用 yarn:
yarn add react-native-waterfall-flow@1.1.5
3.2 验证安装
安装完成后,检查 package.json 文件中是否包含以下依赖:
{
"dependencies": {
"react-native-waterfall-flow": "1.1.5"
}
}
3.3 添加类型声明
由于该库没有内置 TypeScript 类型定义,需要手动添加类型声明文件。
在 src/types 目录下创建 react-native-waterfall-flow.d.ts 文件:
declare module 'react-native-waterfall-flow' {
import { ComponentType, ReactElement, Component } from 'react';
import { ViewStyle } from 'react-native';
export interface WaterfallFlowProps<T = any> {
data: T[];
renderItem: (info: { item: T; index: number; column: number }) => ReactElement | null;
numColumns?: number;
ListHeaderComponent?: ComponentType | ReactElement | null;
ListFooterComponent?: ComponentType | ReactElement | null;
ListEmptyComponent?: ComponentType | ReactElement | null;
onEndReached?: () => void;
onRefresh?: () => void;
refreshing?: boolean;
style?: ViewStyle;
contentContainerStyle?: ViewStyle;
refreshControl?: ReactElement;
keyExtractor?: (item: T, index: number) => string;
onEndReachedThreshold?: number;
}
export default class WaterfallFlow<T = any> extends Component<WaterfallFlowProps<T>> {
scrollToEnd(params?: { animated?: boolean }): void;
scrollToIndex(params: { index: number; animated?: boolean; viewPosition?: number }): void;
scrollToItem(params: { item: any; animated?: boolean; viewPosition?: number }): void;
scrollToOffset(params: { offset: number; animated?: boolean }): void;
}
}
使用时需要正确定义数据类型和 ref:
import WaterfallFlow from 'react-native-waterfall-flow';
interface DataItem {
id: string;
title: string;
height: number;
}
const waterfallRef = useRef<WaterfallFlow<DataItem>>(null);
const renderItem = ({ item, index }: { item: DataItem; index: number }) => (
<View style={{ height: item.height }}>
<Text>{item.title}</Text>
</View>
);
⚙️ 四、原生配置
由于该库支持 Autolink,在 RN 0.72 版本下无需手动配置原生依赖。如果你的项目已接入 Autolink 框架,安装依赖后重新构建即可。
4.1 同步依赖
在 DevEco Studio 中点击右上角的 sync 按钮,或在命令行执行:
cd harmony/entry
ohpm install
📖 五、API 详解
5.1 核心属性
renderItem - 列表项渲染函数
用于渲染列表中的每一项,是瀑布流组件的核心属性。
方法签名:
renderItem: (info: { item: any, index: number, column: number }) => JSX.Element | null
参数说明:
| 参数名 | 类型 | 说明 |
|---|---|---|
| item | any | 当前项的数据 |
| index | number | 当前项在数据源中的索引 |
| column | number | 当前项所在的列索引(从0开始) |
示例:
const renderItem = ({ item, index, column }) => {
return (
<View style={[styles.item, { height: item.height }]}>
<Text>{item.title}</Text>
<Text>第 {column + 1} 列</Text>
</View>
);
};
data - 数据源
瀑布流的数据源,是一个数组,数组中的每个元素会作为 renderItem 的 item 参数传入。
类型: any[]
示例:
const data = [
{ id: '1', title: 'Item 1', height: 150 },
{ id: '2', title: 'Item 2', height: 200 },
{ id: '3', title: 'Item 3', height: 180 },
];
numColumns - 列数
指定瀑布流的列数,默认为 2 列。
类型: number
默认值: 2
示例:
<WaterfallFlow
data={data}
renderItem={renderItem}
numColumns={3}
/>
ListHeaderComponent - 头部组件
在列表顶部渲染的组件,可以是 React 组件或渲染函数。
类型: React.ComponentType | React.ReactElement | null
示例:
// 方式一:直接传入组件
<WaterfallFlow
ListHeaderComponent={<View><Text>列表头部</Text></View>}
/>
// 方式二:传入渲染函数
<WaterfallFlow
ListHeaderComponent={() => <View><Text>列表头部</Text></View>}
/>
ListFooterComponent - 尾部组件
在列表底部渲染的组件,常用于显示加载状态。
类型: React.ComponentType | React.ReactElement | null
示例:
<WaterfallFlow
ListFooterComponent={
<View style={styles.footer}>
<ActivityIndicator />
<Text>加载中...</Text>
</View>
}
/>
ListEmptyComponent - 空列表组件
当 data 为空数组时显示的组件。
类型: React.ComponentType | React.ReactElement | null
示例:
<WaterfallFlow
data={[]}
ListEmptyComponent={
<View style={styles.empty}>
<Text>暂无数据</Text>
</View>
}
/>
5.2 交互属性
onEndReached - 滚动到底部回调
当列表滚动到底部时触发,常用于实现"加载更多"功能。
类型: () => void
示例:
const [loading, setLoading] = useState(false);
const onEndReached = async () => {
if (loading) return;
setLoading(true);
const newData = await fetchMoreData();
setData([...data, ...newData]);
setLoading(false);
};
<WaterfallFlow
data={data}
renderItem={renderItem}
onEndReached={onEndReached}
/>
onRefresh - 下拉刷新回调
下拉刷新时触发的回调函数,需要配合 refreshing 属性使用。
类型: () => void
示例:
const [refreshing, setRefreshing] = useState(false);
const onRefresh = async () => {
setRefreshing(true);
const newData = await fetchNewData();
setData(newData);
setRefreshing(false);
};
<WaterfallFlow
data={data}
renderItem={renderItem}
onRefresh={onRefresh}
refreshing={refreshing}
/>
refreshing - 刷新状态
控制是否显示刷新指示器。
类型: boolean
默认值: false
5.3 样式属性
style - 外层容器样式
瀑布流外层容器的样式,默认有 { flex: 1 } 样式。
类型: ViewStyle
示例:
<WaterfallFlow
style={{ backgroundColor: '#f5f5f5' }}
/>
contentContainerStyle - 内容容器样式
瀑布流内容容器的样式,用于设置内边距等。
类型: ViewStyle
示例:
<WaterfallFlow
contentContainerStyle={{ padding: 10 }}
/>
5.4 静态方法
scrollToEnd - 滚动到底部
滚动到列表底部。
方法签名:
scrollToEnd(params?: { animated?: boolean }): void
参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| animated | boolean | 否 | 是否使用动画,默认 true |
示例:
const waterfallRef = useRef(null);
// 滚动到底部
waterfallRef.current?.scrollToEnd({ animated: true });
<WaterfallFlow ref={waterfallRef} />
scrollToIndex - 滚动到指定索引
将指定位置的元素滚动到可视区域。
方法签名:
scrollToIndex(params: {
index: number,
animated?: boolean,
viewPosition?: number
}): void
参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| index | number | 是 | 要滚动到的元素索引 |
| animated | boolean | 否 | 是否使用动画,默认 true |
| viewPosition | number | 否 | 元素在屏幕中的位置:0顶部/0.5居中/1底部 |
示例:
// 滚动到第 10 个元素,并显示在屏幕中央
waterfallRef.current?.scrollToIndex({
index: 10,
animated: true,
viewPosition: 0.5
});
scrollToOffset - 滚动到指定偏移
滚动到指定的偏移位置(像素)。
方法签名:
scrollToOffset(params: { offset: number, animated?: boolean }): void
参数说明:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| offset | number | 是 | 滚动的偏移量(像素) |
| animated | boolean | 否 | 是否使用动画,默认 true |
示例:
// 滚动到顶部
waterfallRef.current?.scrollToOffset({ offset: 0 });
🎯 六、属性详解
| 属性名 | 描述 | 类型 | 必填 | 默认值 | HarmonyOS 支持 |
|---|---|---|---|---|---|
| renderItem | 列表项渲染函数 | function | 是 | - | ✅ |
| data | 数据源 | array | 是 | - | ✅ |
| numColumns | 列数 | number | 否 | 2 | ✅ |
| ListHeaderComponent | 头部组件 | component | 否 | null | ✅ |
| ListFooterComponent | 尾部组件 | component | 否 | null | ✅ |
| ListEmptyComponent | 空列表组件 | component | 否 | null | ✅ |
| onEndReached | 滚动到底部回调 | function | 否 | - | ✅ |
| onRefresh | 下拉刷新回调 | function | 否 | - | ✅ |
| refreshing | 刷新状态 | boolean | 否 | false | ✅ |
| style | 外层容器样式 | object | 否 | {} | ✅ |
| contentContainerStyle | 内容容器样式 | object | 否 | {} | ✅ |
💡 七、使用示例
7.1 基础瀑布流
最简单的瀑布流实现,展示两列数据。
适用场景: 快速实现基础的瀑布流布局。
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import WaterfallFlow from 'react-native-waterfall-flow';
interface DataItem {
id: string;
title: string;
height: number;
}
const App = () => {
const data: DataItem[] = [
{ id: '1', title: 'Item 1', height: 120 },
{ id: '2', title: 'Item 2', height: 180 },
{ id: '3', title: 'Item 3', height: 150 },
{ id: '4', title: 'Item 4', height: 200 },
{ id: '5', title: 'Item 5', height: 140 },
{ id: '6', title: 'Item 6', height: 170 },
];
const renderItem = ({ item }: { item: DataItem }) => (
<View style={[styles.item, { height: item.height }]}>
<Text style={styles.text}>{item.title}</Text>
</View>
);
return (
<View style={styles.container}>
<WaterfallFlow
data={data}
renderItem={renderItem}
numColumns={2}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
item: {
margin: 5,
borderRadius: 8,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
},
text: { fontSize: 16, color: '#333' },
});
代码解析:
- 定义
DataItem接口描述数据类型 data数组中每个对象包含id、title和height属性renderItem使用类型注解{ item: DataItem }避免隐式 anynumColumns={2}设置为两列瀑布流
7.2 带下拉刷新和加载更多
完整的瀑布流交互实现,支持下拉刷新和上拉加载。
适用场景: 需要数据动态更新的场景,如图片社交、商品列表。
import React, { useState, useCallback } from 'react';
import {
View,
Text,
StyleSheet,
RefreshControl,
ActivityIndicator,
} from 'react-native';
import WaterfallFlow from 'react-native-waterfall-flow';
interface DataItem {
id: string;
title: string;
height: number;
}
function generateData(count: number, startId: number = 0): DataItem[] {
return Array.from({ length: count }, (_, i) => ({
id: `${startId + i + 1}`,
title: `Item ${startId + i + 1}`,
height: 100 + Math.random() * 150,
}));
}
const App = () => {
const [data, setData] = useState<DataItem[]>(generateData(10));
const [refreshing, setRefreshing] = useState(false);
const [loading, setLoading] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setData(generateData(10));
setRefreshing(false);
}, 1500);
}, []);
const onEndReached = useCallback(() => {
if (loading) return;
setLoading(true);
setTimeout(() => {
setData(prev => [...prev, ...generateData(5, prev.length)]);
setLoading(false);
}, 1000);
}, [loading]);
const renderItem = ({ item }: { item: DataItem }) => (
<View style={[styles.item, { height: item.height }]}>
<Text style={styles.text}>{item.title}</Text>
</View>
);
const ListFooterComponent = () => (
<View style={styles.footer}>
{loading && <ActivityIndicator color="#00d4ff" />}
<Text style={styles.footerText}>
{loading ? '加载中...' : '上拉加载更多'}
</Text>
</View>
);
return (
<View style={styles.container}>
<WaterfallFlow
data={data}
renderItem={renderItem}
numColumns={2}
onRefresh={onRefresh}
refreshing={refreshing}
onEndReached={onEndReached}
ListFooterComponent={ListFooterComponent}
contentContainerStyle={styles.content}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f5f5f5' },
content: { padding: 10 },
item: {
margin: 5,
borderRadius: 8,
backgroundColor: '#fff',
justifyContent: 'center',
alignItems: 'center',
},
text: { fontSize: 16, color: '#333' },
footer: { padding: 16, alignItems: 'center' },
footerText: { color: '#888', fontSize: 14 },
});
代码解析:
- 定义
DataItem接口和generateData函数类型 onRefresh实现下拉刷新,重置数据onEndReached实现上拉加载,追加新数据loading状态防止重复加载ListFooterComponent显示加载状态提示
7.3 图片瀑布流
模拟图片社交应用的瀑布流展示,带有图片加载效果。
适用场景: 图片社交、图库应用、壁纸应用。
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity,
} from 'react-native';
import WaterfallFlow from 'react-native-waterfall-flow';
interface ImageItem {
id: string;
url: string;
width: number;
height: number;
likes: number;
}
const IMAGE_DATA: ImageItem[] = [
{
id: '1',
url: 'https://picsum.photos/200/300?random=1',
width: 200,
height: 300,
likes: 128,
},
{
id: '2',
url: 'https://picsum.photos/200/200?random=2',
width: 200,
height: 200,
likes: 256,
},
];
const App = () => {
const [data, setData] = useState<ImageItem[]>(IMAGE_DATA);
const renderItem = ({ item, index }: { item: ImageItem; index: number }) => {
const imageHeight = (item.height / item.width) * 160;
return (
<TouchableOpacity
style={[styles.card, { height: imageHeight + 60 }]}
activeOpacity={0.9}
>
<Image
source={{ uri: item.url }}
style={[styles.image, { height: imageHeight }]}
resizeMode="cover"
/>
<View style={styles.cardFooter}>
<Text style={styles.likes}>❤️ {item.likes}</Text>
</View>
</TouchableOpacity>
);
};
return (
<View style={styles.container}>
<WaterfallFlow
data={data}
renderItem={renderItem}
numColumns={2}
contentContainerStyle={styles.content}
/>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#1a1a2e' },
content: { padding: 8 },
card: {
margin: 4,
borderRadius: 12,
backgroundColor: '#16213e',
overflow: 'hidden',
},
image: { width: '100%' },
cardFooter: {
padding: 10,
flexDirection: 'row',
justifyContent: 'flex-end',
},
likes: { color: '#fff', fontSize: 14 },
});
代码解析:
- 定义
ImageItem接口描述图片数据类型 - 根据图片宽高比动态计算显示高度
- 使用
TouchableOpacity实现点击交互 - 卡片包含图片和点赞数信息
❓ 八、常见问题
8.1 常见问题解答
Q1: 瀑布流高度不一致怎么办?
A: 瀑布流组件会自动根据内容高度进行布局,确保每个 item 的高度是根据内容动态计算的。
Q2: 如何实现三列或更多列?
A: 通过 numColumns 属性设置列数,如 numColumns={3}。
Q3: 下拉刷新不生效?
A: 确保同时设置了 onRefresh 和 refreshing 两个属性。
Q4: 如何滚动到指定位置?
A: 使用 ref 获取组件实例,调用 scrollToIndex 或 scrollToOffset 方法。
Q5: 性能优化建议?
A:
- 避免在 renderItem 中进行复杂计算
- 使用 keyExtractor 优化列表更新
- 合理使用 onEndReachedThreshold 控制加载时机
8.2 最佳实践
- 唯一标识:确保 data 中每项都有唯一的 id
- 防抖加载:在 onEndReached 中添加 loading 状态防止重复加载
- 合理分页:每次加载适量数据,避免一次性加载过多
- 图片优化:使用合适的图片尺寸,避免加载过大的图片
💻 九、完整示例代码
import React, { useState, useRef, useCallback } from 'react';
import {
View,
Text,
StyleSheet,
SafeAreaView,
TouchableOpacity,
RefreshControl,
ActivityIndicator,
Dimensions,
} from 'react-native';
import WaterfallFlow from 'react-native-waterfall-flow';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
const CARD_WIDTH = (SCREEN_WIDTH - 40) / 2;
const COLORS = [
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4',
'#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F',
];
function generateData(count: number, startId: number = 0) {
return Array.from({ length: count }, (_, i) => ({
id: `${startId + i + 1}`,
title: `卡片 ${startId + i + 1}`,
description: `这是第 ${startId + i + 1} 个卡片的内容描述`,
height: 120 + Math.random() * 100,
color: COLORS[Math.floor(Math.random() * COLORS.length)],
likes: Math.floor(Math.random() * 1000),
}));
}
export default function App() {
const [data, setData] = useState(generateData(12));
const [refreshing, setRefreshing] = useState(false);
const [loading, setLoading] = useState(false);
const waterfallRef = useRef(null);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setData(generateData(12));
setRefreshing(false);
}, 1500);
}, []);
const onEndReached = useCallback(() => {
if (loading) return;
setLoading(true);
setTimeout(() => {
setData(prev => [...prev, ...generateData(6, prev.length)]);
setLoading(false);
}, 1000);
}, [loading]);
const scrollToTop = () => {
waterfallRef.current?.scrollToOffset({ offset: 0, animated: true });
};
const scrollToEnd = () => {
waterfallRef.current?.scrollToEnd({ animated: true });
};
const renderItem = ({ item, index }) => (
<TouchableOpacity
style={[styles.card, { height: item.height }]}
activeOpacity={0.9}
>
<View style={[styles.cardHeader, { backgroundColor: item.color }]}>
<Text style={styles.cardIndex}>#{index + 1}</Text>
</View>
<View style={styles.cardContent}>
<Text style={styles.cardTitle}>{item.title}</Text>
<Text style={styles.cardDesc} numberOfLines={2}>
{item.description}
</Text>
</View>
<View style={styles.cardFooter}>
<Text style={styles.likes}>❤️ {item.likes}</Text>
</View>
</TouchableOpacity>
);
const ListHeaderComponent = () => (
<View style={styles.header}>
<Text style={styles.headerTitle}>瀑布流展示</Text>
<Text style={styles.headerSubtitle}>共 {data.length} 个项目</Text>
</View>
);
const ListFooterComponent = () => (
<View style={styles.footer}>
{loading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator color="#00d4ff" />
<Text style={styles.loadingText}>加载中...</Text>
</View>
) : (
<Text style={styles.footerText}>上拉加载更多</Text>
)}
</View>
);
return (
<SafeAreaView style={styles.container}>
<View style={styles.titleBar}>
<Text style={styles.title}>瀑布流布局</Text>
</View>
<WaterfallFlow
ref={waterfallRef}
data={data}
renderItem={renderItem}
numColumns={2}
ListHeaderComponent={ListHeaderComponent}
ListFooterComponent={ListFooterComponent}
onEndReached={onEndReached}
onRefresh={onRefresh}
refreshing={refreshing}
contentContainerStyle={styles.content}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={['#00d4ff']}
tintColor="#00d4ff"
/>
}
/>
<View style={styles.bottomBar}>
<TouchableOpacity style={styles.actionButton} onPress={scrollToTop}>
<Text style={styles.actionButtonText}>回到顶部</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.actionButton} onPress={scrollToEnd}>
<Text style={styles.actionButtonText}>滚动到底部</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1a1a2e',
},
titleBar: {
padding: 16,
backgroundColor: '#16213e',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#fff',
textAlign: 'center',
},
content: {
paddingHorizontal: 8,
paddingBottom: 16,
},
header: {
padding: 16,
alignItems: 'center',
},
headerTitle: {
fontSize: 20,
fontWeight: 'bold',
color: '#fff',
},
headerSubtitle: {
fontSize: 14,
color: '#888',
marginTop: 4,
},
card: {
margin: 4,
borderRadius: 12,
backgroundColor: '#16213e',
overflow: 'hidden',
},
cardHeader: {
height: 40,
justifyContent: 'center',
alignItems: 'center',
},
cardIndex: {
fontSize: 16,
fontWeight: 'bold',
color: '#fff',
},
cardContent: {
padding: 12,
flex: 1,
},
cardTitle: {
fontSize: 16,
fontWeight: '600',
color: '#fff',
marginBottom: 4,
},
cardDesc: {
fontSize: 12,
color: '#888',
lineHeight: 18,
},
cardFooter: {
padding: 10,
borderTopWidth: 1,
borderTopColor: '#2a2a4a',
flexDirection: 'row',
justifyContent: 'flex-end',
},
likes: {
fontSize: 12,
color: '#00d4ff',
},
footer: {
padding: 16,
alignItems: 'center',
},
loadingContainer: {
flexDirection: 'row',
alignItems: 'center',
},
loadingText: {
marginLeft: 8,
color: '#888',
},
footerText: {
color: '#666',
fontSize: 14,
},
bottomBar: {
flexDirection: 'row',
padding: 12,
backgroundColor: '#16213e',
gap: 12,
},
actionButton: {
flex: 1,
backgroundColor: '#00d4ff',
paddingVertical: 12,
borderRadius: 8,
alignItems: 'center',
},
actionButtonText: {
fontSize: 14,
fontWeight: '600',
color: '#1a1a2e',
},
});
🔗 十、相关资源
更多推荐


所有评论(0)