在这里插入图片描述

前言

社交分享是现代运动应用中提升用户粘性和传播效果的重要功能。用户希望能够将自己的运动成果分享给朋友,获得认可和鼓励。本文将详细介绍如何在Flutter与OpenHarmony平台上实现一个完善的社交分享组件,包括运动数据卡片生成、多平台分享、好友互动、排行榜等功能模块的完整实现方案。

社交分享功能的设计需要考虑用户体验和隐私保护的平衡。我们要让分享过程简单快捷,同时给用户足够的控制权来选择分享的内容和范围。精美的分享卡片设计能够提升用户的分享意愿,也能为应用带来更好的传播效果。

Flutter分享数据模型

class ShareableWorkout {
  final String id;
  final String activityType;
  final Duration duration;
  final double distance;
  final double calories;
  final DateTime date;
  final String? imageUrl;
  final List<String> achievements;
  
  ShareableWorkout({
    required this.id,
    required this.activityType,
    required this.duration,
    required this.distance,
    required this.calories,
    required this.date,
    this.imageUrl,
    this.achievements = const [],
  });
  
  String get formattedDuration {
    int hours = duration.inHours;
    int minutes = duration.inMinutes % 60;
    return hours > 0 ? '${hours}小时${minutes}分钟' : '${minutes}分钟';
  }
  
  String get shareText {
    return '我刚完成了一次$activityType运动!用时$formattedDuration,消耗${calories.toInt()}千卡热量。#运动打卡';
  }
}

分享数据模型封装了可分享的运动信息。模型包含运动类型、时长、距离、卡路里、日期等核心数据,以及可选的运动图片和获得的成就列表。formattedDuration属性将时长格式化为易读的中文格式,根据是否超过1小时显示不同的格式。shareText属性生成默认的分享文案,包含运动类型、时长和卡路里消耗,末尾添加话题标签便于社交平台的内容聚合。这种设计让分享内容既信息丰富又简洁明了,适合在各种社交平台传播。

OpenHarmony系统分享服务

import share from '@ohos.app.ability.ShareExtensionAbility';
import common from '@ohos.app.ability.common';

class SystemShareService {
  async shareText(context: common.UIAbilityContext, text: string): Promise<void> {
    let shareData: common.ShareData = {
      type: 'text/plain',
      data: text,
    };
    
    await context.startAbility({
      action: 'ohos.want.action.select',
      type: 'text/plain',
      parameters: {
        'shareData': shareData,
      }
    });
  }
  
  async shareImage(context: common.UIAbilityContext, imagePath: string, text: string): Promise<void> {
    await context.startAbility({
      action: 'ohos.want.action.select',
      type: 'image/*',
      parameters: {
        'stream': imagePath,
        'text': text,
      }
    });
  }
}

系统分享服务调用OpenHarmony的系统分享能力,让用户可以将内容分享到任何支持的应用。shareText方法分享纯文本内容,通过startAbility启动系统的分享选择器,用户可以选择微信、微博等已安装的社交应用。shareImage方法分享图片和文字的组合,type设为image/*表示分享图片类型的内容。这种方式利用系统能力,无需为每个社交平台单独集成SDK,大大简化了开发工作,同时支持用户设备上安装的所有分享目标应用。

Flutter分享卡片组件

class WorkoutShareCard extends StatelessWidget {
  final ShareableWorkout workout;
  
  const WorkoutShareCard({Key? key, required this.workout}) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      padding: EdgeInsets.all(20),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Color(0xFF667eea), Color(0xFF764ba2)],
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
        ),
        borderRadius: BorderRadius.circular(20),
        boxShadow: [
          BoxShadow(color: Colors.black26, blurRadius: 10, offset: Offset(0, 4)),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Icon(Icons.fitness_center, color: Colors.white, size: 24),
              SizedBox(width: 8),
              Text(workout.activityType, style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
            ],
          ),
          SizedBox(height: 20),
          _buildStatRow('时长', workout.formattedDuration),
          _buildStatRow('距离', '${workout.distance.toStringAsFixed(2)} km'),
          _buildStatRow('消耗', '${workout.calories.toInt()} 千卡'),
          SizedBox(height: 16),
          Text(_formatDate(workout.date), style: TextStyle(color: Colors.white70, fontSize: 12)),
        ],
      ),
    );
  }
  
  Widget _buildStatRow(String label, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: TextStyle(color: Colors.white70)),
          Text(value, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
        ],
      ),
    );
  }
  
  String _formatDate(DateTime date) {
    return '${date.year}${date.month}${date.day}日';
  }
}

分享卡片组件生成精美的运动数据展示卡片。我们使用渐变背景和阴影效果创造视觉吸引力,紫色渐变传达运动的活力感。卡片顶部显示运动类型和图标,中间部分以清晰的行格式展示时长、距离和卡路里三个核心数据,底部显示运动日期。白色文字在渐变背景上清晰可读,不同层级的信息使用不同的透明度区分。这种设计的卡片在社交平台上分享时能够吸引眼球,展示用户的运动成果,同时也是应用的品牌展示。

Flutter卡片截图服务

class CardScreenshotService {
  static Future<Uint8List?> captureCard(GlobalKey cardKey) async {
    try {
      RenderRepaintBoundary boundary = 
          cardKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
      ui.Image image = await boundary.toImage(pixelRatio: 3.0);
      ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
      return byteData?.buffer.asUint8List();
    } catch (e) {
      print('截图失败: $e');
      return null;
    }
  }
  
  static Future<String?> saveToFile(Uint8List imageData, String fileName) async {
    try {
      final directory = await getTemporaryDirectory();
      final filePath = '${directory.path}/$fileName.png';
      final file = File(filePath);
      await file.writeAsBytes(imageData);
      return filePath;
    } catch (e) {
      print('保存失败: $e');
      return null;
    }
  }
}

卡片截图服务将Flutter组件转换为可分享的图片。captureCard方法使用RepaintBoundary和GlobalKey定位要截图的组件,toImage方法将组件渲染为图片,pixelRatio设为3.0确保高清晰度。图片数据转换为PNG格式的字节数组,便于后续处理。saveToFile方法将图片数据保存到临时目录,返回文件路径用于分享。这种方式让用户可以将精心设计的分享卡片作为图片分享到任何平台,保持一致的视觉效果,不受平台限制。

OpenHarmony好友关系服务

import relationalStore from '@ohos.data.relationalStore';

class FriendshipService {
  private rdbStore: relationalStore.RdbStore | null = null;
  
  async initDatabase(context: Context): Promise<void> {
    const config: relationalStore.StoreConfig = {
      name: 'social.db',
      securityLevel: relationalStore.SecurityLevel.S1,
    };
    this.rdbStore = await relationalStore.getRdbStore(context, config);
    
    await this.rdbStore.executeSql(
      'CREATE TABLE IF NOT EXISTS friends (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT, friend_id TEXT, status TEXT, created_at INTEGER)'
    );
  }
  
  async addFriend(userId: string, friendId: string): Promise<void> {
    if (this.rdbStore) {
      let valueBucket = {
        'user_id': userId,
        'friend_id': friendId,
        'status': 'pending',
        'created_at': Date.now(),
      };
      await this.rdbStore.insert('friends', valueBucket);
    }
  }
  
  async getFriends(userId: string): Promise<Array<string>> {
    let friends: Array<string> = [];
    if (this.rdbStore) {
      let predicates = new relationalStore.RdbPredicates('friends');
      predicates.equalTo('user_id', userId).equalTo('status', 'accepted');
      let resultSet = await this.rdbStore.query(predicates, ['friend_id']);
      while (resultSet.goToNextRow()) {
        friends.push(resultSet.getString(resultSet.getColumnIndex('friend_id')));
      }
      resultSet.close();
    }
    return friends;
  }
}

好友关系服务管理用户之间的社交关系。我们使用关系型数据库存储好友关系,表结构包含用户ID、好友ID、关系状态和创建时间。status字段支持pending(待确认)和accepted(已接受)两种状态,实现好友申请流程。addFriend方法创建好友申请,初始状态为pending。getFriends方法查询已确认的好友列表,通过predicates构建查询条件。这种设计支持完整的好友管理功能,包括添加好友、接受申请、查看好友列表等操作。

Flutter好友列表组件

class FriendListItem extends StatelessWidget {
  final String friendId;
  final String friendName;
  final String? avatarUrl;
  final int todaySteps;
  final VoidCallback onTap;
  
  const FriendListItem({
    Key? key,
    required this.friendId,
    required this.friendName,
    this.avatarUrl,
    required this.todaySteps,
    required this.onTap,
  }) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return ListTile(
      onTap: onTap,
      leading: CircleAvatar(
        backgroundImage: avatarUrl != null ? NetworkImage(avatarUrl!) : null,
        child: avatarUrl == null ? Text(friendName[0]) : null,
      ),
      title: Text(friendName),
      subtitle: Text('今日 $todaySteps 步'),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.directions_walk, size: 16, color: Colors.grey),
          SizedBox(width: 4),
          Text('$todaySteps', style: TextStyle(fontWeight: FontWeight.bold)),
        ],
      ),
    );
  }
}

好友列表组件展示用户的好友及其运动数据。每个列表项包含头像、昵称和今日步数,让用户能够快速了解好友的运动情况。头像使用CircleAvatar组件,支持网络图片和文字首字母两种显示方式。subtitle显示好友今日的步数,trailing部分用图标和数字强调步数数据。onTap回调处理点击事件,可以跳转到好友详情页或发起互动。这种设计让社交功能融入运动数据展示,用户在查看好友列表的同时也能获得运动激励。

Flutter排行榜组件

class LeaderboardView extends StatelessWidget {
  final List<LeaderboardEntry> entries;
  final String currentUserId;
  
  const LeaderboardView({
    Key? key,
    required this.entries,
    required this.currentUserId,
  }) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: entries.length,
      itemBuilder: (context, index) {
        var entry = entries[index];
        bool isCurrentUser = entry.userId == currentUserId;
        
        return Container(
          margin: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
          padding: EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: isCurrentUser ? Colors.blue.withOpacity(0.1) : Colors.white,
            borderRadius: BorderRadius.circular(12),
            border: isCurrentUser ? Border.all(color: Colors.blue, width: 2) : null,
          ),
          child: Row(
            children: [
              _buildRankBadge(index + 1),
              SizedBox(width: 12),
              CircleAvatar(child: Text(entry.userName[0])),
              SizedBox(width: 12),
              Expanded(child: Text(entry.userName, style: TextStyle(fontWeight: isCurrentUser ? FontWeight.bold : FontWeight.normal))),
              Text('${entry.value}', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            ],
          ),
        );
      },
    );
  }
  
  Widget _buildRankBadge(int rank) {
    Color badgeColor;
    if (rank == 1) badgeColor = Colors.amber;
    else if (rank == 2) badgeColor = Colors.grey;
    else if (rank == 3) badgeColor = Colors.brown;
    else badgeColor = Colors.blue;
    
    return Container(
      width: 32,
      height: 32,
      decoration: BoxDecoration(color: badgeColor, shape: BoxShape.circle),
      child: Center(child: Text('$rank', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold))),
    );
  }
}

class LeaderboardEntry {
  final String userId;
  final String userName;
  final int value;
  
  LeaderboardEntry({required this.userId, required this.userName, required this.value});
}

排行榜组件展示好友之间的运动数据排名。每个排行项显示名次、头像、昵称和数值,当前用户的条目使用蓝色边框和背景高亮显示,便于快速定位自己的排名。前三名使用金、银、铜三种颜色的徽章,其他名次使用蓝色徽章。排行榜通过竞争机制激励用户增加运动量,看到好友排名靠前会产生追赶的动力。这种社交化的运动激励方式比单纯的个人目标更能持续激发用户的运动热情。

OpenHarmony点赞互动服务

import http from '@ohos.net.http';

class SocialInteractionService {
  async likeWorkout(workoutId: string, userId: string): Promise<boolean> {
    let httpRequest = http.createHttp();
    
    try {
      let response = await httpRequest.request(
        'https://api.fitness.com/social/like',
        {
          method: http.RequestMethod.POST,
          header: { 'Content-Type': 'application/json' },
          extraData: JSON.stringify({
            workoutId: workoutId,
            userId: userId,
            timestamp: Date.now(),
          }),
        }
      );
      return response.responseCode === 200;
    } catch (error) {
      console.error('点赞失败: ' + error);
      return false;
    } finally {
      httpRequest.destroy();
    }
  }
  
  async addComment(workoutId: string, userId: string, content: string): Promise<boolean> {
    let httpRequest = http.createHttp();
    
    try {
      let response = await httpRequest.request(
        'https://api.fitness.com/social/comment',
        {
          method: http.RequestMethod.POST,
          header: { 'Content-Type': 'application/json' },
          extraData: JSON.stringify({
            workoutId: workoutId,
            userId: userId,
            content: content,
            timestamp: Date.now(),
          }),
        }
      );
      return response.responseCode === 200;
    } catch (error) {
      console.error('评论失败: ' + error);
      return false;
    } finally {
      httpRequest.destroy();
    }
  }
}

点赞互动服务实现用户之间的社交互动功能。likeWorkout方法向服务器发送点赞请求,包含运动记录ID、用户ID和时间戳。addComment方法发送评论请求,额外包含评论内容。两个方法都使用HTTP POST请求,数据格式为JSON。通过try-catch处理网络异常,finally块确保HTTP请求资源被正确释放。这些互动功能让用户可以对好友的运动成果表示认可和鼓励,增强社交连接,提升应用的用户粘性。

Flutter分享按钮组件

class ShareButton extends StatelessWidget {
  final ShareableWorkout workout;
  final GlobalKey cardKey;
  
  const ShareButton({
    Key? key,
    required this.workout,
    required this.cardKey,
  }) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return ElevatedButton.icon(
      onPressed: () => _showShareOptions(context),
      icon: Icon(Icons.share),
      label: Text('分享成果'),
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
      ),
    );
  }
  
  void _showShareOptions(BuildContext context) {
    showModalBottomSheet(
      context: context,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (context) => Container(
        padding: EdgeInsets.all(20),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('分享到', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                _buildShareOption(context, Icons.chat, '微信', Colors.green),
                _buildShareOption(context, Icons.public, '微博', Colors.red),
                _buildShareOption(context, Icons.image, '保存图片', Colors.blue),
                _buildShareOption(context, Icons.more_horiz, '更多', Colors.grey),
              ],
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildShareOption(BuildContext context, IconData icon, String label, Color color) {
    return GestureDetector(
      onTap: () => Navigator.pop(context),
      child: Column(
        children: [
          Container(
            padding: EdgeInsets.all(12),
            decoration: BoxDecoration(color: color.withOpacity(0.1), shape: BoxShape.circle),
            child: Icon(icon, color: color, size: 28),
          ),
          SizedBox(height: 8),
          Text(label, style: TextStyle(fontSize: 12)),
        ],
      ),
    );
  }
}

分享按钮组件提供便捷的分享入口和选项。点击按钮弹出底部面板,展示多个分享目标选项,包括微信、微博、保存图片和更多。每个选项使用圆形图标和文字标签,颜色与对应平台的品牌色一致,便于用户识别。底部面板使用圆角设计,视觉上更加柔和。这种设计模式在移动应用中非常常见,用户已经形成了操作习惯,能够快速完成分享操作。分享功能的便捷性直接影响用户的分享意愿和应用的传播效果。

总结

本文全面介绍了Flutter与OpenHarmony平台上社交分享组件的实现方案。从分享数据模型到卡片设计,从系统分享到好友管理,从排行榜到互动功能,涵盖了社交分享的各个方面。通过精美的分享卡片、便捷的分享流程和丰富的社交互动,我们可以构建出一个能够有效提升用户粘性和应用传播的社交模块,让运动变得更加有趣和有动力。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐