RN核心语法与组件体系:UI布局与基础交互

RN核心语法与组件体系:UI布局与基础交互

在上一篇文章中,我们完成了RN开发环境的搭建并实现了第一个HelloWorld应用。本文作为RN体系化专栏的第二篇,将聚焦RN核心组件、Flex布局体系、样式系统与基础交互,帮助你从"能运行"进阶到"能独立搭建页面UI并实现用户交互",为后续复杂应用开发夯实基础。

一、RN核心基础组件:构建UI的基石

RN提供了一套封装好的基础组件,这些组件最终会映射为对应平台的原生控件,既保证了跨端一致性,又具备原生级的交互体验。我们先从最常用的核心组件入手,逐个拆解其用法。

1. 容器与文本:View与Text

(1)View组件(基础容器)

View是RN中最基础的容器组件,类似于Web中的div,用于承载其他组件、实现布局嵌套。它支持Flex布局、样式设置和触摸事件,是页面结构的核心骨架。

基础用法

jsx 复制代码
import { View, StyleSheet } from 'react-native';

export default function BasicView() {
  return (
    // 外层容器,采用Flex布局居中内部元素
    <View style={styles.container}>
      {/* 内层子容器,设置背景色和宽高 */}
      <View style={styles.box1} />
      <View style={styles.box2} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1, // 占满父容器剩余空间
    backgroundColor: '#f5f5f5',
    justifyContent: 'center', // 主轴(垂直)居中
    alignItems: 'center', // 交叉轴(水平)居中
  },
  box1: {
    width: 100,
    height: 100,
    backgroundColor: '#0066cc',
    marginBottom: 20, // 与下方box2的间距
  },
  box2: {
    width: 80,
    height: 80,
    backgroundColor: '#ff6600',
    borderRadius: 10, // 圆角效果
  },
});
(2)Text组件(文本展示)

Text是RN中唯一能显示文本的组件(Web中任意标签可写文本,但RN不行),支持字体样式、换行、富文本和文本事件。

基础用法

jsx 复制代码
import { Text, View, StyleSheet } from 'react-native';

export default function BasicText() {
  return (
    <View style={styles.container}>
      {/* 基础文本 */}
      <Text style={styles.title}>React Native 组件学习</Text>
      {/* 多行文本与样式嵌套(富文本) */}
      <Text style={styles.content}>
        这是一段多行文本,支持
        <Text style={styles.highlight}>样式嵌套</Text>
        ,还能实现
        <Text style={styles.link}>点击跳转</Text>
        等交互。
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#fff',
  },
  title: {
    fontSize: 22,
    fontWeight: 'bold', // 加粗
    color: '#333',
    marginBottom: 15,
  },
  content: {
    fontSize: 16,
    color: '#666',
    lineHeight: 24, // 行高,控制文本间距
  },
  highlight: {
    color: '#0066cc',
    fontWeight: '600',
  },
  link: {
    color: '#ff6600',
    textDecorationLine: 'underline', // 下划线,模拟链接
  },
});

2. 图片展示:Image组件

Image组件用于加载本地或网络图片,支持缓存、缩放、圆角等功能,是实现图文页面的核心组件。

(1)加载网络图片
jsx 复制代码
import { Image, View, StyleSheet } from 'react-native';

export default function NetworkImage() {
  return (
    <View style={styles.container}>
      <Image
        style={styles.image}
        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} // 网络图片URI
        resizeMode="contain" // 缩放模式:保持宽高比,完整显示图片
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
  },
  image: {
    width: 200,
    height: 200,
    borderRadius: 10,
  },
});
(2)加载本地图片

首先将图片放入项目assets/images目录(需自行创建),然后通过require引入:

jsx 复制代码
// 本地图片需指定相对路径
<Image
  style={styles.localImage}
  source={require('../assets/images/avatar.png')}
/>

// 对应的样式
localImage: {
  width: 80,
  height: 80,
  borderRadius: 40, // 圆形头像
},

关键属性说明

  • resizeMode:控制图片缩放方式,常用值有contain(保持比例)、cover(铺满容器,裁剪多余部分)、stretch(拉伸填充,可能变形);
  • fadeDuration:设置图片加载时的淡入动画时长(仅iOS);
  • cachePolicy:网络图片缓存策略,如cacheOnly(仅从缓存加载)。

3. 交互组件:Touchable系列与TextInput

RN的交互组件分为两类:触摸反馈组件 (实现点击/长按等操作)和输入组件(实现用户输入)。

(1)Touchable系列组件

RN没有Web中的button标签,而是通过Touchable系列组件实现触摸交互,常用的有TouchableOpacity(点击时透明度变化)、TouchableHighlight(点击时背景高亮)、TouchableWithoutFeedback(无视觉反馈)。

最常用的TouchableOpacity

jsx 复制代码
import { View, Text, TouchableOpacity, StyleSheet, Alert } from 'react-native';

export default function TouchableDemo() {
  const handlePress = () => {
    // 弹出提示框
    Alert.alert('提示', '按钮被点击了!');
  };

  const handleLongPress = () => {
    Alert.alert('提示', '按钮被长按了!');
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={styles.button}
        onPress={handlePress} // 点击事件
        onLongPress={handleLongPress} // 长按事件
        activeOpacity={0.7} // 点击时透明度(默认0.2)
      >
        <Text style={styles.buttonText}>点击我</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#0066cc',
    paddingHorizontal: 30,
    paddingVertical: 12,
    borderRadius: 8,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '500',
  },
});
(2)TextInput(文本输入)

TextInput用于实现用户输入,支持单行/多行输入、占位符、输入限制、密码隐藏等功能,是表单页面的核心组件。

基础用法

jsx 复制代码
import { View, TextInput, StyleSheet, Text } from 'react-native';
import { useState } from 'react';

export default function TextInputDemo() {
  // 用useState管理输入框内容
  const [inputValue, setInputValue] = useState('');

  return (
    <View style={styles.container}>
      <Text style={styles.label}>请输入用户名:</Text>
      <TextInput
        style={styles.input}
        placeholder="请输入您的用户名" // 占位提示文字
        placeholderTextColor="#999" // 占位文字颜色
        value={inputValue} // 绑定输入值
        onChangeText={(text) => setInputValue(text)} // 输入变化时更新状态
        maxLength={20} // 最大输入长度
        clearButtonMode="while-editing" // iOS专属:编辑时显示清除按钮
        autoCapitalize="none" // 关闭自动大写
      />
      {/* 实时显示输入内容 */}
      <Text style={styles.tip}>已输入:{inputValue}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#fff',
  },
  label: {
    fontSize: 16,
    color: '#333',
    marginBottom: 8,
  },
  input: {
    height: 44,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    paddingHorizontal: 12,
    fontSize: 16,
    marginBottom: 15,
  },
  tip: {
    fontSize: 14,
    color: '#666',
  },
});

4. 列表组件:FlatList(高效渲染长列表)

当需要展示大量数据列表时,直接用View嵌套多个组件会导致性能卡顿,RN提供了FlatList组件,通过懒加载复用组件实现高效渲染,是长列表的首选方案。

基础用法

jsx 复制代码
import { FlatList, View, Text, StyleSheet, Image } from 'react-native';

// 模拟列表数据
const DATA = [
  { id: '1', title: 'RN基础组件', author: '前端小白', avatar: 'https://placehold.co/40x40' },
  { id: '2', title: 'Flex布局实战', author: 'RN进阶者', avatar: 'https://placehold.co/40x40' },
  { id: '3', title: '状态管理入门', author: '全栈开发', avatar: 'https://placehold.co/40x40' },
  { id: '4', title: '原生模块交互', author: '资深工程师', avatar: 'https://placehold.co/40x40' },
  { id: '5', title: '性能优化技巧', author: '架构师', avatar: 'https://placehold.co/40x40' },
  // 可扩展更多数据
];

// 列表项组件
const ListItem = ({ item }) => (
  <View style={styles.itemContainer}>
    <Image source={{ uri: item.avatar }} style={styles.avatar} />
    <View style={styles.textContainer}>
      <Text style={styles.title}>{item.title}</Text>
      <Text style={styles.author}>作者:{item.author}</Text>
    </View>
  </View>
);

export default function FlatListDemo() {
  return (
    <FlatList
      data={DATA} // 数据源
      renderItem={({ item }) => <ListItem item={item} />} // 渲染列表项
      keyExtractor={(item) => item.id} // 列表项唯一标识(必须)
      style={styles.list}
      ItemSeparatorComponent={() => <View style={styles.separator} />} // 列表项分隔线
      ListHeaderComponent={() => <Text style={styles.header}>RN学习资源列表</Text>} // 列表头部
      ListEmptyComponent={() => <Text style={styles.empty}>暂无数据</Text>} // 数据为空时显示
    />
  );
}

const styles = StyleSheet.create({
  list: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  header: {
    fontSize: 18,
    fontWeight: 'bold',
    padding: 15,
    backgroundColor: '#fff',
  },
  itemContainer: {
    flexDirection: 'row', // 横向排列
    alignItems: 'center',
    padding: 15,
    backgroundColor: '#fff',
  },
  avatar: {
    width: 40,
    height: 40,
    borderRadius: 20,
    marginRight: 12,
  },
  textContainer: {
    flex: 1, // 占满剩余空间
  },
  title: {
    fontSize: 16,
    color: '#333',
    marginBottom: 4,
  },
  author: {
    fontSize: 14,
    color: '#999',
  },
  separator: {
    height: 1,
    backgroundColor: '#eee',
  },
  empty: {
    textAlign: 'center',
    padding: 20,
    color: '#999',
  },
});

核心属性说明

  • data:列表数据源,必须是数组;
  • renderItem:渲染单个列表项的函数;
  • keyExtractor:为每个列表项生成唯一key,避免渲染异常;
  • ItemSeparatorComponent:列表项之间的分隔线;
  • ListHeaderComponent/ListFooterComponent:列表头部/尾部组件;
  • onEndReached:列表滚动到底部时触发,用于实现下拉加载更多。

二、RN Flex布局体系:搞定跨端页面布局

RN默认采用Flex布局(弹性布局),不同于Web中Flex需手动开启,RN的View组件天然支持Flex,通过简单的属性即可实现复杂的页面排版,是跨端布局的核心方案。

1. Flex布局核心概念

Flex布局包含容器项目两个角色:

  • 容器 :开启Flex的父组件(RN中View默认是Flex容器);
  • 项目:容器内的子组件。

Flex布局有两根轴:

  • 主轴 :默认是垂直方向(flexDirection: column),可改为水平方向(row);
  • 交叉轴:与主轴垂直的轴,主轴为垂直时交叉轴为水平,反之亦然。

2. 容器常用属性

(1)flexDirection:控制主轴方向
属性值 主轴方向 适用场景
column(默认) 垂直方向,从上到下 移动端页面的纵向排版(如列表、表单)
row 水平方向,从左到右 横向排列的组件(如导航栏、标签栏)
column-reverse 垂直方向,从下到上 反向纵向排列
row-reverse 水平方向,从右到左 反向横向排列

示例:横向排列导航栏

jsx 复制代码
<View style={{ flexDirection: 'row', justifyContent: 'space-around', padding: 10 }}>
  <Text style={styles.navItem}>首页</Text>
  <Text style={styles.navItem}>课程</Text>
  <Text style={styles.navItem}>我的</Text>
</View>
(2)justifyContent:控制项目在主轴上的对齐方式
属性值 对齐效果
flex-start(默认) 靠近主轴起点
flex-end 靠近主轴终点
center 主轴居中
space-between 项目之间间距相等,两端对齐
space-around 项目两侧间距相等
space-evenly 所有间距(包括两端)相等
(3)alignItems:控制项目在交叉轴上的对齐方式
属性值 对齐效果
stretch(默认) 拉伸填满交叉轴(需项目无固定尺寸)
flex-start 靠近交叉轴起点
flex-end 靠近交叉轴终点
center 交叉轴居中
baseline 按项目基线对齐(适用于文本)
(4)flexWrap:控制项目是否换行

当项目总尺寸超过容器时,通过flexWrap控制是否换行,默认nowrap(不换行,项目会被压缩)。

  • wrap:自动换行;
  • nowrap:不换行(默认)。

3. 项目常用属性

  • flex:控制项目在主轴上的占比,数值为权重(如两个项目flex:1flex:2,则分别占1/3和2/3空间);
  • alignSelf:覆盖容器的alignItems,单独设置某个项目的交叉轴对齐方式;
  • margin/padding:控制项目的内外边距(与Web一致)。

4. Flex布局实战:登录页面

jsx 复制代码
import { View, TextInput, TouchableOpacity, Text, StyleSheet, Image } from 'react-native';
import { useState } from 'react';

export default function LoginPage() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = () => {
    console.log('登录信息:', { username, password });
  };

  return (
    <View style={styles.container}>
      {/* 顶部logo */}
      <Image
        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
        style={styles.logo}
      />
      {/* 表单区域 */}
      <View style={styles.formContainer}>
        <TextInput
          style={styles.input}
          placeholder="请输入用户名"
          value={username}
          onChangeText={setUsername}
        />
        <TextInput
          style={styles.input}
          placeholder="请输入密码"
          value={password}
          onChangeText={setPassword}
          secureTextEntry={true} // 密码隐藏
        />
        {/* 登录按钮 */}
        <TouchableOpacity style={styles.loginBtn} onPress={handleLogin}>
          <Text style={styles.btnText}>登录</Text>
        </TouchableOpacity>
        {/* 辅助链接 */}
        <View style={styles.linkContainer}>
          <Text style={styles.link}>忘记密码?</Text>
          <Text style={styles.link}>注册账号</Text>
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
    alignItems: 'center', // 交叉轴水平居中
    paddingTop: 60,
  },
  logo: {
    width: 80,
    height: 80,
    marginBottom: 40,
  },
  formContainer: {
    width: '85%', // 宽度占父容器85%
  },
  input: {
    height: 48,
    backgroundColor: '#fff',
    borderRadius: 8,
    paddingHorizontal: 15,
    fontSize: 16,
    marginBottom: 12,
  },
  loginBtn: {
    backgroundColor: '#0066cc',
    borderRadius: 8,
    paddingVertical: 14,
    alignItems: 'center',
    marginVertical: 15,
  },
  btnText: {
    color: '#fff',
    fontSize: 16,
    fontWeight: '500',
  },
  linkContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  link: {
    color: '#0066cc',
    fontSize: 14,
  },
});

三、RN样式系统:StyleSheet与样式适配

RN的样式系统类似CSS,但有明显差异:

  • 样式属性采用驼峰命名 (如backgroundColor而非background-color);
  • 没有CSS选择器,样式需通过style属性直接绑定;
  • 推荐使用StyleSheet.create创建样式,可提前校验样式合法性、优化性能。

1. StyleSheet核心用法

StyleSheet.create用于创建样式对象,支持样式复用和嵌套(有限),是RN样式开发的标准方式。

jsx 复制代码
import { StyleSheet } from 'react-native';

// 全局样式常量(可抽离到单独文件)
export const globalStyles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  text: {
    fontSize: 16,
    color: '#333',
  },
  // 样式嵌套(仅支持简单嵌套,复杂样式需拆分为多个属性)
  button: {
    padding: 12,
    borderRadius: 8,
    backgroundColor: '#0066cc',
    // 无法直接嵌套hover样式,RN需通过state控制交互样式
  },
});

2. 样式优先级

RN样式优先级从高到低为:内联样式 > StyleSheet样式 > 全局样式

jsx 复制代码
// 内联样式会覆盖StyleSheet中的color属性
<Text style={[globalStyles.text, { color: '#ff6600' }]}>优先级测试</Text>

3. 尺寸适配:应对不同屏幕

RN中尺寸单位为逻辑像素(dp),会自动根据设备像素密度(DPI)转换为物理像素,无需手动处理,但需注意屏幕宽度适配:

  • 推荐使用百分比Flex权重 适配宽度(如width: '80%');
  • 可通过DimensionsAPI获取屏幕尺寸,实现精准适配。

示例:获取屏幕尺寸

jsx 复制代码
import { Dimensions } from 'react-native';

// 获取屏幕宽高
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');

// 适配不同屏幕的图片宽度
const imageWidth = screenWidth * 0.8; // 占屏幕宽度80%

四、基础交互与简单动画

除了点击、输入等基础交互,RN还提供了AnimatedAPI实现简单的动画效果,提升页面体验。

1. 触摸事件进阶:传递参数

实际开发中,列表项点击常需传递数据(如ID),可通过箭头函数实现:

jsx 复制代码
<TouchableOpacity onPress={() => handleItemClick(item.id)}>
  <Text>{item.title}</Text>
</TouchableOpacity>

2. 简单动画:Animated实现渐隐渐现

jsx 复制代码
import { View, Animated, TouchableOpacity, Text, StyleSheet } from 'react-native';
import { useState, useRef } from 'react';

export default function SimpleAnimation() {
  // 创建动画值,初始为0(透明)
  const fadeAnim = useRef(new Animated.Value(0)).current;
  const [isShow, setIsShow] = useState(false);

  const toggleAnimation = () => {
    if (isShow) {
      // 隐藏动画:从1(不透明)变为0(透明)
      Animated.timing(fadeAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true, // 使用原生驱动,提升动画性能
      }).start(() => setIsShow(false));
    } else {
      // 显示动画:从0变为1
      Animated.timing(fadeAnim, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }).start(() => setIsShow(true));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity style={styles.btn} onPress={toggleAnimation}>
        <Text style={styles.btnText}>{isShow ? '隐藏方块' : '显示方块'}</Text>
      </TouchableOpacity>
      {/* 动画组件 */}
      <Animated.View
        style={[
          styles.box,
          {
            opacity: fadeAnim, // 绑定透明度动画
            transform: [{ scale: fadeAnim }], // 同时实现缩放动画
          },
        ]}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
  },
  btn: {
    backgroundColor: '#0066cc',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 8,
    marginBottom: 30,
  },
  btnText: {
    color: '#fff',
    fontSize: 16,
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: '#ff6600',
    borderRadius: 10,
  },
});

五、小结与下一阶段预告

本文系统讲解了RN的核心基础组件、Flex布局体系、样式系统和基础交互,你已具备独立搭建常规页面UI和实现简单交互的能力。通过实战案例(登录页、列表页),你也能感受到RN跨端布局的便捷性和组件化开发的优势。

下一篇文章《RN路由与状态管理:打造多页面应用》,将带你学习React Navigation路由配置和Redux状态管理,解决多页面跳转和数据共享问题,实现从"单页面"到"多页面应用"的跨越。

如果你在组件使用或布局调试中遇到问题,可随时留言,我会为你提供针对性的解决方案!

相关推荐
SEO-狼术3 小时前
Telerik UI for WPF and WinForms 2025 Q4 Crack
ui·wpf
song5013 小时前
鸿蒙 Flutter 语音交互进阶:TTS/STT 全离线部署与多语言适配
分布式·flutter·百度·华为·重构·electron·交互
灰灰勇闯IT4 小时前
RN原生模块交互:打通JS与原生的桥梁
开发语言·javascript·交互
Devlive 开源社区4 小时前
View Shadcn UI v2025.1.4 发布 - 全面拥抱暗黑模式
ui
Kingfar_15 小时前
HCI多模态人机交互技术探索
人机交互·交互·可用性测试·用户体验·眼动
song5015 小时前
鸿蒙 Flutter 图像编辑:原生图像处理与滤镜开发
图像处理·人工智能·分布式·flutter·华为·交互
招风的黑耳5 小时前
Axure设计案例——颜色选择器
ui·axure·颜色选择器
梓贤Vigo5 小时前
【Axure原型分享】AI图片修复
交互·产品经理·axure·原型·中继器
灵感菇_17 小时前
Flutter Riverpod 完整教程:从入门到实战
前端·flutter·ui·状态管理