概述

本文分析的是一个基于React Native构建的附近的人发现应用,集成了地理位置筛选、实时状态监测、个性化推荐等核心功能。该应用采用了多维度用户画像、智能筛选算法和实时交互设计,展现了位置社交类应用的典型技术架构。在鸿蒙OS的跨端适配场景中,这种涉及地理位置和实时状态的应用具有重要的技术参考价值。

核心架构设计深度解析

地理位置数据模型设计

应用定义了完整的附近用户数据结构:

type NearbyUser = {
  id: string;
  name: string;
  age: number;
  distance: number; // 距离(公里)
  lastSeen: string; // 最后在线时间
  bio: string;
  commonInterests: string[];
  isOnline: boolean;
  isFavorite: boolean;
};

这种数据结构设计体现了位置社交的核心维度:基础信息(姓名、年龄)、地理位置(距离、最后在线)、个人特征(简介、兴趣)和状态标记(在线状态、收藏状态)。distance字段实现了基于公里的距离量化,为后续的筛选和排序提供了数据基础。

在鸿蒙ArkUI体系中,接口定义保持了相同的结构:

interface NearbyUser {
  id: string;
  name: string;
  age: number;
  distance: number;
  lastSeen: string;
  bio: string;
  commonInterests: string[];
  isOnline: boolean;
  isFavorite: boolean;
}

多维度筛选与排序系统

应用实现了复杂的筛选和排序算法:

// 根据筛选条件过滤用户
const filteredUsers = users.filter(user => {
  if (distanceFilter === '1km' && user.distance > 1) return false;
  if (distanceFilter === '2km' && user.distance > 2) return false;
  if (distanceFilter === '5km' && user.distance > 5) return false;
  
  if (onlineFilter === 'online' && !user.isOnline) return false;
  if (onlineFilter === 'offline' && user.isOnline) return false;
  
  return true;
});

// 根据排序方式排序
const sortedUsers = [...filteredUsers].sort((a, b) => {
  if (sortBy === 'distance') {
    return a.distance - b.distance; // 距离升序
  } else if (sortBy === 'lastSeen') {
    return a.lastSeen.localeCompare(b.lastSeen); // 时间比较
  } else { // commonInterest
    return b.commonInterests.length - a.commonInterests.length; // 兴趣数量降序
  }
});

这种处理模式采用了链式操作:先filter筛选再sort排序。展开运算符[…filteredUsers]确保了排序操作不会影响原始数据。多种排序策略提供了灵活的展示选项。

鸿蒙的实现采用计算属性模式:

@State users: NearbyUser[] = [];
@State distanceFilter: string = 'all';
@State onlineFilter: string = 'all';
@State sortBy: string = 'distance';

// 筛选后的用户
get filteredUsers(): NearbyUser[] {
  return this.users.filter(user => {
    if (this.distanceFilter === '1km' && user.distance > 1) return false;
    if (this.distanceFilter === '2km' && user.distance > 2) return false;
    if (this.distanceFilter === '5km' && user.distance > 5) return false;
    
    if (this.onlineFilter === 'online' && !user.isOnline) return false;
    if (this.onlineFilter === 'offline' && user.isOnline) return false;
    
    return true;
  });
}

// 排序后的用户
get sortedUsers(): NearbyUser[] {
  return [...this.filteredUsers].sort((a, b) => {
    if (this.sortBy === 'distance') {
      return a.distance - b.distance;
    } else if (this.sortBy === 'lastSeen') {
      return a.lastSeen.localeCompare(b.lastSeen);
    } else {
      return b.commonInterests.length - a.commonInterests.length;
    }
  });
}

状态可视化展示系统

NearbyUserCard组件实现了丰富的状态展示:

const NearbyUserCard = ({ user, onSendMessage, onAddFriend, onToggleFavorite }) => {
  return (
    <View style={styles.userCard}>
      <View style={styles.userHeader}>
        <View style={styles.userAvatar}>
          <Text style={styles.avatarText}>{ICONS.user}</Text>
        </View>
        <View style={styles.userInfo}>
          <View style={styles.userDetails}>
            <Text style={styles.userName}>{user.name}, {user.age}</Text>
            <View style={styles.statusContainer}>
              <View style={[styles.statusDot, user.isOnline ? styles.onlineStatus : styles.offlineStatus]} />
              <Text style={styles.statusText}>{user.isOnline ? '在线' : '离线'}</Text>
            </View>
          </View>
          <View style={styles.distanceContainer}>
            <Text style={styles.locationIcon}>{ICONS.location}</Text>
            <Text style={styles.distanceText}>{user.distance} km</Text>
          </View>
        </View>
      </View>
      
      {/* 更多内容 */}
    </View>
  );
};

这种设计采用了视觉化状态指示器:圆形状态点通过条件样式显示不同颜色(在线绿色、离线灰色),距离信息结合定位图标提供直观的地理感知。slice(0,3)限制了兴趣标签的显示数量,保持了界面的整洁性。

鸿蒙的实现需要将样式逻辑转换为声明式结构:

@Component
struct NearbyUserCard {
  @Prop user: NearbyUser;
  
  build() {
    Column() {
      Row() {
        // 头像
        Column() { Text('👤') }
        
        // 用户信息
        Column() {
          Text(`${this.user.name}, ${this.user.age}`)
          
          // 状态指示器
          Row() {
            Circle()
              .width(8).height(8)
              .fill(this.user.isOnline ? Color.Green : Color.Gray)
            Text(this.user.isOnline ? '在线' : '离线')
          }
        }
        
        // 距离信息
        Row() {
          Text('📍')
          Text(`${this.user.distance} km`)
        }
      }
      
      // 个人简介和兴趣
      Text(this.user.bio)
      Row() {
        ForEach(this.user.commonInterests.slice(0, 3), (interest: string) => {
          Text(interest)
        })
      }
    }
  }
}

跨端适配技术方案

组件映射策略

React Native组件 鸿蒙ArkUI组件 关键适配点
FlatList List 列表实现和性能优化
TouchableOpacity Button 交互反馈机制不同
ScrollView Scroll 滚动行为一致
View Column/Row/Stack 布局系统转换

样式系统转换

// React Native
statusDot: {
  width: 8,
  height: 8,
  borderRadius: 4,
  marginRight: 4,
},
onlineStatus: {
  backgroundColor: '#10b981',
},

// 鸿蒙
Circle()
  .width(8).height(8)
  .fill(Color.Green)

状态管理迁移

// React Native
const [users, setUsers] = useState<NearbyUser[]>([]);
const [distanceFilter, setDistanceFilter] = useState('all');

// 鸿蒙
@State users: NearbyUser[] = [];
@State distanceFilter: string = 'all';

性能优化与最佳实践

列表渲染优化

配置keyExtractor提升列表性能:

<FlatList
  data={sortedUsers}
  keyExtractor={item => item.id}
  renderItem={({ item }) => <NearbyUserCard user={item} />}
/>

筛选计算优化

使用useMemo避免重复计算:

const sortedUsers = useMemo(() => {
  const filtered = users.filter(user => {
    // 筛选逻辑
  });
  return [...filtered].sort((a, b) => {
    // 排序逻辑
  });
}, [users, distanceFilter, onlineFilter, sortBy]);

架构与数据建模的语义边界
这段代码以 NearbyUser 类型为中心构建页面语义,字段拆分清晰地覆盖了人设展示(name、age、bio)、活跃状态(isOnline、lastSeen)、社交意向(isFavorite)与关系契合度(commonInterests)。这种“展示模型 + 交互标志”的组合非常适合跨端桥接:鸿蒙端只需遵循同一数据契约即可在 ArkUI 层稳定渲染与分发事件。建议将 lastSeen 以数值时间戳或 ISO 字符串存储,展示层再格式化为相对时间,避免当前字符串比较造成排序不稳定;距离则统一以米/千米做单位换算,确保端上格式一致。

组件栈与交互语义
NearbyUserCard 承载了用户基本信息、在线状态、距离、兴趣标签与三类操作按钮(收藏/消息/添加),通过 onSendMessage、onAddFriend、onToggleFavorite 明确把“动作”的意义抽象为事件,而不是和样式或平台能力耦合。FilterOption 将筛选项抽象为“可选标签 + 选中态”,上层只传递 isSelected 与 onPress,使得筛选 UI 能自由替换为鸿蒙端的 ArkUI 组件而不改变业务语义。页面组件 NearbyPeopleApp 则组合统计区、筛选区与列表区,把“附近的人”这个场景分解为三层:数据统计、筛选状态机、列表渲染,这正是跨端结构化的合理落点。

筛选与排序的轻量状态机
页面维护了 distanceFilter、onlineFilter 与 sortBy 三个维度,使用 filter → sort 的顺序派生出最终渲染列表。派生过程建议用 useMemo 包裹,依赖 users、distanceFilter、onlineFilter、sortBy,减少不必要重算与重渲染,尤其在鸿蒙端桥接场景下能明显降低跨层事件与 UI 刷新次数。收藏切换当前用 setUsers(users.map(…)) 实现不可变更新,为防止闭包旧值导致快速连点时状态回跳,采用函数式更新 setUsers(prev => prev.map(…)) 更稳妥;事件处理器也应通过 useCallback 固定引用,从而减少子组件的无效更新。

列表与虚拟化的跨端调优
附近用户列表使用 FlatList 并通过 ListHeaderComponent 衔接统计文案,是 RN 侧组织内容的典型手段。双横向筛选条采用多个水平 ScrollView 组合,在 RN 端是合理方案;在鸿蒙端需要注意滚动物理与事件节流,在 RN 侧为列表设置合适的 initialNumToRender、windowSize、removeClippedSubviews,并在尺寸可预期时提供 getItemLayout,使渲染与回收行为更可控。ArkUI 侧的滚动与曝光埋点建议走统一抽象,避免每个列表项单独上报造成跨端事件风暴。

能力桥接与操作统一
当前消息与加好友采用 Alert 作为占位提示,生产实现建议抽象为“能力服务层”:在 RN 端定义 sendMessage(userId, payload)、addFriend(userId) 这类语义化 API;在鸿蒙端以 ArkUI 或 AbilityBridge 实现具体能力,包括权限申请、失败重试、队列与离线缓存。收藏操作作为纯本地状态更新,也应该在桥接层同时支持“服务器确认”的异步流,以便在端上做乐观更新与失败回滚,保证跨端一致的交互体验。

性能与可观测性闭环
列表 keyExtractor 稳定使用 item.id,有助于 RN 侧复用与鸿蒙端桥接的识别。交互埋点建议统一事件名与属性协议,例如 favorite_toggle、message_click、add_friend_click,并在桥接层聚合上报,减少端间差异。网络错误与权限拒绝应在能力服务层完成统一处理,页面只关心展示与重试语义,从而让跨端差异被封装起来,避免散落在组件中。

权限与隐私的工程边界
“附近的人”往往涉及定位能力与相邻用户聚合,这在鸿蒙端必须通过明确的权限申请与最小化数据原则来实现。建议把定位与刷新能力封装为“位置服务”,在 RN 层提供 refreshNearbyUsers 的语义,而在 ArkUI 侧处理权限弹窗、后台更新策略与低功耗配置。用户资料属于敏感数据,应统一通过安全存储或加密传输,并在端上提供“清理缓存/撤回授权”的一致入口。

跨端一致性的落点
把“页面语义”与“平台能力”解耦是贯穿始终的原则:上层组件只描述展示与交互意图,中层服务抽象统一输入/输出与错误语义,底层桥接实现鸿蒙的 ArkUI/Ability 能力。列表虚拟化、筛选状态机、能力服务与图标抽象这四个层面一旦建立,React Native 与鸿蒙端就能在同一语义下演进,平台差异被边界化在可控的实现细节里,既可维护又可测试。


完整代码code:

// app.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, FlatList } from 'react-native';

// 图标库
const ICONS = {
  user: '👤',
  location: '📍',
  message: '💬',
  add: '➕',
  heart: '❤️',
  phone: '📞',
  filter: '🔍',
  refresh: '🔄',
};

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

// 用户类型
type NearbyUser = {
  id: string;
  name: string;
  age: number;
  distance: number; // 距离(公里)
  lastSeen: string; // 最后在线时间
  bio: string;
  commonInterests: string[];
  isOnline: boolean;
  isFavorite: boolean;
};

// 附近用户卡片组件
const NearbyUserCard = ({ 
  user, 
  onSendMessage,
  onAddFriend,
  onToggleFavorite
}: { 
  user: NearbyUser; 
  onSendMessage: (id: string) => void;
  onAddFriend: (id: string) => void;
  onToggleFavorite: (id: string) => void;
}) => {
  return (
    <View style={styles.userCard}>
      <View style={styles.userHeader}>
        <View style={styles.userAvatar}>
          <Text style={styles.avatarText}>{ICONS.user}</Text>
        </View>
        <View style={styles.userInfo}>
          <View style={styles.userDetails}>
            <Text style={styles.userName}>{user.name}, {user.age}</Text>
            <View style={styles.statusContainer}>
              <View style={[styles.statusDot, user.isOnline ? styles.onlineStatus : styles.offlineStatus]} />
              <Text style={styles.statusText}>{user.isOnline ? '在线' : '离线'}</Text>
            </View>
          </View>
          <View style={styles.distanceContainer}>
            <Text style={styles.locationIcon}>{ICONS.location}</Text>
            <Text style={styles.distanceText}>{user.distance} km</Text>
          </View>
        </View>
      </View>
      
      <Text style={styles.userBio}>{user.bio}</Text>
      
      <View style={styles.interestsContainer}>
        {user.commonInterests.slice(0, 3).map((interest, index) => (
          <View key={index} style={styles.interestTag}>
            <Text style={styles.interestText}>{interest}</Text>
          </View>
        ))}
      </View>
      
      <View style={styles.lastSeenContainer}>
        <Text style={styles.lastSeenText}>最后在线: {user.lastSeen}</Text>
      </View>
      
      <View style={styles.cardActions}>
        <TouchableOpacity 
          style={[styles.actionButton, styles.favoriteButton, user.isFavorite && styles.favoritedButton]} 
          onPress={() => onToggleFavorite(user.id)}
        >
          <Text style={[styles.actionText, user.isFavorite && styles.favoritedText]}>
            {user.isFavorite ? ICONS.heart : '🤍'} 收藏
          </Text>
        </TouchableOpacity>
        <TouchableOpacity 
          style={[styles.actionButton, styles.messageButton]} 
          onPress={() => onSendMessage(user.id)}
        >
          <Text style={styles.actionText}>{ICONS.message} 消息</Text>
        </TouchableOpacity>
        <TouchableOpacity 
          style={[styles.actionButton, styles.addButton]} 
          onPress={() => onAddFriend(user.id)}
        >
          <Text style={styles.actionText}>{ICONS.add} 添加</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};

// 筛选选项组件
const FilterOption = ({ label, value, isSelected, onPress }: { 
  label: string; 
  value: string; 
  isSelected: boolean; 
  onPress: () => void 
}) => {
  return (
    <TouchableOpacity 
      style={[styles.filterOption, isSelected && styles.selectedFilterOption]} 
      onPress={onPress}
    >
      <Text style={[styles.filterText, isSelected && styles.selectedFilterText]}>{label}</Text>
    </TouchableOpacity>
  );
};

// 主页面组件
const NearbyPeopleApp: React.FC = () => {
  const [users, setUsers] = useState<NearbyUser[]>([
    {
      id: '1',
      name: '张小明',
      age: 28,
      distance: 0.5,
      lastSeen: '刚刚',
      bio: '喜欢摄影和旅行,周末经常去户外徒步',
      commonInterests: ['摄影', '旅行', '户外'],
      isOnline: true,
      isFavorite: false
    },
    {
      id: '2',
      name: '李小红',
      age: 25,
      distance: 1.2,
      lastSeen: '5分钟前',
      bio: '健身爱好者,专注于瑜伽和普拉提',
      commonInterests: ['健身', '瑜伽', '健康生活'],
      isOnline: true,
      isFavorite: true
    },
    {
      id: '3',
      name: '王大伟',
      age: 32,
      distance: 2.8,
      lastSeen: '1小时前',
      bio: '程序员,喜欢科技和游戏',
      commonInterests: ['编程', '游戏', '科技'],
      isOnline: false,
      isFavorite: false
    },
    {
      id: '4',
      name: '陈美丽',
      age: 27,
      distance: 0.8,
      lastSeen: '刚刚',
      bio: '美食博主,擅长制作各种甜品',
      commonInterests: ['美食', '烘焙', '烹饪'],
      isOnline: true,
      isFavorite: false
    },
    {
      id: '5',
      name: '刘小华',
      age: 30,
      distance: 3.5,
      lastSeen: '2小时前',
      bio: '音乐老师,喜欢吉他和创作',
      commonInterests: ['音乐', '吉他', '创作'],
      isOnline: false,
      isFavorite: true
    }
  ]);

  const [distanceFilter, setDistanceFilter] = useState('all'); // all, 1km, 2km, 5km
  const [onlineFilter, setOnlineFilter] = useState('all'); // all, online, offline
  const [sortBy, setSortBy] = useState('distance'); // distance, lastSeen, commonInterest

  const handleSendMessage = (id: string) => {
    Alert.alert('发送消息', `${users.find(u => u.id === id)?.name} 发送消息`);
  };

  const handleAddFriend = (id: string) => {
    Alert.alert('添加好友', `已向 ${users.find(u => u.id === id)?.name} 发送好友请求`);
  };

  const handleToggleFavorite = (id: string) => {
    setUsers(users.map(user => 
      user.id === id 
        ? { ...user, isFavorite: !user.isFavorite } 
        : user
    ));
  };

  const refreshNearbyUsers = () => {
    Alert.alert('刷新', '正在为您查找附近的人...');
  };

  // 根据筛选条件过滤用户
  const filteredUsers = users.filter(user => {
    if (distanceFilter === '1km' && user.distance > 1) return false;
    if (distanceFilter === '2km' && user.distance > 2) return false;
    if (distanceFilter === '5km' && user.distance > 5) return false;
    
    if (onlineFilter === 'online' && !user.isOnline) return false;
    if (onlineFilter === 'offline' && user.isOnline) return false;
    
    return true;
  });

  // 根据排序方式排序
  const sortedUsers = [...filteredUsers].sort((a, b) => {
    if (sortBy === 'distance') {
      return a.distance - b.distance;
    } else if (sortBy === 'lastSeen') {
      // 简化处理,实际应用中需要更复杂的比较逻辑
      return a.lastSeen.localeCompare(b.lastSeen);
    } else { // commonInterest
      return b.commonInterests.length - a.commonInterests.length;
    }
  });

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>附近的人</Text>
        <TouchableOpacity style={styles.refreshButton} onPress={refreshNearbyUsers}>
          <Text style={styles.refreshText}>{ICONS.refresh} 刷新</Text>
        </TouchableOpacity>
      </View>

      {/* 统计信息 */}
      <View style={styles.statsContainer}>
        <View style={styles.statItem}>
          <Text style={styles.statNumber}>{users.length}</Text>
          <Text style={styles.statLabel}>附近用户</Text>
        </View>
        <View style={styles.statItem}>
          <Text style={styles.statNumber}>
            {users.filter(u => u.isOnline).length}
          </Text>
          <Text style={styles.statLabel}>在线用户</Text>
        </View>
        <View style={styles.statItem}>
          <Text style={styles.statNumber}>
            {users.filter(u => u.isFavorite).length}
          </Text>
          <Text style={styles.statLabel}>收藏用户</Text>
        </View>
      </View>

      {/* 筛选选项 */}
      <View style={styles.filtersContainer}>
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <View style={styles.filtersRow}>
            <Text style={styles.filterCategory}>距离:</Text>
            <FilterOption 
              label="全部" 
              value="all" 
              isSelected={distanceFilter === 'all'} 
              onPress={() => setDistanceFilter('all')} 
            />
            <FilterOption 
              label="1km内" 
              value="1km" 
              isSelected={distanceFilter === '1km'} 
              onPress={() => setDistanceFilter('1km')} 
            />
            <FilterOption 
              label="2km内" 
              value="2km" 
              isSelected={distanceFilter === '2km'} 
              onPress={() => setDistanceFilter('2km')} 
            />
            <FilterOption 
              label="5km内" 
              value="5km" 
              isSelected={distanceFilter === '5km'} 
              onPress={() => setDistanceFilter('5km')} 
            />
          </View>
        </ScrollView>
        
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <View style={styles.filtersRow}>
            <Text style={styles.filterCategory}>状态:</Text>
            <FilterOption 
              label="全部" 
              value="all" 
              isSelected={onlineFilter === 'all'} 
              onPress={() => setOnlineFilter('all')} 
            />
            <FilterOption 
              label="在线" 
              value="online" 
              isSelected={onlineFilter === 'online'} 
              onPress={() => setOnlineFilter('online')} 
            />
            <FilterOption 
              label="离线" 
              value="offline" 
              isSelected={onlineFilter === 'offline'} 
              onPress={() => setOnlineFilter('offline')} 
            />
          </View>
        </ScrollView>
        
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <View style={styles.filtersRow}>
            <Text style={styles.filterCategory}>排序:</Text>
            <FilterOption 
              label="距离" 
              value="distance" 
              isSelected={sortBy === 'distance'} 
              onPress={() => setSortBy('distance')} 
            />
            <FilterOption 
              label="活跃度" 
              value="lastSeen" 
              isSelected={sortBy === 'lastSeen'} 
              onPress={() => setSortBy('lastSeen')} 
            />
            <FilterOption 
              label="兴趣" 
              value="commonInterest" 
              isSelected={sortBy === 'commonInterest'} 
              onPress={() => setSortBy('commonInterest')} 
            />
          </View>
        </ScrollView>
      </View>

      {/* 附近用户列表 */}
      <FlatList
        data={sortedUsers}
        keyExtractor={item => item.id}
        renderItem={({ item }) => (
          <NearbyUserCard
            user={item}
            onSendMessage={handleSendMessage}
            onAddFriend={handleAddFriend}
            onToggleFavorite={handleToggleFavorite}
          />
        )}
        style={styles.usersList}
        showsVerticalScrollIndicator={false}
        ListHeaderComponent={
          <Text style={styles.sectionTitle}>附近的人 ({sortedUsers.length})</Text>
        }
      />

      {/* 底部导航 */}
      <View style={styles.bottomNav}>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.location}</Text>
          <Text style={styles.navText}>附近</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.message}</Text>
          <Text style={styles.navText}>消息</Text>
        </TouchableOpacity>
        <TouchableOpacity style={[styles.navItem, styles.activeNavItem]}>
          <Text style={styles.navIcon}>{ICONS.user}</Text>
          <Text style={styles.navText}>我的</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.navItem}>
          <Text style={styles.navIcon}>{ICONS.filter}</Text>
          <Text style={styles.navText}>筛选</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f8fafc',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 20,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#e2e8f0',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  refreshButton: {
    backgroundColor: '#3b82f6',
    paddingHorizontal: 16,
    paddingVertical: 8,
    borderRadius: 20,
  },
  refreshText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
  statsContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    padding: 16,
    backgroundColor: '#ffffff',
    marginBottom: 16,
  },
  statItem: {
    alignItems: 'center',
  },
  statNumber: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#3b82f6',
  },
  statLabel: {
    fontSize: 12,
    color: '#64748b',
    marginTop: 4,
  },
  filtersContainer: {
    backgroundColor: '#ffffff',
    paddingHorizontal: 16,
    marginBottom: 16,
  },
  filtersRow: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingVertical: 8,
  },
  filterCategory: {
    fontSize: 14,
    color: '#1e293b',
    marginRight: 8,
    fontWeight: '500',
  },
  filterOption: {
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 16,
    backgroundColor: '#f1f5f9',
    marginRight: 8,
  },
  selectedFilterOption: {
    backgroundColor: '#3b82f6',
  },
  filterText: {
    fontSize: 12,
    color: '#64748b',
  },
  selectedFilterText: {
    color: '#ffffff',
  },
  usersList: {
    flex: 1,
    paddingHorizontal: 16,
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#1e293b',
    marginVertical: 12,
  },
  userCard: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 16,
    elevation: 1,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
  },
  userHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 12,
  },
  userAvatar: {
    width: 50,
    height: 50,
    borderRadius: 25,
    backgroundColor: '#dbeafe',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 12,
  },
  avatarText: {
    fontSize: 24,
    color: '#3b82f6',
  },
  userInfo: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  userDetails: {
    flex: 1,
  },
  userName: {
    fontSize: 16,
    fontWeight: 'bold',
    color: '#1e293b',
  },
  statusContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    marginTop: 4,
  },
  statusDot: {
    width: 8,
    height: 8,
    borderRadius: 4,
    marginRight: 4,
  },
  onlineStatus: {
    backgroundColor: '#10b981',
  },
  offlineStatus: {
    backgroundColor: '#94a3b8',
  },
  statusText: {
    fontSize: 12,
    color: '#64748b',
  },
  distanceContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  locationIcon: {
    fontSize: 14,
    color: '#64748b',
    marginRight: 4,
  },
  distanceText: {
    fontSize: 12,
    color: '#64748b',
  },
  userBio: {
    fontSize: 14,
    color: '#334155',
    lineHeight: 20,
    marginBottom: 12,
  },
  interestsContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    marginBottom: 8,
  },
  interestTag: {
    backgroundColor: '#f1f5f9',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
    marginRight: 8,
    marginBottom: 4,
  },
  interestText: {
    fontSize: 12,
    color: '#475569',
  },
  lastSeenContainer: {
    marginBottom: 12,
  },
  lastSeenText: {
    fontSize: 12,
    color: '#64748b',
  },
  cardActions: {
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  actionButton: {
    flex: 1,
    padding: 10,
    borderRadius: 8,
    alignItems: 'center',
    marginHorizontal: 2,
  },
  favoriteButton: {
    backgroundColor: '#f1f5f9',
  },
  favoritedButton: {
    backgroundColor: '#fee2e2',
  },
  messageButton: {
    backgroundColor: '#e0f2fe',
  },
  addButton: {
    backgroundColor: '#3b82f6',
  },
  actionText: {
    fontSize: 12,
    fontWeight: '500',
    color: '#64748b',
  },
  favoritedText: {
    color: '#ef4444',
  },
  bottomNav: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#e2e8f0',
    paddingVertical: 12,
  },
  navItem: {
    alignItems: 'center',
    flex: 1,
  },
  activeNavItem: {
    paddingBottom: 2,
    borderBottomWidth: 2,
    borderBottomColor: '#3b82f6',
  },
  navIcon: {
    fontSize: 20,
    color: '#94a3b8',
    marginBottom: 4,
  },
  activeNavIcon: {
    color: '#3b82f6',
  },
  navText: {
    fontSize: 12,
    color: '#94a3b8',
  },
  activeNavText: {
    color: '#3b82f6',
    fontWeight: '500',
  },
});

export default NearbyPeopleApp;

请添加图片描述

打包

接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

在这里插入图片描述

打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:

在这里插入图片描述

最后运行效果图如下显示:

请添加图片描述

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐