在这里插入图片描述

前言

分享功能是商城应用中促进用户传播和拉新的重要功能,用户可以将心仪的商品、优惠活动分享给好友。一个设计良好的分享组件需要支持多种分享渠道,并提供美观的分享面板和分享内容预览。本文将详细介绍如何在Flutter和OpenHarmony平台上开发分享功能组件。

分享功能的设计需要考虑分享渠道的覆盖面和分享内容的吸引力。常见的分享渠道包括微信好友、微信朋友圈、QQ、微博等社交平台,以及复制链接、保存图片等通用方式。分享内容应该包含商品图片、标题、价格等关键信息,吸引被分享者点击查看。

Flutter分享数据模型

首先定义分享内容的数据模型:

class ShareContent {
  final String title;
  final String description;
  final String imageUrl;
  final String linkUrl;
  final ShareType type;

  const ShareContent({
    required this.title,
    required this.description,
    required this.imageUrl,
    required this.linkUrl,
    this.type = ShareType.link,
  });
}

enum ShareType {
  link,   // 链接分享
  image,  // 图片分享
  text,   // 文本分享
}

ShareContent类定义了分享内容的基本属性。title是分享标题,description是分享描述,imageUrl是分享图片,linkUrl是分享链接。ShareType枚举定义了链接、图片和文本三种分享类型。这种数据模型的设计支持各种分享场景。

分享渠道定义:

class ShareChannel {
  final String id;
  final String name;
  final IconData icon;
  final Color color;

  const ShareChannel({
    required this.id,
    required this.name,
    required this.icon,
    required this.color,
  });

  static const wechat = ShareChannel(
    id: 'wechat',
    name: '微信',
    icon: Icons.chat,
    color: Color(0xFF07C160),
  );

  static const moments = ShareChannel(
    id: 'moments',
    name: '朋友圈',
    icon: Icons.camera_alt,
    color: Color(0xFF07C160),
  );

  static const qq = ShareChannel(
    id: 'qq',
    name: 'QQ',
    icon: Icons.message,
    color: Color(0xFF12B7F5),
  );

  static const weibo = ShareChannel(
    id: 'weibo',
    name: '微博',
    icon: Icons.public,
    color: Color(0xFFE6162D),
  );

  static const copyLink = ShareChannel(
    id: 'copy',
    name: '复制链接',
    icon: Icons.link,
    color: Color(0xFF999999),
  );

  static const saveImage = ShareChannel(
    id: 'save',
    name: '保存图片',
    icon: Icons.download,
    color: Color(0xFF999999),
  );
}

ShareChannel类定义了分享渠道的属性,包括ID、名称、图标和主题色。静态常量预定义了常用的分享渠道,每个渠道使用对应平台的品牌色。这种设计使分享渠道的配置更加灵活,可以根据需要选择显示哪些渠道。

分享面板组件

class ShareSheet extends StatelessWidget {
  final ShareContent content;
  final List<ShareChannel> channels;
  final ValueChanged<ShareChannel>? onShare;

  const ShareSheet({
    Key? key,
    required this.content,
    required this.channels,
    this.onShare,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          _buildHandle(),
          _buildTitle(),
          _buildChannelGrid(),
          _buildCancelButton(context),
        ],
      ),
    );
  }
}

ShareSheet组件以底部弹出面板的形式展示分享选项。content是要分享的内容,channels是可用的分享渠道列表,onShare回调在用户选择渠道时触发。Container设置白色背景和顶部圆角,Column垂直排列拖动条、标题、渠道网格和取消按钮。mainAxisSize.min使面板高度自适应内容。

拖动条和标题:

Widget _buildHandle() {
  return Container(
    margin: const EdgeInsets.only(top: 12),
    width: 36,
    height: 4,
    decoration: BoxDecoration(
      color: const Color(0xFFE0E0E0),
      borderRadius: BorderRadius.circular(2),
    ),
  );
}

Widget _buildTitle() {
  return const Padding(
    padding: EdgeInsets.all(16),
    child: Text(
      '分享到',
      style: TextStyle(
        fontSize: 16,
        fontWeight: FontWeight.w600,
        color: Color(0xFF333333),
      ),
    ),
  );
}

拖动条是底部面板的视觉标识,表明面板可以拖动关闭。使用灰色圆角矩形,宽36像素高4像素。标题"分享到"使用16像素粗体,清晰标识面板的功能。这种设计符合移动端底部面板的通用模式。

分享渠道网格

Widget _buildChannelGrid() {
  return Padding(
    padding: const EdgeInsets.symmetric(horizontal: 16),
    child: Wrap(
      spacing: 24,
      runSpacing: 20,
      children: channels.map((channel) {
        return _buildChannelItem(channel);
      }).toList(),
    ),
  );
}

Widget _buildChannelItem(ShareChannel channel) {
  return GestureDetector(
    onTap: () => onShare?.call(channel),
    child: SizedBox(
      width: 60,
      child: Column(
        children: [
          Container(
            width: 48,
            height: 48,
            decoration: BoxDecoration(
              color: channel.color.withOpacity(0.1),
              borderRadius: BorderRadius.circular(12),
            ),
            child: Icon(
              channel.icon,
              size: 24,
              color: channel.color,
            ),
          ),
          const SizedBox(height: 8),
          Text(
            channel.name,
            style: const TextStyle(
              fontSize: 11,
              color: Color(0xFF666666),
            ),
          ),
        ],
      ),
    ),
  );
}

分享渠道使用Wrap流式布局,当一行放不下时自动换行。每个渠道项包含图标和名称,图标使用渠道主题色的浅色背景和深色图标。SizedBox设置固定宽度确保各渠道项对齐。GestureDetector处理点击事件,触发分享操作。这种设计让用户能够快速识别和选择分享渠道。

取消按钮

Widget _buildCancelButton(BuildContext context) {
  return GestureDetector(
    onTap: () => Navigator.of(context).pop(),
    child: Container(
      width: double.infinity,
      padding: const EdgeInsets.symmetric(vertical: 16),
      margin: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFFF5F5F5),
        borderRadius: BorderRadius.circular(8),
      ),
      alignment: Alignment.center,
      child: const Text(
        '取消',
        style: TextStyle(
          fontSize: 15,
          color: Color(0xFF666666),
        ),
      ),
    ),
  );
}

取消按钮放在面板底部,使用灰色背景和圆角。点击时关闭分享面板。Container设置全宽和内边距,确保按钮有足够的点击区域。这种设计让用户可以方便地关闭分享面板。

分享面板显示方法

class ShareHelper {
  static void show(
    BuildContext context, {
    required ShareContent content,
    List<ShareChannel>? channels,
    ValueChanged<ShareChannel>? onShare,
  }) {
    final defaultChannels = [
      ShareChannel.wechat,
      ShareChannel.moments,
      ShareChannel.qq,
      ShareChannel.weibo,
      ShareChannel.copyLink,
      ShareChannel.saveImage,
    ];

    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.transparent,
      builder: (context) => ShareSheet(
        content: content,
        channels: channels ?? defaultChannels,
        onShare: (channel) {
          Navigator.of(context).pop();
          onShare?.call(channel);
          _handleShare(context, content, channel);
        },
      ),
    );
  }

  static void _handleShare(
    BuildContext context,
    ShareContent content,
    ShareChannel channel,
  ) {
    switch (channel.id) {
      case 'copy':
        Clipboard.setData(ClipboardData(text: content.linkUrl));
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('链接已复制')),
        );
        break;
      case 'save':
        // 保存图片逻辑
        break;
      default:
        // 调用第三方分享SDK
        break;
    }
  }
}

ShareHelper工具类封装了分享面板的显示和分享处理逻辑。show方法显示分享面板,提供默认的分享渠道列表。_handleShare方法根据选择的渠道执行对应的分享操作,复制链接使用Clipboard API,保存图片和第三方分享需要调用对应的SDK。这种封装使分享功能的使用更加便捷。

OpenHarmony分享面板实现

@Component
struct ShareSheet {
  @Prop content: ShareContentInfo
  @Prop channels: ShareChannelInfo[] = []
  private onShare: (channel: ShareChannelInfo) => void = () => {}
  private onCancel: () => void = () => {}

  build() {
    Column() {
      this.Handle()
      this.Title()
      this.ChannelGrid()
      this.CancelButton()
    }
    .width('100%')
    .backgroundColor(Color.White)
    .borderRadius({ topLeft: 16, topRight: 16 })
  }
}

OpenHarmony的分享面板使用Column垂直排列各个区域。@Prop装饰的属性从父组件接收分享内容和渠道列表。borderRadius只设置顶部圆角。这种实现方式与Flutter版本结构一致。

分享数据接口:

interface ShareContentInfo {
  title: string
  description: string
  imageUrl: string
  linkUrl: string
}

interface ShareChannelInfo {
  id: string
  name: string
  icon: Resource
  color: string
}

TypeScript接口定义了分享内容和分享渠道的数据结构。icon使用Resource类型引用本地图标资源,color使用字符串存储颜色值。

分享渠道网格ArkUI实现

@Builder
ChannelGrid() {
  Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
    ForEach(this.channels, (channel: ShareChannelInfo) => {
      this.ChannelItem(channel)
    })
  }
  .width('100%')
  .padding({ left: 16, right: 16 })
}

@Builder
ChannelItem(channel: ShareChannelInfo) {
  Column() {
    Column() {
      Image(channel.icon)
        .width(24)
        .height(24)
    }
    .width(48)
    .height(48)
    .backgroundColor(channel.color + '1A')
    .borderRadius(12)
    .justifyContent(FlexAlign.Center)
    
    Text(channel.name)
      .fontSize(11)
      .fontColor('#666666')
      .margin({ top: 8 })
  }
  .width(60)
  .margin({ right: 24, bottom: 20 })
  .onClick(() => this.onShare(channel))
}

Flex组件配合FlexWrap.Wrap实现流式布局。ForEach遍历渠道数组生成渠道项。每个渠道项使用Column垂直排列图标和名称。backgroundColor使用渠道颜色加透明度后缀实现浅色背景。onClick事件处理器在用户点击时触发分享回调。

商品分享组件

class ProductShareButton extends StatelessWidget {
  final String productId;
  final String productName;
  final String productImage;
  final double productPrice;

  const ProductShareButton({
    Key? key,
    required this.productId,
    required this.productName,
    required this.productImage,
    required this.productPrice,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => _showShare(context),
      child: Container(
        padding: const EdgeInsets.all(8),
        child: const Icon(
          Icons.share,
          size: 20,
          color: Color(0xFF666666),
        ),
      ),
    );
  }

  void _showShare(BuildContext context) {
    final content = ShareContent(
      title: productName,
      description: ${productPrice.toStringAsFixed(2)}',
      imageUrl: productImage,
      linkUrl: 'https://example.com/product/$productId',
    );

    ShareHelper.show(
      context,
      content: content,
      onShare: (channel) {
        // 记录分享统计
      },
    );
  }
}

ProductShareButton组件封装了商品分享功能。接收商品ID、名称、图片和价格,点击时构建分享内容并显示分享面板。分享链接使用商品ID生成,便于被分享者直接打开商品详情。onShare回调可以用于记录分享统计数据。这种封装使商品分享的使用更加便捷。

总结

本文详细介绍了Flutter和OpenHarmony平台上分享功能组件的开发过程。分享功能作为促进用户传播的重要功能,其设计质量直接影响分享的转化效果。通过分享面板、分享渠道、分享内容等组件的合理设计,我们为用户提供了便捷的分享体验。在实际项目中,还需要集成第三方分享SDK,并考虑分享统计、分享海报生成等功能。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

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

更多推荐