三、主题系统
主题系统是UI Kitten最强大的特性之一。它不仅支持亮色/暗色主题的无缝切换,还允许你创建完全自定义的品牌主题。
3.1 使用内置主题
UI Kitten提供了两套内置主题:
import * as eva from '@eva-design/eva';
import { ApplicationProvider } from '@ui-kitten/components';
// 亮色主题
<ApplicationProvider {...eva} theme={eva.light}>
{/* 应用内容 */}
</ApplicationProvider>
// 暗色主题
<ApplicationProvider {...eva} theme={eva.dark}>
{/* 应用内容 */}
</ApplicationProvider>
3.2 运行时动态切换主题
UI Kitten最引人注目的特性之一,是能够在运行时动态切换主题,无需重新加载应用。这对于实现"深色模式"功能至关重要。
实现步骤:
// 1. 创建一个Context来管理当前主题
// ThemeContext.js
import React from 'react';
export const ThemeContext = React.createContext({
theme: 'light',
toggleTheme: () => {},
});
// 2. 在App中使用state管理主题
// App.js
import React, { useState } from 'react';
import * as eva from '@eva-design/eva';
import { ApplicationProvider } from '@ui-kitten/components';
import { ThemeContext } from './ThemeContext';
import { AppNavigator } from './navigation/AppNavigator';
export default function App() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
const nextTheme = theme === 'light' ? 'dark' : 'light';
setTheme(nextTheme);
};
return (
<ThemeContext.Provider value={
{ theme, toggleTheme }}>
<ApplicationProvider {...eva} theme={eva[theme]}>
<AppNavigator />
</ApplicationProvider>
</ThemeContext.Provider>
);
}
// 3. 在任何组件中切换主题
// SettingsScreen.js
import React, { useContext } from 'react';
import { Button } from '@ui-kitten/components';
import { ThemeContext } from './ThemeContext';
export function SettingsScreen() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<Button onPress={toggleTheme}>
切换至{theme === 'light' ? '暗色' : '亮色'}模式
</Button>
);
}
运行时主题切换的优势:
无需重新加载应用,体验流畅
所有组件自动适配新主题,无需手动刷新
支持与系统主题设置同步
3.3 创建自定义主题
UI Kitten允许你通过扩展内置主题来创建自定义主题:
// custom-theme.js
import * as eva from '@eva-design/eva';
// 创建自定义亮色主题
export const customLightTheme = {
...eva.light,
'color-primary-500': '#FF6B6B', // 自定义主色调
'color-primary-600': '#FF5252', // 主色调变体
'color-success-500': '#4ECDC4', // 自定义成功色
'color-danger-500': '#FF6B6B', // 自定义危险色
'text-basic-color': '#2D3436', // 基础文字颜色
'background-basic-color-1': '#FFFFFF', // 背景色
};
// 创建自定义暗色主题
export const customDarkTheme = {
...eva.dark,
'color-primary-500': '#FF6B6B',
'color-primary-600': '#FF5252',
'color-success-500': '#4ECDC4',
'color-danger-500': '#FF6B6B',
'text-basic-color': '#DFE6E9',
'background-basic-color-1': '#1E1E1E',
};
// 使用自定义主题
import { customLightTheme, customDarkTheme } from './custom-theme';
<ApplicationProvider {...eva} theme={customLightTheme}>
{/* 应用内容 */}
</ApplicationProvider>
3.4 Eva设计系统的变量命名规范
Eva Design System的变量命名遵循一致的规范:
颜色级别(level)从100到900,数值越大颜色越深。500通常代表基础色。
四、核心组件详解
UI Kitten提供了超过25个通用组件。以下是开发中最常用的核心组件及其详细用法。
4.1 布局组件
Layout组件
Layout是最基础的容器组件,提供了主题感知的背景色:
import { Layout, Text } from '@ui-kitten/components';
export function HomeScreen() {
return (
<Layout style={
{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text category="h1">欢迎使用UI Kitten</Text>
</Layout>
);
}
Divider组件
分割线组件,用于在视觉上分隔内容:
import { Divider, Text, Layout } from '@ui-kitten/components';
export function SettingsList() {
return (
<Layout>
<Text category="s1">账户设置</Text>
<Divider style={
{ marginVertical: 8 }} />
<Text category="s1">隐私设置</Text>
<Divider style={
{ marginVertical: 8 }} />
<Text category="s1">通知设置</Text>
</Layout>
);
}
4.2 表单组件
Input组件
文本输入框组件,支持多种状态和样式:
import React, { useState } from 'react';
import { Input, Icon } from '@ui-kitten/components';
export function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [secureTextEntry, setSecureTextEntry] = useState(true);
const EyeIcon = (props) => (
<Icon {...props} name={secureTextEntry ? 'eye-off' : 'eye'} />
);
return (
<>
<Input
placeholder="邮箱"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
style={
{ marginBottom: 16 }}
/>
<Input
placeholder="密码"
value={password}
onChangeText={setPassword}
secureTextEntry={secureTextEntry}
accessoryRight={(props) => (
<Icon {...props} name={secureTextEntry ? 'eye-off' : 'eye'} />
)}
/>
</>
);
}
Select组件
下拉选择器组件:
import React, { useState } from 'react';
import { Select, SelectItem } from '@ui-kitten/components';
export function CitySelect() {
const [selectedIndex, setSelectedIndex] = useState(null);
const [selectedCity, setSelectedCity] = useState('');
const cities = ['北京', '上海', '广州', '深圳'];
return (
<Select
placeholder="请选择城市"
value={selectedCity}
selectedIndex={selectedIndex}
onSelect={(index) => {
setSelectedIndex(index);
setSelectedCity(cities[index.row]);
}}
>
{cities.map((city, index) => (
<SelectItem key={index} title={city} />
))}
</Select>
);
}
4.3 模态框 Modal
Modal组件用于创建弹窗:
import React, { useState } from 'react';
import { Modal, Button, Card, Text } from '@ui-kitten/components';
import { StyleSheet, View } from 'react-native';
export function CustomModal() {
const [visible, setVisible] = useState(false);
const styles = StyleSheet.create({
modal: {
backgroundColor: 'white',
borderRadius: 8,
padding: 16,
width: '80%',
maxWidth: 300,
},
backdrop: {
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
buttonContainer: {
flexDirection: 'row',
justifyContent: 'flex-end',
marginTop: 16,
gap: 8,
},
});
return (
<>
<Button onPress={() => setVisible(true)}>打开模态框</Button>
<Modal
visible={visible}
backdropStyle={styles.backdrop}
onBackdropPress={() => setVisible(false)}
>
<View style={styles.modal}>
<Text category="h6">确认操作</Text>
<Text style={
{ marginTop: 12 }}>确定要执行此操作吗?</Text>
<View style={styles.buttonContainer}>
<Button size="small" appearance="ghost" onPress={() => setVisible(false)}>
取消
</Button>
<Button size="small" onPress={() => setVisible(false)}>
确定
</Button>
</View>
</View>
</Modal>
</>
);
}
Modal组件关键属性:
visible:控制模态框显示/隐藏
backdropStyle:自定义背景遮罩样式
onBackdropPress:点击背景遮罩时的回调
4.4 导航组件
UI Kitten提供了与React Navigation深度集成的导航组件:
BottomNavigation组件:
import React, { useState } from 'react';
import { BottomNavigation, BottomNavigationTab, Icon } from '@ui-kitten/components';
const PersonIcon = (props) => <Icon {...props} name="person-outline" />;
const BellIcon = (props) => <Icon {...props} name="bell-outline" />;
const SettingsIcon = (props) => <Icon {...props} name="settings-outline" />;
export function AppBottomNavigation({ navigation, state }) {
return (
<BottomNavigation
selectedIndex={state.index}
onSelect={index => navigation.navigate(state.routeNames[index])}
>
<BottomNavigationTab title="个人" icon={PersonIcon} />
<BottomNavigationTab title="通知" icon={BellIcon} />
<BottomNavigationTab title="设置" icon={SettingsIcon} />
</BottomNavigation>
);
}
TopNavigation组件:
import { TopNavigation, Icon } from '@ui-kitten/components';
const BackIcon = (props) => <Icon {...props} name="arrow-back" />;
const MenuIcon = (props) => <Icon {...props} name="menu-outline" />;
export function CustomTopNavigation({ navigation, title }) {
return (
<TopNavigation
title={title}
alignment="center"
accessoryLeft={(props) => <Icon {...props} name="arrow-back" onPress={() => navigation.goBack()} />}
accessoryRight={(props) => <Icon {...props} name="menu-outline" />}
/>
);
}
4.5 卡片组件 Card
Card组件用于展示内容块:
import { Card, Text, Button } from '@ui-kitten/components';
export function ProductCard({ product, onPress }) {
return (
<Card
style={
{ marginVertical: 8, marginHorizontal: 16 }}
onPress={onPress}
>
<Text category="h6">{product.name}</Text>
<Text category="s2" appearance="hint" style={
{ marginTop: 4 }}>
{product.description}
</Text>
<Text category="h6" status="primary" style={
{ marginTop: 12 }}>
¥{product.price}
</Text>
</Card>
);
}