当前位置: 首页 > news >正文

ReactNative【实战系列教程】我的小红书 3 -- 自定义底栏Tab导航(含图片选择 expo-image-picker 的使用)

最终效果

在这里插入图片描述

技术要点

自定义 tab

需从 “expo-router/ui” 中导入 TabList, Tabs, TabSlot, TabTrigger 实现

  • Tabs 表示含底栏的页面容器
  • TabList 为整个底栏的容器
  • TabSlot 渲染 tab 路由对应的页面
  • TabTrigger 触发 tab 底栏的路由导航
    • name 属性对应页面文件
    • href 属性对应页面的路由
import { Tabs, TabList, TabTrigger, TabSlot } from 'expo-router/ui';
import { Text } from 'react-native';// Defining the layout of the custom tab navigator
export default function Layout() {return (<Tabs><TabSlot /><TabList><TabTrigger name="home" href="/"><Text>Home</Text></TabTrigger><TabTrigger name="article" href="/article"><Text>Article</Text></TabTrigger></TabList></Tabs>);
}

在 TabTrigger 内自由设计每个 tab 项的元素和样式。

更多详情可参考官网

高亮选中的 tab

  1. 获取当前路由
import { usePathname } from "expo-router";
const active_href = usePathname();
  1. 根据当前路由,渲染高亮样式
const active_tab_color = "red";
<Textstyle={{color:tab.href === active_href ? active_tab_color : "black",}}
>{tab.label}
</Text>

选择图片

安装依赖

npx expo install expo-image-picker

utils/imagePicker.ts

import * as ImagePicker from "expo-image-picker";
import { Alert } from "react-native";
// 请求相机胶卷权限
export const requestGalleryPermission = async (): Promise<boolean> => {const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();if (status !== "granted") {Alert.alert("权限拒绝", "需要相机胶卷权限才能选择图片");return false;}return true;
};
// 从相机胶卷选择图片
export const pickImage = async (): Promise<string | undefined> => {const hasPermission = await requestGalleryPermission();if (!hasPermission) return;const result = await ImagePicker.launchImageLibraryAsync({mediaTypes: "images",allowsEditing: true,aspect: [4, 3],quality: 1,});if (!result.canceled && result.assets?.length > 0) {return result.assets[0].uri;}
};
// 请求相机权限
export const requestCameraPermission = async (): Promise<boolean> => {const { status } = await ImagePicker.requestCameraPermissionsAsync();if (status !== "granted") {Alert.alert("权限拒绝", "需要相机权限才能拍照");return false;}return true;
};
// 使用相机拍照
export const takePhoto = async (): Promise<string | undefined> => {const hasPermission = await requestCameraPermission();if (!hasPermission) return;const result = await ImagePicker.launchCameraAsync({mediaTypes: "images",allowsEditing: true,aspect: [4, 3],quality: 1,});if (!result.canceled && result.assets?.length > 0) {return result.assets[0].uri;}
};

页面使用

import { pickImage } from "@/utils/imagePicker";
  const onPublishPress = async () => {const imageUri = await pickImage();if (imageUri) {console.log("选择的图片的URI:", imageUri);}};

代码实现

创建各 tab 对应的页面

  • app/(tabs)/index.tsx
  • app/(tabs)/message.tsx
  • app/(tabs)/mine.tsx
  • app/(tabs)/shop.tsx

因暂无内容,放下方初始模板即可。

import { StyleSheet, Text, View } from "react-native";
export default function IndexScreen() {return (<View style={styles.page}><Text>首页</Text></View>);
}
const styles = StyleSheet.create({page: {},
});

app/(tabs)/_layout.tsx

import icon_tab_publish from "@/assets/images/icon_tab_publish.png";
import { pickImage } from "@/utils/imagePicker";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import { usePathname } from "expo-router";
import { TabList, Tabs, TabSlot, TabTrigger } from "expo-router/ui";
import React from "react";
import { Image, Text, TouchableOpacity } from "react-native";
export default function TabLayout() {const active_href = usePathname();const active_tab_color = "red";const tabs = [{href: "/",name: "index",label: "首页",icon: "home",},{href: "/shop",name: "shop",label: "购物",icon: "shopping-cart",},{href: "/publish",name: "publish",label: "发布",icon: "publish",},{href: "/message",name: "message",label: "消息",icon: "message",},{href: "/mine",name: "mine",label: "我",icon: "person",},];const onPublishPress = async () => {const imageUri = await pickImage();if (imageUri) {console.log("Selected image URI:", imageUri);}};return (<Tabs><TabSlot /><TabList>{tabs.map((tab, index: number) => {if (index === 2) {return (<TouchableOpacitykey={tab.name}style={{flex: 1,justifyContent: "center",alignItems: "center",marginHorizontal: 20,}}onPress={onPublishPress}><Imagestyle={{width: 58,height: 42,resizeMode: "contain",}}source={icon_tab_publish}/></TouchableOpacity>);} else {return (<TabTriggerkey={tab.name}name={tab.name}href={tab.href as "/"}style={{flex: 1,alignItems: "center",justifyContent: "center",padding: 10,}}><MaterialIconsname={tab.icon as "home" | "shopping-cart" | "message" | "person"}size={24}color={tab.href === active_href ? active_tab_color : "black"}/><Textstyle={{color:tab.href === active_href ? active_tab_color : "black",}}>{tab.label}</Text></TabTrigger>);}})}</TabList></Tabs>);
}

图片素材

assets/images/icon_tab_publish.png

在这里插入图片描述

http://www.lryc.cn/news/579531.html

相关文章:

  • GPT-2论文阅读:Language Models are Unsupervised Multitask Learners
  • Mac电脑 触摸板增强工具 BetterTouchTool
  • 探秘展销编辑器:相较于传统展销的卓越优势与甄选指南​
  • Redis实现哨兵模式
  • MCP协议打破数据孤岛
  • 在Ubuntu24上安装ollama
  • VsCode 配置 C/C++ 开发环境
  • 【第三章:神经网络原理详解与Pytorch入门】01.神经网络算法理论详解与实践-(3)神经网络中的前向传播、反向传播的原理与实现
  • JavaScript的初步学习
  • 2021/7 N2 jlpt 词汇
  • npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
  • Apache POI 详解 - Java 操作 Excel/Word/PPT
  • docker-compose一键部署全栈项目。springboot后端,react前端
  • 如何将信息从 iPhone 同步到Mac(完整步骤和示意图)
  • mac 电脑安装Homebrew来安装npm与node成功后,安装nvm的流程
  • MySQL 8.0 OCP 1Z0-908 题目解析(19)
  • 标准测试测试数据STDF学习笔记
  • MediaCrawler:强大的自媒体平台爬虫工具
  • Spring Boot 多 ActiveMQ 通道配置与多连接消息发送实战(含完整示例与踩坑记录)
  • Ubuntu 24.04 LTS 服务器配置:安装 JDK、Nginx、Redis。
  • 一体机电脑为何热度持续上升?消费者更看重哪些功能?
  • 关于系统无法找到 arm-linux-gcc 命令,这表明你的环境中尚未安装 ARM 交叉编译工具链。以下是详细的解决方案:(DIY机器人工房)
  • 牛客:HJ16 购物单【01背包】【华为机考】
  • 封装 获取paramsByKey 方法
  • 毕业设计(启智模块化机器人的组装与K5的使用
  • 使用Visual Studio 2022创建CUDA编程项目
  • 车载交换机动态MAC学习和静态MAC绑定如何获取MAC地址表
  • jenkins角色权限
  • 这才叫窗口查询!TDEngine官方文档没讲透的实战玩法
  • 微信小程序41~50