@gaozh1024/rn-kit
v0.4.15
Published
Panther Expo Framework - All-in-one React Native framework
Maintainers
Readme
@gaozh1024/rn-kit
Panther Expo Framework - All-in-one React Native framework
一个集成的 React Native 开发框架,包含主题系统、UI 组件、API 工厂和导航组件。
✅ 推荐初始化方式
业务 App 推荐优先使用 AppProvider,而不是只手动包一层 ThemeProvider。
AppProvider 默认会整合:
SafeAreaProviderThemeProviderNavigationProviderOverlayProviderAppStatusBar
另外在开发环境下,AppProvider 默认会启用一套轻量的开发日志基础设施:
LoggerProvider- CLI 彩色日志输出
- App 内
LogOverlay浮层 AppErrorBoundaryReact 渲染错误兜底
这样页面切换、主题切换时,状态栏会自动跟随全局主题变化。
📦 安装
npm install @gaozh1024/rn-kit
# 或
pnpm add @gaozh1024/rn-kit
# 或
yarn add @gaozh1024/rn-kit前置依赖
Expo 项目(推荐)
如果你使用的是 Expo,请优先使用 expo install,让 Expo 按当前 SDK 自动选择兼容版本:
npx expo install react-native-screens react-native-safe-area-context
npx expo install react-native-gesture-handler react-native-reanimated
npx expo install @expo/vector-icons expo-linear-gradient
npm install react-native-svg如果你的项目是 Expo SDK 54 / React Native 0.81,还需要:
npx expo install react-native-worklets注意:Expo SDK 54 对应的是 React Native 0.81,不是 0.79。 如果你的项目是 React Native 0.79,通常对应 Expo SDK 53 一档,请不要直接按 SDK 54 的版本理解依赖关系。
非 Expo / 手动安装
npm install react react-native
npm install react-native-screens react-native-safe-area-context
npm install react-native-gesture-handler react-native-reanimated
npm install @expo/vector-icons expo-linear-gradient
npm install react-native-svg当前兼容性范围
0.4.3 当前将 peerDependencies 收紧到以下范围,避免 npm 解析到和当前 RN 不兼容的过高版本:
expo:>=53 <55react-native:>=0.79 <0.82react-native-reanimated:>=3.17.0 <5react-native-worklets:>=0.5.0 <0.6.0(可选)
如果你在 Expo 项目中安装依赖,建议顺序是:
npx expo install react-native-screens react-native-safe-area-context
npx expo install react-native-gesture-handler react-native-reanimated
npx expo install @expo/vector-icons expo-linear-gradient expo-image
npx expo install react-native-worklets
npm install @gaozh1024/rn-kit如果你是 Expo SDK 53 / RN 0.79 项目,通常不需要单独安装 react-native-worklets,以 expo install 给出的结果为准。
从
rn-kit 0.4.6开始,AppImage基于expo-image实现。 新建模板项目通常已内置,无需重复安装;旧项目升级到rn-kit >= 0.4.6时,请执行npx expo install expo-image。
⚠️ 样式配置(必看)
本框架使用 Tailwind CSS 类名实现样式(如 bg-primary-500, flex-1, p-4),需要在你的项目中配置 NativeWind 才能正常显示样式。
如果你发现 AppHeader、AppView、AppButton 没有样式或布局错乱,通常不是框架内部渲染失败,而是消费方 app 没有把 NativeWind 和 Tailwind 扫描范围配置完整。
npm install nativewind
npm install -D tailwindcss创建 tailwind.config.js:
module.exports = {
content: [
'./App.{js,jsx,ts,tsx}',
'./src/**/*.{js,jsx,ts,tsx}',
'./node_modules/@gaozh1024/rn-kit/dist/**/*.{js,mjs}', // 必须包含框架路径
],
safelist: [
{ pattern: /^(flex)-(1|2|3|4|5|6|7|8|9|10|11|12)$/ },
'flex-wrap',
{ pattern: /^(items)-(start|center|end|stretch)$/ },
{ pattern: /^(justify)-(start|center|end|between|around)$/ },
{ pattern: /^(p|px|py|gap)-(0|1|2|3|4|5|6|8|10|12)$/ },
{ pattern: /^(rounded)-(none|sm|md|lg|xl|2xl|full)$/ },
{
pattern: /^(bg|text)-(primary|secondary|success|warning|error|info|gray|white|black)(-.+)?$/,
},
],
theme: { extend: {} },
plugins: [],
};修改 babel.config.js:
module.exports = function (api) {
api.cache(true);
return {
presets: [['babel-preset-expo', { jsxImportSource: 'nativewind' }], 'nativewind/babel'],
};
};🚀 快速开始
import { AppProvider, AppView, AppText, AppButton, useToggle } from '@gaozh1024/rn-kit';
function App() {
const [visible, { toggle }] = useToggle(false);
return (
<AppProvider>
<AppView flex p={4}>
<AppText size="xl">Hello Panther!</AppText>
<AppButton onPress={toggle}>{visible ? '隐藏' : '显示'}</AppButton>
</AppView>
</AppProvider>
);
}如果你只需要最小主题能力,也可以单独使用:
import { ThemeProvider, createTheme } from '@gaozh1024/rn-kit';
const theme = createTheme({
colors: {
primary: '#f38b32',
},
});📚 API 概览
🎨 主题系统
import { ThemeProvider, createTheme, useTheme } from '@gaozh1024/rn-kit';🧱 应用初始化与状态栏
import { AppProvider, AppStatusBar } from '@gaozh1024/rn-kit';受控切换主题时,推荐直接给 AppProvider / ThemeProvider 传 isDark,不要再通过重建根组件强制刷新:
<AppProvider lightTheme={lightTheme} darkTheme={darkTheme} isDark={themeMode === 'dark'}>
<RootNavigator />
</AppProvider>🧩 UI 组件
import {
AppView,
AppScrollView,
AppFlatList,
AppText,
AppPressable,
KeyboardDismissView,
KeyboardInsetView,
AppInput, // 原子组件
Row,
Col,
Center, // 布局
AppButton, // 组合组件
Toast,
Alert,
Loading,
Skeleton,
SkeletonText,
SkeletonAvatar,
Progress, // 反馈
Card,
Icon,
AppImage,
AppList,
GradientView,
PageDrawer, // 数据展示 / 页面级抽屉
Checkbox,
Radio,
Switch,
Select,
Picker,
DatePicker, // 表单
} from '@gaozh1024/rn-kit';布局与容器约定
- 这批容器组件已统一支持一套快捷参数,优先走 React Native
style,不再依赖这些参数对应的 Tailwind safelist:- 布局:
flex/row/wrap/center/between/items/justify - 间距:
p/px/py/pt/pb/pl/pr/m/mx/my/mt/mb/ml/mr/gap - 尺寸:
w/h/minW/minH/maxW/maxH - 外观:
rounded
- 布局:
SafeScreen/AppScreen同时支持:bg="primary-500"这类显式颜色surface="background" | "card" | "muted"这类语义背景dismissKeyboardOnPressOutside:点击非输入区域时收起键盘
- 语义建议:
SafeScreen:底层安全区容器,默认top=true/bottom=trueAppScreen:业务页面容器,默认top=false/bottom=true,更适合和AppHeader搭配
- 顶部安全区职责建议:
- 带
AppHeader的页面:顶部安全区交给AppHeader,AppScreen保持默认top={false} - 不带
AppHeader的页面:顶部安全区交给AppScreen top或SafeScreen - 这样
status bar + header可以保持同一块背景,避免顶部颜色割裂
- 带
- 推荐模式:
// Header 页
<AppScreen>
<AppHeader title="设置" />
<AppScrollView>{/* 内容 */}</AppScrollView>
</AppScreen>
// 非 Header 页
<AppScreen top>
<AppView flex>{/* 内容 */}</AppView>
</AppScreen>
// 沉浸式页面
<SafeScreen top={false}>{/* 内容 */}</SafeScreen>AppScrollView支持dismissKeyboardOnPressOutside- 开启后会自动启用点击空白收起键盘
- 并默认补上
keyboardShouldPersistTaps="handled"
AppFlatList支持与AppScrollView一致的容器快捷参数- 外层支持:
flex/ 外边距 / 尺寸 /bg/surface/rounded - 内容区支持:布局 / 内边距 /
gap - 开启
dismissKeyboardOnPressOutside时默认补上keyboardShouldPersistTaps="handled"
- 外层支持:
KeyboardDismissView适合非页面容器、自定义布局场景下单独包裹使用KeyboardInsetView适合底部输入栏 / 评论框 / 聊天输入区的键盘避让AppInput的尺寸控制建议:style={{ height: 56 }}会作用到输入框外层容器- 更明确的写法可以使用
containerStyle/inputStyle
- 表单类触发器补充说明:
AppInput/Select/Picker/DatePicker现已支持一套“外层基础快捷参数”- 常用场景:
- 外层排版:
flex/mt/mb/w - 控件外观:
h/minH/maxH/rounded/bg/surface
- 外层排版:
AppImage已基于expo-image封装- 支持缓存策略
cachePolicy - 支持占位图
placeholder - 默认支持淡入过渡
transition
- 支持缓存策略
- 骨架屏已提供统一组件:
SkeletonSkeletonBlockSkeletonTextSkeletonAvatar
容器快捷参数支持矩阵
| 组件 | 默认行为 | 支持快捷参数 | 补充说明 |
| --------------- | -------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| AppView | 基础容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 通用容器基座 |
| Row | row,默认 items="center" | 继承 AppView 全部快捷参数 | justify 默认 start |
| Col | 纵向布局,默认 items="stretch" | 继承 AppView 全部快捷参数 | justify 默认 start |
| Center | 强制居中,默认不撑满 | 继承 AppView 大部分快捷参数 | 内部固定 center,需要铺满时请显式传 flex |
| AppScrollView | 滚动容器 | 外层支持:flex / 外边距 / 尺寸 / bg / surface / rounded;内容区支持:布局 / 内边距 / gap | row / items / justify 作用于 contentContainerStyle |
| AppFlatList | 虚拟列表容器 | 外层支持:flex / 外边距 / 尺寸 / bg / surface / rounded;内容区支持:布局 / 内边距 / gap | 保持原生 FlatListProps<T>,适合常规高性能列表场景 |
| AppPressable | 可点击容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 适合作为“可点击的 AppView”,保留 pressedClassName,且兼容原生 style(state) |
| AppText | 基础文本 | flex / 间距 / 尺寸 / bg / surface / rounded / className | 仅保留适合文本的快捷参数,不支持 row/gap/items/justify 等容器语义 |
| GradientView | 渐变背景容器 | 布局 / 间距 / 尺寸 / rounded | 适合页面头图、Banner、渐变卡片容器 |
| AppImage | 图片组件 | 外层支持:flex / 外边距 / 尺寸 / rounded / bg / surface | 保留 width/height/borderRadius 兼容写法,并新增快捷别名 |
| Icon | 图标组件 | 外层支持:flex / 间距 / 尺寸 / rounded / bg / surface | 适合做图标按钮、徽标入口、状态图标容器 |
| AppButton | 按钮 | flex / 外边距 / 尺寸 / rounded | size 继续控制默认内边距;快捷参数主要用于外层排版 |
| Card | 卡片容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 另有 noShadow / noBorder / noRadius |
| AppList | 高级列表组件 | 外层支持:flex / 外边距 / 尺寸 / bg / surface / rounded;内容区支持:布局 / 内边距 / gap | 和 AppFlatList 保持一致,适合直接承载业务空态/错态/骨架 |
| AppInput | 输入框 | 外层支持:flex / 外边距;输入容器支持:尺寸 / rounded / bg / surface | 更细粒度仍推荐配合 containerStyle / inputStyle |
| Checkbox | 复选框 | 外层支持:flex / 间距 / gap / 尺寸 / rounded / bg / surface | 适合直接扩展点击热区、间距和标签排版 |
| Radio | 单选框 | 外层支持:flex / 间距 / gap / 尺寸 / rounded / bg / surface | 与 Checkbox 保持一致,便于统一表单行样式 |
| Switch | 开关 | 外层支持:flex / 外边距;轨道支持:rounded | 尺寸仍建议优先使用 size,style 继续可用于细调轨道 |
| Slider | 滑块 | 外层支持:flex / 外边距 / 宽度;轨道支持:rounded / bg / surface | 更适合直接控制组件占位宽度与轨道观感 |
| CheckboxGroup | 复选组 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 组容器本身按 AppView 思路工作,子项仍使用 Checkbox |
| RadioGroup | 单选组 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 组容器本身按 AppView 思路工作,子项仍使用 Radio |
| Select | 选项选择器 | 外层支持:flex / 外边距;触发器支持:尺寸 / rounded / bg / surface | 适合单选 / 多选列表型选择 |
| Picker | 通用多列滚轮选择器 | 外层支持:flex / 外边距;触发器支持:尺寸 / rounded / bg / surface | 适合省市区、级联、多列滚轮选择 |
| DatePicker | 日期滚轮选择器 | 继承 Picker 的同一套基础快捷参数 | 仅封装日期语义与快捷按钮 |
| FormItem | 表单项容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 适合统一表单块容器、说明区、帮助文案区 |
| Progress | 进度条 | 外层支持:flex / 外边距 / 尺寸;轨道支持:rounded / bg / surface | size 继续负责默认高度语义,h 可用于显式覆盖 |
| SafeScreen | 底层安全区容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 默认 top=true / bottom=true,安全区 inset 会自动并入 padding |
| AppScreen | 页面语义容器 | 布局 / 间距 / 尺寸 / bg / surface / rounded / className | 默认 top=false / bottom=true,更适合带 AppHeader 的页面 |
说明:
className依然走 NativeWind;上表中的快捷参数本身已经由框架直接转换为内联style。
Button 颜色语义
AppButton 目前支持以下 color:
primarysecondarysuccesswarninginfoerrordanger(error的兼容别名)muted
<AppButton color="success">保存成功</AppButton>
<AppButton color="warning" variant="outline">
继续操作
</AppButton>
<AppButton color="danger">删除</AppButton>键盘收起交互
AppButton 新增:
dismissKeyboardOnPress?: boolean- 默认值:
true
也就是说,大多数提交/保存/登录按钮在点击前会先自动收起键盘:
<AppButton onPress={handleSubmit}>提交</AppButton>
<AppButton dismissKeyboardOnPress={false} onPress={handleToolbarAction}>
保持键盘
</AppButton>容器侧推荐这样使用:
<AppScreen dismissKeyboardOnPressOutside>
<AppScrollView dismissKeyboardOnPressOutside>
<AppInput placeholder="请输入手机号" />
<AppInput placeholder="请输入密码" secureTextEntry />
<AppButton onPress={handleLogin}>登录</AppButton>
</AppScrollView>
</AppScreen>如果不是整页容器,而是局部自定义布局,也可以单独使用:
<KeyboardDismissView>
<AppView p={4} gap={3}>
<AppInput placeholder="搜索内容" />
<AppButton onPress={handleSearch}>搜索</AppButton>
</AppView>
</KeyboardDismissView>聊天页 / 底部输入栏场景推荐:
<AppScreen>
<AppView flex>{/* message list */}</AppView>
<KeyboardInsetView px={4} py={3} surface="card">
<AppInput placeholder="输入消息..." />
</KeyboardInsetView>
</AppScreen>KeyboardInsetView 支持:
enabledbottomSafeAreakeyboardOffset
适合:
- 聊天输入框
- 评论输入框
- 底部回复栏
- 固定在页面底部的表单操作区
列表场景则推荐:
<AppFlatList
data={users}
renderItem={renderUser}
keyExtractor={item => item.id}
flex
px={4}
py={3}
gap={3}
dismissKeyboardOnPressOutside
/>AppScreen 与 SafeScreen 的使用建议
推荐按语义区分:
// 1) 常规业务页面:顶部由 AppHeader 负责安全区
<AppScreen>
<AppHeader title="设置" />
<AppView flex>{/* page content */}</AppView>
</AppScreen>
// 2) 无 Header 的全屏页面:直接使用 SafeScreen
<SafeScreen>
<AppView flex>{/* full screen content */}</AppView>
</SafeScreen>
// 3) 即使使用 AppScreen,也仍然可以显式覆盖
<AppScreen top bottom={false}>
<AppView flex>{/* custom layout */}</AppView>
</AppScreen>AppPressable 状态样式建议
AppPressable 同时支持两类写法:
- 静态
style={{ ... }} - 原生
Pressable风格的style(state) => ({ ... })
例如静态样式:
<AppPressable p={12} rounded="lg" style={{ backgroundColor: '#6366f1', opacity: 0.9 }} />以及状态样式:
<AppPressable
p={12}
rounded="lg"
bg="primary-500"
style={({ pressed, hovered, focused }) => ({
opacity: pressed ? 0.7 : 1,
borderWidth: focused ? 2 : 0,
borderColor: hovered ? '#f38b32' : 'transparent',
})}
/>适合:
- 业务侧自定义静态背景色 / 阴影 / 圆角
- 按下态透明度
- Web/TV 场景的
hovered/focused - 与
pressedClassName同时配合使用
可本地化文案参数(i18n 推荐)
AppList- 面向带空态 / 错误态 / 下拉刷新 / 上拉加载等“增强列表”场景
- 如果只需要原生
FlatList+ 统一布局/主题能力,优先使用AppFlatList errorTitle:错误标题(默认加载失败)errorDescription:错误描述兜底(默认请检查网络后重试)retryText:重试按钮文案(默认重新加载)
SelectsingleSelectTitle/multipleSelectTitle:弹窗标题searchPlaceholder:搜索占位文案emptyText:空状态文案selectedCountText:多选计数模板,支持{{count}}confirmText:多选确认按钮文案
PickerpickerTitle/cancelText/confirmText:弹窗文案renderDisplayText:自定义触发区展示文本renderFooter:自定义底部区域,适合扩展省市区、级联选择等场景
DatePickercancelText/confirmText:弹窗操作按钮文案pickerTitle:弹窗标题文案yearLabel/monthLabel/dayLabel:列标题文案todayText/minDateText/maxDateText:快捷按钮文案
图片与骨架屏
AppImage 当前基于 expo-image 封装,适合统一处理远程图片缓存、占位和错误态:
<AppImage
source={{ uri: user.avatar }}
width={80}
height={80}
borderRadius="full"
placeholder={require('./avatar-placeholder.png')}
cachePolicy="memory-disk"
/>通用内容骨架推荐直接使用:
<AppView p={4} gap={3}>
<SkeletonAvatar size={48} />
<SkeletonText lines={3} lineWidths={['100%', '92%', '60%']} />
<Skeleton h={120} rounded="lg" />
</AppView>AppList 和 AppImage 内部也已复用统一骨架能力。
表单与反馈 Hook 当前 API
import { useForm, useToast, useLoading, useAlert, useLogger } from '@gaozh1024/rn-kit';
const form = useForm({
schema,
defaultValues: { name: '' },
});
form.values;
form.errors;
form.setValue('name', 'Panther');
await form.validate();
await form.validateField('name');
await form.handleSubmit(async values => {
console.log(values);
});
const toast = useToast();
toast.show('已保存', 'success', 2000);
toast.success('成功');
const loading = useLoading();
loading.show('加载中...');
loading.hide();
const alert = useAlert();
alert.alert({ title: '提示', message: '操作完成' });
alert.confirm({ title: '确认删除', message: '删除后不可恢复' });
const logger = useLogger('auth');
logger.info('开始登录', { page: 'Login' });
logger.error('登录失败', { code: 401 });说明:
useForm使用defaultValues,不是initialValuesuseForm提供setValue/handleSubmit,不是setFieldValue/submituseToast当前签名为show(message, type?, duration?)useLoading当前签名为show(text?)/hide()useAlert当前提供alert()/confirm(),不包含prompt()/custom()useLogger(namespace?)提供debug / info / warn / error / clear / entries
开发日志 / 可观测性基础设施
框架现在内置了一套开发态可观测性基础设施,目标是帮助排查问题,而不是直接做线上监控平台。
默认能力:
useLogger(namespace?):组件内打点- 内存日志缓冲:保留最近若干条日志
- Console Transport:CLI 中按 level 彩色输出
LogOverlay:App 内浮动日志面板- 浮层增强:level 筛选 / namespace 筛选 / 导出当前日志 / 按钮可拖动吸边并按当前 storage 实现恢复位置
1. 最简单用法:直接跟随 AppProvider
import { AppProvider, useLogger, AppButton } from '@gaozh1024/rn-kit';
function LoginButton() {
const logger = useLogger('login');
return (
<AppButton
onPress={() => {
logger.info('点击登录按钮');
}}
>
登录
</AppButton>
);
}
export default function App() {
return (
<AppProvider>
<LoginButton />
</AppProvider>
);
}说明:
AppProvider在开发环境下默认enableLogger = true- 生产环境默认关闭
- 开启后会同时启用 console 输出和 App 内日志浮层
2. 显式控制是否启用
<AppProvider
enableLogger
enableErrorBoundary
loggerProps={{
level: 'info',
maxEntries: 300,
consoleEnabled: true,
defaultExpanded: false,
}}
>
<App />
</AppProvider>常用 loggerProps:
enabledlevel:'debug' | 'info' | 'warn' | 'error'maxEntriesconsoleEnabledoverlayEnableddefaultExpandedexportEnabledonExport
onExport 会收到:
{
entries: LogEntry[];
serialized: string;
}错误边界相关:
enableErrorBoundary:是否启用 React 错误边界errorBoundaryProps.title:兜底标题errorBoundaryProps.description:兜底说明errorBoundaryProps.showDetails:是否显示错误详情errorBoundaryProps.resetText:重试按钮文案
当错误边界与 logger 同时开启时,组件渲染异常会自动写入 react 命名空间日志,便于在控制台和 LogOverlay 中回看。
3. 单独使用 OverlayProvider / LoggerProvider
如果你不是通过 AppProvider 接入,而是自己手动包 Provider,需要注意:
LoggerProvider默认enabled = falseOverlayProvider里传入的 logger 也默认不主动开启
所以需要显式打开:
import { OverlayProvider } from '@gaozh1024/rn-kit';
<OverlayProvider
loggerProps={{
enabled: true,
overlayEnabled: true,
consoleEnabled: true,
}}
>
<App />
</OverlayProvider>;或者:
import { AppErrorBoundary, LoggerProvider } from '@gaozh1024/rn-kit';
<LoggerProvider enabled overlayEnabled consoleEnabled>
<AppErrorBoundary enabled showDetails>
<App />
</AppErrorBoundary>
</LoggerProvider>;🪝 Hooks
import {
// UI Hooks
useToggle,
usePageDrawer,
useDebounce,
useThrottle,
useKeyboard,
useDimensions,
useOrientation,
// Core Hooks
useAsyncState,
useRequest,
usePagination,
useRefresh,
useInfinite,
useStorage,
} from '@gaozh1024/rn-kit';🎞 Motion / 动画
框架当前动画底层已统一迁移到 react-native-reanimated,并继续通过 motion/animated adapter 收口 runtime。
当前 driver 固定为 reanimated,可直接读取 runtime 能力信息:
import {
getMotionAnimatedCapabilities,
getMotionAnimatedDriver,
getMotionScenarioRecommendation,
shouldPreferReanimatedForScenario,
supportsMotionCapability,
} from '@gaozh1024/rn-kit';
const driver = getMotionAnimatedDriver(); // 'reanimated'
const capabilities = getMotionAnimatedCapabilities();
const supportsSharedValues = supportsMotionCapability('sharedValues'); // true
const recommendation = getMotionScenarioRecommendation('sheet-drawer');
const preferReanimated = shouldPreferReanimatedForScenario('complex-gesture'); // true当前 capability 结论:
- 基础 timing / sequence / parallel / event:支持
useNativeDriver兼容层:支持- shared values / worklets / layout transitions:支持
- 复杂手势、滚动联动、抽屉 / sheet、可折叠 header 已统一跑在 reanimated 上
当前场景建议可简单理解为:
- 推荐直接使用当前 driver:
press-feedbackpresence-transitionprogress-feedbacktoggle-controlsheet-drawerstagger-listcollapsible-headercomplex-gesture
- 当前 runtime 已支持,但是否采用还取决于上层方案:
shared-elementlayout-transition
可以直接使用的 motion 能力:
import {
// motion hooks
useReducedMotion,
usePresenceMotion,
usePressMotion,
useToggleMotion,
useProgressMotion,
useSheetMotion,
useStaggerMotion,
useCollapsibleHeaderMotion,
// motion components
MotionView,
MotionPressable,
Presence,
StaggerItem,
CollapseView,
} from '@gaozh1024/rn-kit';1. 按压动画
以下组件已经内置按压动效,常用按压参数统一为:
motionPresetmotionDurationmotionReduceMotion
默认策略:
AppPressable默认motionPreset="none",更适合做基础可点击容器MotionPressable默认motionPreset="soft"AppButton/Card/Select/Picker/DatePicker/PageDrawer等语义组件默认按压反馈为softAppPressableMotionPressableAppButtonCardSelectPickerDatePickerAppHeaderBottomTabBarDrawerContentPageDrawer
<AppButton>保存</AppButton>
<AppButton motionDuration={180}>保存</AppButton>
<Card onPress={() => {}} motionPreset="strong" />可选值:
'soft''strong''none'
也可以通过全局 Provider 统一控制:
import { AppProvider, MotionConfigProvider } from '@gaozh1024/rn-kit';
<MotionConfigProvider defaultPressPreset="strong" durationScale={0.9}>
<App />
</MotionConfigProvider>;
<AppProvider
motion={{
reduceMotion: false,
durationScale: 0.9,
defaultPressPreset: 'soft',
defaultPresencePreset: 'fadeUp',
}}
>
<App />
</AppProvider>;可用于:
- 全局降低 / 关闭动画
- 统一默认按压反馈强度
- 统一默认显隐预设
2. 显隐动画
适合弹层、提示、局部块出现/消失:
import { Presence } from '@gaozh1024/rn-kit';
<Presence visible={visible} preset="fadeUp">
<AppView>
<AppText>内容出现</AppText>
</AppView>
</Presence>;
<MotionView
visible={visible}
preset="fadeUp"
motionDuration={260}
motionDistance={24}
motionReduceMotion={false}
/>;常用 preset:
fadefadeUpfadeDownscalescaleFadeslideUpslideDownslideLeftslideRightdialogtoastsheet
Presence / MotionView 额外支持:
motionPreset(与preset并存,优先级更高)motionDurationmotionEnterDurationmotionExitDurationmotionDistancemotionReduceMotion
3. 列表错峰动画
<AppList data={data} stagger staggerMs={50} renderItem={({ item }) => <Card>{item.title}</Card>} />列表动画参数语义:
motionReduceMotion:关闭普通列表项 entering / exiting / layout 动画staggerReduceMotion:仅关闭stagger模式下的错峰入场动画
导航抽屉也支持:
<DrawerContent {...props} staggerItems />4. Sheet / Drawer 动画
BottomSheetModal 与 PageDrawer 已统一接入内部 motion:
- 遮罩淡入淡出
- 面板进出场
- 手势关闭
- 支持组件级 motion 参数覆盖
<PageDrawer
visible={visible}
onClose={close}
placement="right"
motionPreset="soft"
motionOverlayOpacity={0.72}
motionVelocityThreshold={1.4}
/>
<BottomSheetModal
visible={visible}
onRequestClose={close}
overlayColor="rgba(0,0,0,0.5)"
surfaceColor="#fff"
motionDuration={240}
motionOpenDuration={320}
motionCloseDuration={180}
motionDistance={320}
motionOverlayOpacity={0.72}
motionSwipeThreshold={96}
/>BottomSheetModal 可选:
motionDurationmotionOpenDurationmotionCloseDurationmotionDistancemotionOverlayOpacitymotionSwipeThresholdmotionVelocityThresholdmotionReduceMotion
PageDrawer 也支持:
motionPresetmotionDurationmotionOpenDurationmotionCloseDurationmotionReduceMotionmotionDistancemotionOverlayOpacitymotionSwipeThreshold(兼容旧的swipeThreshold)motionVelocityThreshold
Select / Picker / DatePicker 也支持同一组 sheet 动画参数:
- 按压:
motionPreset/motionDuration/motionReduceMotion motionOpenDurationmotionCloseDurationmotionDistancemotionOverlayOpacitymotionSwipeThresholdmotionVelocityThresholdmotionReduceMotion
4.1 真实高度折叠 / 展开
如果你需要“高度从 0 平滑展开到内容实际高度”的效果,优先使用 CollapseView。
<CollapseView
visible={open}
motionDuration={280}
motionSpringPreset="smooth"
unmountOnExit={false}
>
<AppView pt={15} pb={15}>
{/* content */}
</AppView>
</CollapseView>可选参数:
motionDurationmotionSpringPresetmotionReduceMotioncollapsedHeightunmountOnExit
说明:
CollapseView用于真实高度折叠动画motionLayoutPreset="accordion"仍然是布局/拉伸类预设,不等价于精确 height 补间
5. 可折叠 Header
import { Animated, AppHeader, useCollapsibleHeaderMotion } from '@gaozh1024/rn-kit';
const headerMotion = useCollapsibleHeaderMotion({
minHeight: 44,
maxHeight: 88,
});
<>
<AppHeader title="首页" collapsibleMotion={headerMotion} />
<Animated.ScrollView onScroll={headerMotion.onScroll} scrollEventThrottle={16}>
{/* content */}
</Animated.ScrollView>
</>;6. 高级布局动画预设
Presence / MotionView / StaggerItem / AppList 现在支持更高层的布局动画封装:
motionLayoutPresetmotionLayoutDurationmotionLayoutDelaymotionLayoutSpring
可选预设:
fadefade-upfade-downslide-leftslide-rightzoom-fadelist-itemlist-reorderaccordiondialog
<Presence
visible={visible}
motionLayoutPreset="dialog"
motionLayoutDuration={280}
motionLayoutSpring="smooth"
>
<AppView>{/* content */}</AppView>
</Presence>
<AppList
data={data}
motionLayoutPreset="list-item"
motionLayoutDuration={260}
motionLayoutDelay={30}
motionLayoutSpring="snappy"
renderItem={({ item }) => <Card>{item.title}</Card>}
/>如果同时传入 motionEntering / motionExiting / motionLayout,则显式传入值优先。
7. Spring 动画配置
Progress / Switch / Checkbox / Radio 现在支持:
motionSpringPreset
可选值:
snappysmoothbouncy
<Progress value={72} motionSpringPreset="smooth" />
<Switch checked={enabled} onChange={setEnabled} motionSpringPreset="bouncy" />
<Checkbox checked motionSpringPreset="smooth" />未传 motionSpringPreset 时,仍默认使用 timing 动画。
8. 当前已接入动画的组件范围
- 反馈:
Alert/Toast/ overlay alert / overlay toast - 表单:
Switch/Checkbox/Radio/Select/Picker/DatePicker - 展示:
Progress/Card/AppList/PageDrawer/AppButton - 导航:
AppHeader/BottomTabBar/DrawerContent
其中 Alert / Toast 以及 overlay alert 也支持组件级显隐动画控制:
motionPresetmotionDurationmotionEnterDurationmotionExitDurationmotionDistancemotionReduceMotion
Presence / MotionView / StaggerItem 额外支持基于 reanimated 的布局级动画透传:
motionEnteringmotionExitingmotionLayoutmotionLayoutPresetmotionLayoutDurationmotionLayoutDelaymotionLayoutSpring
Progress 也支持:
motionDurationmotionSpringPresetmotionReduceMotion
Switch / Checkbox / Radio 也支持:
motionDurationmotionSpringPresetmotionReduceMotion
AppButton / Card / Select / Picker / DatePicker / PageDrawer 也统一支持:
motionPresetmotionDurationmotionReduceMotion
AppList 错峰 / 列表项动画还支持:
staggerPresetstaggerMsstaggerBaseDelayMsstaggerDurationstaggerDistancestaggerReduceMotionmotionEnteringmotionExitingmotionLayout
导航组件的动画参数也已统一:
AppHeadermotionPresetmotionDurationmotionReduceMotion- 支持通过
style.backgroundColor直接覆盖 header 背景色
BottomTabBar- 按压:
motionPreset/motionDuration/motionReduceMotion - 指示器:
indicatorMotionPreset/indicatorMotionDuration/indicatorMotionEnterDuration/indicatorMotionExitDuration/indicatorMotionDistance/indicatorMotionReduceMotion
- 按压:
DrawerContent- 按压:
motionPreset/motionDuration/motionReduceMotion - 指示条:
indicatorMotionPreset/indicatorMotionDuration/indicatorMotionEnterDuration/indicatorMotionExitDuration/indicatorMotionDistance/indicatorMotionReduceMotion - 错峰:
staggerPreset/staggerMs/staggerBaseDelayMs/staggerDuration/staggerDistance/staggerReduceMotion
- 按压:
9. 可复用的动画类型
可直接从包中导入:
import type {
PressMotionProps,
PresenceMotionProps,
SheetMotionProps,
ProgressMotionProps,
ToggleMotionProps,
StaggerMotionProps,
MotionSharedValue,
MotionAnimatedViewStyle,
MotionAnimatedTextStyle,
MotionAnimatedScrollHandler,
} from '@gaozh1024/rn-kit';运行时 helper / hooks 也可直接复用:
import { useEffect } from 'react';
import {
resolveMotionLayoutPreset,
Animated,
useSharedValue,
useAnimatedStyle,
withRepeat,
withTiming,
} from '@gaozh1024/rn-kit';
const layoutPreset = resolveMotionLayoutPreset({
preset: 'dialog',
duration: 280,
spring: 'smooth',
});
function PulseDot() {
const progress = useSharedValue(0);
useEffect(() => {
progress.value = withRepeat(withTiming(1, { duration: 600 }), -1, true);
}, [progress]);
const animatedStyle = useAnimatedStyle(() => ({
opacity: progress.value,
}));
return <Animated.View style={animatedStyle} />;
}如需自定义循环动画、shared value 或滚动联动,推荐统一从框架导出的 motion adapter 获取:
Animated(框架导出的 reanimated adapter alias,不是 RN 原生Animated)useSharedValueuseAnimatedStyleuseAnimatedScrollHandleruseDerivedValueuseAnimatedReactionwithTimingwithSpringwithDelaywithSequencewithRepeat
10. Reanimated 迁移状态
当前框架 motion runtime 已完成统一迁移:
- motion hooks 默认返回 reanimated shared value / animated style
Pressable/Progress/Sheet/Drawer/Alert/Toast/Header等组件已接入 reanimated- 高级布局动画预设与 spring 动画已在常见组件层完成封装
- 复杂手势、滚动联动和后续布局动画扩展都以 reanimated 为基础继续演进
🧭 导航
import {
NavigationProvider,
StackNavigator,
TabNavigator,
BottomTabBar,
DrawerNavigator,
useNavigation,
useRoute,
} from '@gaozh1024/rn-kit';TabNavigator 在未显式传入 tabBar 时,会默认使用框架内置的 BottomTabBar(默认高度 65)。
默认情况下,框架已关闭底部导航“选中横条”指示器;如需开启,可通过
tabBarOptions.showActiveIndicator或自定义BottomTabBar打开。
<TabNavigator
tabBarOptions={{
activeTintColor: '#f38b32',
inactiveTintColor: '#9ca3af',
height: 72,
showActiveIndicator: true,
indicatorColor: '#f38b32',
indicatorHeight: 3,
style: { borderTopWidth: 0 },
}}
>
{/* screens */}
</TabNavigator>如果你需要完全自定义底栏,也可以手动覆盖:
<TabNavigator tabBar={props => <BottomTabBar {...props} height={72} />}>
{/* screens */}
</TabNavigator>🧲 抽屉
框架同时提供两类抽屉能力:
- 导航级抽屉:
DrawerNavigator/DrawerContent - 页面级抽屉:
PageDrawer
1. 页面级抽屉
适合当前页面内的筛选面板、操作栏、详情侧栏。
import React from 'react';
import { AppButton, AppText, AppView, PageDrawer } from '@gaozh1024/rn-kit';
function FilterPanel() {
const [visible, setVisible] = React.useState(false);
return (
<>
<AppButton onPress={() => setVisible(true)}>打开筛选</AppButton>
<PageDrawer
visible={visible}
onClose={() => setVisible(false)}
title="筛选条件"
placement="right"
width={320}
>
<AppView gap={3}>
<AppText>这里放筛选项</AppText>
</AppView>
</PageDrawer>
</>
);
}PageDrawer 支持:
- 左 / 右侧抽屉
- 点击遮罩关闭
- 自定义
header/footer - 手势滑动关闭
- Android 返回键优先关闭抽屉
常用参数:
placement:'left' | 'right'width: 抽屉宽度,默认320swipeEnabled: 是否启用手势关闭,默认trueswipeThreshold: 触发关闭阈值,默认80closeOnBackdropPress: 点击遮罩关闭,默认true
🌈 渐变背景
框架提供 GradientView 作为渐变背景容器,底层封装 expo-linear-gradient。
import { GradientView, AppText } from '@gaozh1024/rn-kit';
<GradientView colors={['#f38b32', '#fb923c']} style={{ padding: 24, borderRadius: 16 }}>
<AppText color="white" weight="bold">
渐变卡片
</AppText>
</GradientView>;TypeScript 下如果你把颜色数组先提到变量里,建议写成 tuple:
const heroColors = ['#f38b32', '#fb923c'] as const;
<GradientView colors={heroColors} />;如果你的应用是手动集成 @gaozh1024/rn-kit,请同时安装:
npx expo install expo-linear-gradient如果你不想在页面里重复写 useState(false),也可以直接使用:
import { AppButton, PageDrawer, usePageDrawer } from '@gaozh1024/rn-kit';
const drawer = usePageDrawer();
<AppButton onPress={drawer.open}>打开</AppButton>;
<PageDrawer visible={drawer.visible} onClose={drawer.close} />;2. 导航级抽屉
适合整个导航结构都交给抽屉接管的场景:
默认情况下,框架已关闭
DrawerContent当前项指示条;如需开启,可显式传入showActiveIndicator。
import { DrawerContent, DrawerNavigator } from '@gaozh1024/rn-kit';
<DrawerNavigator
drawerContent={props => (
<DrawerContent
{...props}
showActiveIndicator
items={[
{ name: 'Home', label: '首页', icon: 'home' },
{ name: 'Settings', label: '设置', icon: 'settings' },
]}
/>
)}
>
{/* screens */}
</DrawerNavigator>;🔌 API 工厂
import { createAPI, createApiLoggerTransport, z, storage, ErrorCode } from '@gaozh1024/rn-kit';
const api = createAPI({
baseURL: 'https://api.example.com',
getHeaders: async () => {
const token = await storage.getItem('token');
return token ? { Authorization: `Bearer ${token}` } : undefined;
},
endpoints: {
getUser: {
method: 'GET',
path: '/users/{id}',
input: z.object({
id: z.string(),
include: z.string().optional(),
}),
},
revokeDevice: {
method: 'POST',
path: '/devices/{device_id}/revoke',
input: z.object({
device_id: z.string(),
}),
},
},
});默认行为:
- 支持
{id}和:id两种路径参数写法 - 如果路径参数缺失,调用会在发请求前直接抛出
VALIDATION错误 GET:路径参数会替换到 URL,剩余字段自动拼到 query,不发送 bodyPOST/PUT/PATCH/DELETE:会发送完整 body- 普通对象 body 默认使用
application/json - 如果用户显式传入
Content-Type,以用户传入的为准 headers与getHeaders()会自动合并,后者优先级更高getHeaders()/endpoint.getHeaders()/ 请求体序列化阶段如果抛错,也会统一进入onError与observability.error
例如:
await api.getUser({
id: 'u_1',
include: 'profile',
});
// => GET https://api.example.com/users/u_1?include=profile
await api.revokeDevice({
device_id: 'dev_1',
});
// => POST https://api.example.com/devices/dev_1/revoke
// => body: {"device_id":"dev_1"}Storage 注入:项目启动时切换为持久化存储
框架默认导出的 storage 是内存实现,适合测试和无持久化场景。
如果项目希望统一改成持久化存储,推荐在启动阶段注入。
推荐放到独立启动文件中,例如:
// src/bootstrap/storage.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
import { setStorageAdapter } from '@gaozh1024/rn-kit';
setStorageAdapter({
getItem: key => AsyncStorage.getItem(key),
setItem: (key, value) => AsyncStorage.setItem(key, value),
removeItem: key => AsyncStorage.removeItem(key),
});然后在应用入口最早执行:
// App.tsx
import './src/bootstrap/storage';如果你只想快速演示,也可以直接在启动代码里写:
import AsyncStorage from '@react-native-async-storage/async-storage';
import { setStorageAdapter } from '@gaozh1024/rn-kit';
setStorageAdapter({
getItem: key => AsyncStorage.getItem(key),
setItem: (key, value) => AsyncStorage.setItem(key, value),
removeItem: key => AsyncStorage.removeItem(key),
});注入后,框架内所有基于 storage 的能力都会自动走你提供的实现,例如:
createAPI中的 token 读取useStorage- logger 按钮位置持久化
- 你自己的
session/ 缓存 / 草稿等业务存储
业务代码仍然保持:
import { storage } from '@gaozh1024/rn-kit';
await storage.setItem('token', 'abc123');
const token = await storage.getItem('token');API 自动打点(request / response / error)
createAPI 已支持开发态自动打点。
默认行为:
- 开发环境下
observability.enabled默认开启 - 如果当前 App 已通过
AppProvider/LoggerProvider启用了 logger - 那么 API 请求会自动写入
api命名空间日志
记录阶段:
- request
- response
- error
const api = createAPI({
baseURL: 'https://api.example.com',
observability: {
enabled: true,
includeInput: true,
includeResponseData: false,
},
endpoints: {
getProfile: {
method: 'GET',
path: '/profile',
},
},
});也可以添加自定义 transport:
const api = createAPI({
baseURL: 'https://api.example.com',
observability: {
enabled: true,
transports: [
event => {
console.log('api event', event.stage, event.endpointName);
},
],
},
endpoints: {
getProfile: {
method: 'GET',
path: '/profile',
},
},
});如果你想手动指定写到某个 logger,也可以:
const transport = createApiLoggerTransport({
namespace: 'network',
includeInput: true,
includeResponseData: true,
});
const api = createAPI({
baseURL: 'https://api.example.com',
observability: {
enabled: true,
transports: [transport],
},
endpoints: {
getProfile: {
method: 'GET',
path: '/profile',
},
},
});📄 文档
- 框架文档 - 完整文档索引
📱 状态栏使用说明
1. 全局默认行为
推荐:
import { AppProvider } from '@gaozh1024/rn-kit';
export default function App() {
return (
<AppProvider>
<RootNavigator />
</AppProvider>
);
}此时框架会自动注入全局 AppStatusBar:
- 亮色主题:
dark-content - 暗色主题:
light-content - 默认
translucent={false} - Android 状态栏背景默认跟随当前主题背景色
2. 使用 AppHeader 时的默认行为
如果页面使用了 AppHeader,通常不需要再单独处理状态栏:
AppHeader内部会自动注入AppFocusedStatusBar- 配置为
translucent + backgroundColor="transparent" - 顶部状态栏区域会直接显示 Header 自身背景色
适合:
- 普通详情页
- 设置页
- 使用有色 Header 的二级页面
3. 页面级覆盖
如果某个页面需要单独控制状态栏,可以在页面内显式渲染:
import { AppFocusedStatusBar } from '@gaozh1024/rn-kit';
<AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />;适合:
- 登录页
- 沉浸式详情页
- 顶部大图/渐变背景页
对于导航页面,优先使用 AppFocusedStatusBar,这样只有当前聚焦页面会覆盖状态栏配置。
4. 登录页全屏背景示例
如果登录页希望顶部状态栏区域也和页面背景保持一致,不要直接使用默认白底容器。
推荐:
import { AppFocusedStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
export function LoginScreen() {
return (
<>
<AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
<SafeScreen bg="primary-500">
<AppView flex className="bg-primary-500">
{/* page content */}
</AppView>
</SafeScreen>
</>
);
}5. 沉浸式状态栏示例
import { AppFocusedStatusBar, SafeScreen, AppView } from '@gaozh1024/rn-kit';
export function HeroScreen() {
return (
<>
<AppFocusedStatusBar barStyle="light-content" backgroundColor="transparent" translucent />
<SafeScreen top={false} bottom={false}>
<AppView flex className="bg-black">
{/* hero content */}
</AppView>
</SafeScreen>
</>
);
}6. 常见问题
为什么顶部还是白色?
通常是以下原因之一:
- 当前页面没有使用
AppHeader,也没有单独覆盖AppFocusedStatusBar/AppStatusBar - 页面容器本身是白底
- 使用了
AppScreen/SafeScreen,但没有设置bg - 顶部安全区没有和页面背景统一
如果你用的是:
<AppScreen>那它默认不适合登录页这类全屏品牌色场景。请改成:
<AppScreen bg="primary-500">或者直接用:
<SafeScreen bg="primary-500">📄 许可证
MIT
