Flutter 封装:富文本 RichText 极简封装

1,839 阅读3分钟

1. 需求:

开发中遇到一个富文本展示点击效果(用户协议和隐私),通过官方的原始方法能够实现,但是很繁琐而且无聊,随想实现一个方便且高效的富文本生成方法,参考 iOS,最终完美实现;

2. 实现原理:

  1. 声明协议字典, 例如

    var linkMap = {
      '《用户协议》': 'https://flutter.dev',
      '《隐私政策》': 'https://flutter.dev',
    };
    
  2. 通过 《 》分割整段文字为数组;然后判断数组元素是否等于 “《$e》”; 如果等于则创建为链接 TextSpan),不等于则创建普通 TextSpan;可以得到 TextSpan 数组;

  3. ontap 回调(点击链接)返回 linkMap 中对应 key 和 value;

3. sceenshot:

Simulator Screen Shot - iPhone 11 Pro - 2021-07-31 at 12.50.12.png

4. example:

//
//  RichTextDemo.dart
//  fluttertemplet
//
//  Created by shang on 7/31/21 12:11 PM.
//  Copyright © 7/31/21 shang. All rights reserved.
//

import 'package:flutter/material.dart';
import 'package:fluttertemplet/basicWidget/AttributedString.dart';
import 'package:fluttertemplet/dartExpand/ddlog.dart';

class RichTextDemo extends StatefulWidget {

  final String? title;

  RichTextDemo({ Key? key, this.title}) : super(key: key);


  @override
  _RichTextDemoState createState() => _RichTextDemoState();
}

class _RichTextDemoState extends State<RichTextDemo> {

  @override
  Widget build(BuildContext context) {
    dynamic arguments = ModalRoute.of(context)!.settings.arguments;

    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title ?? "$widget"),
        ),
        body: buildRichText(context),
    );
  }

  Widget buildRichText(BuildContext context) {

    var linkMap = {
      '《用户协议》': 'https://flutter.dev',
      '《隐私政策》': 'https://flutter.dev',
    };

    String text = """
        亲爱的xxxx用户,感谢您信任并使用xxxxAPP!
xxxx十分重视用户权利及隐私政策并严格按照相关法律法规的要求,对《用户协议》和《隐私政策》进行了更新,特向您说明如下:
        1.为向您提供更优质的服务,我们会收集、使用必要的信息,并会采取业界先进的安全措施保护您的信息安全;
        2.基于您的明示授权,我们可能会获取设备号信息、包括:设备型号、操作系统版本、设备设置、设备标识符、MAC(媒体访问控制)地址、IMEI(移动设备国际身份码)、广告标识符(“IDFA”与“IDFV”)、集成电路卡识别码(“ICCD”)、软件安装列表。我们将使用三方产品(友盟、极光等)统计使用我们产品的设备数量并进行设备机型数据分析与设备适配性分析。(以保障您的账号与交易安全),且您有权拒绝或取消授权;
        3.您可灵活设置伴伴账号的功能内容和互动权限,您可在《隐私政策》中了解到权限的详细应用说明;
        4.未经您同意,我们不会从第三方获取、共享或向其提供您的信息;
        5.您可以查询、更正、删除您的个人信息,我们也提供账户注销的渠道。
        请您仔细阅读并充分理解相关条款,其中重点条款已为您黑体加粗标识,方便您了解自己的权利。如您点击“同意”,即表示您已仔细阅读并同意本《用户协议》及《隐私政策》,将尽全力保障您的合法权益并继续为您提供优质的产品和服务。如您点击“不同意”,将可能导致您无法继续使用我们的产品和服务。
""";
    final textRich = Text.rich(
      TextSpan(
        children: NAttributedString(
            context: context,
            text: text,
            linkMap: linkMap,
            // style: TextStyle(
            //     fontSize: 13,
            // ),
            // linkStyle: TextStyle(fontSize: 15),
            onTap: (key, value){
              ddlog(key);
              ddlog(value);
            }
        ).textSpans,
//     children: RichTextExt.createTextSpans(context,
//         text: text,
//         onTap: (key, value){
//           ddlog(key);
//           ddlog(value);
//         }
//     )
      ),
      strutStyle: StrutStyle(
        leading: 0.4,
      ),
    );

    return Container(
      padding: EdgeInsets.all(12),
      child: textRich,
    );
  }
}

//flutter: 2021-07-31 12:57:28.257309  RichTextDemo.dart, _RichTextDemoState [line 66]: 《用户协议》
//flutter: 2021-07-31 12:57:28.257929  RichTextDemo.dart, _RichTextDemoState [line 67]: https://flutter.dev
//flutter: 2021-07-31 12:57:28.890716  RichTextDemo.dart, _RichTextDemoState [line 66]: 《隐私政策》
//flutter: 2021-07-31 12:57:28.891331  RichTextDemo.dart, _RichTextDemoState [line 67]: https://flutter.dev

5. 两种封装方式:

扩展封装: rich_text_ext.dart

//...
children: RichTextExt.createTextSpans(context,
    text: text,
    linkMap: protocolMap,
    onTap: (key, value){
      ddlog(key);
      ddlog(value);
    }
)
//...

类封装: NAttributedString.dart

//...
// children: NAttributedString(
//     context: context,
//     text: text,
//     linkMap: protocolMap,
//     onTap: (key, value){
//       ddlog(key);
//       ddlog(value);
//     }
// ).textSpans,
//...