ReactNative样式设计Skill react-native-styling

这个技能用于React Native应用中的样式设计和布局优化,包括StyleSheet API、Flexbox布局、响应式设计、平台特定样式和主题化。关键词:React Native, 样式设计, Flexbox, 响应式设计, 主题化, 移动开发, 前端开发, 用户体验设计。

移动开发 0 次安装 0 次浏览 更新于 3/25/2026

名称: react-native-styling 用户可调用: false 描述: 用于使用StyleSheet、Flexbox布局、响应式设计和主题化来样式化React Native组件。涵盖平台特定样式和设计系统。 允许工具:

  • 读取
  • 写入
  • 编辑
  • Bash
  • Grep
  • Glob

React Native 样式设计

使用此技能当使用StyleSheet API、Flexbox布局样式化React Native组件,并创建响应式、平台感知的设计。

关键概念

StyleSheet API

使用StyleSheet创建优化样式:

import { View, Text, StyleSheet } from 'react-native';

export default function Card() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>标题</Text>
      <Text style={styles.body}>正文文本</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#fff',
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3, // Android 阴影
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
    marginBottom: 8,
  },
  body: {
    fontSize: 14,
    color: '#666',
    lineHeight: 20,
  },
});

Flexbox 布局

React Native 默认使用Flexbox:

import { View, StyleSheet } from 'react-native';

// 列布局(默认)
const styles = StyleSheet.create({
  column: {
    flex: 1,
    flexDirection: 'column', // 默认
    justifyContent: 'flex-start', // 默认
    alignItems: 'stretch', // 默认
  },
});

// 行布局
const rowStyles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
  },
});

// 居中内容
const centeredStyles = StyleSheet.create({
  centered: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

响应式设计

使用Dimensions进行响应式布局:

import { View, Dimensions, StyleSheet } from 'react-native';

const { width, height } = Dimensions.get('window');

const styles = StyleSheet.create({
  container: {
    width: width * 0.9, // 屏幕宽度的90%
    height: height * 0.5, // 屏幕高度的50%
  },
  card: {
    width: width > 768 ? 400 : width * 0.9, // 平板与手机对比
  },
});

平台特定样式

应用平台特定样式:

import { Platform, StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    paddingTop: Platform.OS === 'ios' ? 20 : 0,
    ...Platform.select({
      ios: {
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.3,
        shadowRadius: 4,
      },
      android: {
        elevation: 4,
      },
    }),
  },
  text: {
    fontFamily: Platform.select({
      ios: 'System',
      android: 'Roboto',
    }),
  },
});

最佳实践

使用 StyleSheet.create()

始终使用StyleSheet以提升性能:

// 不好 - 每次渲染都创建新对象
<View style={{ padding: 16, backgroundColor: '#fff' }}>
  <Text>内容</Text>
</View>

// 好 - 使用StyleSheet优化
const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#fff',
  },
});

<View style={styles.container}>
  <Text>内容</Text>
</View>

使用数组组合样式

使用数组组合样式:

import { View, Text, StyleSheet } from 'react-native';

function Button({ primary, disabled }: { primary?: boolean; disabled?: boolean }) {
  return (
    <View style={[
      styles.button,
      primary && styles.buttonPrimary,
      disabled && styles.buttonDisabled,
    ]}>
      <Text style={[
        styles.buttonText,
        primary && styles.buttonTextPrimary,
      ]}>
        按下我
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  button: {
    padding: 12,
    borderRadius: 8,
    backgroundColor: '#e0e0e0',
  },
  buttonPrimary: {
    backgroundColor: '#007AFF',
  },
  buttonDisabled: {
    opacity: 0.5,
  },
  buttonText: {
    textAlign: 'center',
    color: '#333',
    fontWeight: '600',
  },
  buttonTextPrimary: {
    color: '#fff',
  },
});

设计令牌

创建可重用的设计令牌:

// theme.ts
export const colors = {
  primary: '#007AFF',
  secondary: '#5856D6',
  success: '#34C759',
  error: '#FF3B30',
  warning: '#FF9500',
  background: '#FFFFFF',
  surface: '#F2F2F7',
  text: {
    primary: '#000000',
    secondary: '#3C3C43',
    tertiary: '#8E8E93',
  },
};

export const spacing = {
  xs: 4,
  sm: 8,
  md: 16,
  lg: 24,
  xl: 32,
};

export const typography = {
  h1: {
    fontSize: 32,
    fontWeight: 'bold' as const,
    lineHeight: 40,
  },
  h2: {
    fontSize: 24,
    fontWeight: 'bold' as const,
    lineHeight: 32,
  },
  body: {
    fontSize: 16,
    lineHeight: 24,
  },
  caption: {
    fontSize: 12,
    lineHeight: 16,
  },
};

export const shadows = {
  small: {
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
    elevation: 2,
  },
  medium: {
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.15,
    shadowRadius: 4,
    elevation: 4,
  },
  large: {
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.2,
    shadowRadius: 8,
    elevation: 8,
  },
};

// 使用
import { colors, spacing, typography, shadows } from './theme';

const styles = StyleSheet.create({
  container: {
    padding: spacing.md,
    backgroundColor: colors.background,
  },
  title: {
    ...typography.h1,
    color: colors.text.primary,
  },
  card: {
    ...shadows.medium,
    borderRadius: 8,
  },
});

主题上下文

实现主题切换:

import React, { createContext, useContext, useState } from 'react';

type Theme = {
  colors: {
    background: string;
    text: string;
    primary: string;
  };
};

const lightTheme: Theme = {
  colors: {
    background: '#FFFFFF',
    text: '#000000',
    primary: '#007AFF',
  },
};

const darkTheme: Theme = {
  colors: {
    background: '#000000',
    text: '#FFFFFF',
    primary: '#0A84FF',
  },
};

const ThemeContext = createContext<{
  theme: Theme;
  toggleTheme: () => void;
}>({
  theme: lightTheme,
  toggleTheme: () => {},
});

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [isDark, setIsDark] = useState(false);

  const toggleTheme = () => setIsDark(!isDark);

  return (
    <ThemeContext.Provider
      value={{
        theme: isDark ? darkTheme : lightTheme,
        toggleTheme,
      }}
    >
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);

// 使用
function MyComponent() {
  const { theme } = useTheme();

  return (
    <View style={{ backgroundColor: theme.colors.background }}>
      <Text style={{ color: theme.colors.text }}>主题化文本</Text>
    </View>
  );
}

常见模式

卡片组件与变体

import React from 'react';
import { View, Text, StyleSheet, ViewStyle } from 'react-native';

interface CardProps {
  title: string;
  children: React.ReactNode;
  variant?: 'default' | 'outlined' | 'elevated';
}

export default function Card({ title, children, variant = 'default' }: CardProps) {
  const variantStyle = variant === 'outlined'
    ? styles.outlined
    : variant === 'elevated'
    ? styles.elevated
    : styles.default;

  return (
    <View style={[styles.card, variantStyle]}>
      <Text style={styles.title}>{title}</Text>
      <View style={styles.content}>{children}</View>
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    borderRadius: 12,
    padding: 16,
    marginVertical: 8,
  },
  default: {
    backgroundColor: '#F2F2F7',
  },
  outlined: {
    backgroundColor: 'transparent',
    borderWidth: 1,
    borderColor: '#C6C6C8',
  },
  elevated: {
    backgroundColor: '#fff',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 8,
    elevation: 4,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 12,
  },
  content: {
    marginTop: 8,
  },
});

响应式网格

import React from 'react';
import { View, Dimensions, StyleSheet } from 'react-native';

const { width } = Dimensions.get('window');
const columns = width > 768 ? 3 : 2;
const gap = 16;
const itemWidth = (width - (columns + 1) * gap) / columns;

function Grid({ items }: { items: React.ReactNode[] }) {
  return (
    <View style={styles.container}>
      {items.map((item, index) => (
        <View key={index} style={styles.item}>
          {item}
        </View>
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    padding: gap,
    gap: gap,
  },
  item: {
    width: itemWidth,
  },
});

动画按钮

import React from 'react';
import {
  Pressable,
  Text,
  StyleSheet,
  Animated,
  PressableStateCallbackType,
} from 'react-native';

interface ButtonProps {
  title: string;
  onPress: () => void;
}

export default function AnimatedButton({ title, onPress }: ButtonProps) {
  const scale = new Animated.Value(1);

  const handlePressIn = () => {
    Animated.spring(scale, {
      toValue: 0.95,
      useNativeDriver: true,
    }).start();
  };

  const handlePressOut = () => {
    Animated.spring(scale, {
      toValue: 1,
      useNativeDriver: true,
    }).start();
  };

  return (
    <Pressable
      onPress={onPress}
      onPressIn={handlePressIn}
      onPressOut={handlePressOut}
    >
      {({ pressed }) => (
        <Animated.View
          style={[
            styles.button,
            { transform: [{ scale }] },
            pressed && styles.pressed,
          ]}
        >
          <Text style={styles.text}>{title}</Text>
        </Animated.View>
      )}
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#007AFF',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    alignItems: 'center',
  },
  pressed: {
    backgroundColor: '#0051D5',
  },
  text: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '600',
  },
});

反模式

不要使用百分比表示维度

// 不好 - 百分比不如预期工作
<View style={{ width: '50%' }}>
  <Text>半宽</Text>
</View>

// 好 - 使用flex或特定维度
<View style={{ flex: 1 }}>
  <Text>全宽</Text>
</View>

不要忘记平台特定阴影

// 不好 - 仅iOS阴影
<View style={{
  shadowColor: '#000',
  shadowOffset: { width: 0, height: 2 },
  shadowOpacity: 0.3,
  shadowRadius: 4,
}}>
  <Text>卡片</Text>
</View>

// 好 - iOS和Android都包含
<View style={{
  shadowColor: '#000',
  shadowOffset: { width: 0, height: 2 },
  shadowOpacity: 0.3,
  shadowRadius: 4,
  elevation: 4, // Android
}}>
  <Text>卡片</Text>
</View>

不要使用变换进行布局

// 不好 - 变换不影响布局
<View style={{ transform: [{ translateX: 100 }] }}>
  <Text>已移动</Text>
</View>

// 好 - 使用边距/内边距进行布局
<View style={{ marginLeft: 100 }}>
  <Text>已移动</Text>
</View>

不要硬编码颜色

// 不好 - 硬编码颜色
<View style={{ backgroundColor: '#007AFF' }}>
  <Text style={{ color: '#FFFFFF' }}>文本</Text>
</View>

// 好 - 使用设计令牌
import { colors } from './theme';

<View style={{ backgroundColor: colors.primary }}>
  <Text style={{ color: colors.text.onPrimary }}>文本</Text>
</View>

相关技能

  • react-native-components: 样式化核心组件
  • react-native-platform: 平台特定样式考虑
  • react-native-performance: 优化样式性能