Flutter BBCode解析插件flutter_bbcode的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter BBCode解析插件flutter_bbcode的使用

简介

flutter_bbcode 是一个用于在 Flutter 应用中解析和显示 BBCode 的简单插件。它支持自定义标签和样式,可以让你轻松地将 BBCode 转换为可读性高的文本。

特点

  • 将 BBCode 渲染为可读性高的文本
  • 支持不同的样式
  • 支持自定义标签

预览

Preview 1 Preview 2

开始使用

安装

  1. pubspec.yaml 文件中添加 flutter_bbcode 依赖:

    dependencies:
      flutter_bbcode: ^latest_version
    
  2. 运行 flutter pub get 来安装依赖。

  3. 导入包:

    import 'package:flutter_bbcode/flutter_bbcode.dart';
    

基本用法

安装完插件后,显示 BBCode 非常简单。以下是一个基本示例:

import 'package:flutter/material.dart';
import 'package:flutter_bbcode/flutter_bbcode.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('BBCode Example')),
        body: Center(
          child: BBCodeText(
            data: '[b]This is bold text[/b] and [i]this is italic text[/i].',
          ),
        ),
      ),
    );
  }
}

自定义样式表

你可以通过提供一个 BBStylesheet 来覆盖默认的样式和标签。以下是一个示例:

import 'package:flutter/material.dart';
import 'package:flutter_bbcode/flutter_bbcode.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var extendedStyle = defaultBBStylesheet()
      ..addTag(YourNewTag())
      ..replaceTag(HeaderTag(1, 16));

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('BBCode Example')),
        body: Center(
          child: BBCodeText(
            data: '[b]This is bold text[/b] and [i]this is italic text[/i].',
            stylesheet: extendedStyle,
          ),
        ),
      ),
    );
  }
}

class YourNewTag extends StyleTag {
  @override
  String get name => 'newtag';

  @override
  TextStyle get style => TextStyle(color: Colors.red, fontSize: 20);
}

创建自定义标签

你可以通过扩展 AbstractTagStyleTagWrappedStyleTagAdvancedTag 类来创建自定义标签。以下是一个简单的自定义标签示例:

import 'package:flutter/material.dart';
import 'package:flutter_bbcode/flutter_bbcode.dart';

class CustomTag extends StyleTag {
  @override
  String get name => 'custom';

  @override
  TextStyle get style => TextStyle(color: Colors.purple, fontSize: 18);
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var extendedStyle = defaultBBStylesheet()
      ..addTag(CustomTag());

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('BBCode Example')),
        body: Center(
          child: BBCodeText(
            data: '[custom]This is custom styled text[/custom].',
            stylesheet: extendedStyle,
          ),
        ),
      ),
    );
  }
}

默认支持的标签

以下是 flutter_bbcode 默认支持的标签:

  • [B] - 粗体文本
  • [I] - 斜体文本
  • [U] - 下划线文本
  • [S] - 删除线文本
  • [COLOR=#HEX] - 基于 HEX 的彩色文本
  • [H1] - 标题文本,支持到 [H6]
  • [URL=https://google.com] - 支持带或不带文本的链接。默认操作是记录消息。示例使用 url_launcher 可以在示例中找到。
  • [IMG=src] - 显示互联网上的图片。
  • [QUOTE=Marten] - 用于包裹引用块。
  • [SPOILER=Name] - 用于创建可点击的隐藏内容标签。
  • [LIST] / [LIST=1] / [UL] / [OL] - 用于创建(有序)列表。注意项目需要是 [*]item[/*] 的形式。
  • [LEFT], [CENTER], [RIGHT] - 对齐文本

示例代码

以下是一个更复杂的示例,展示了如何使用 flutter_bbcode 处理多种 BBCode 输入并切换不同的样式表:

import 'package:flutter/material.dart';
import 'package:flutter_bbcode/flutter_bbcode.dart';
import 'package:url_launcher/url_launcher.dart';

void main() {
  runApp(const MyApp());
}

class HintedStyle {
  final BBStylesheet? style;
  final String hint;

  HintedStyle(this.style, this.hint);
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const inputs = <String>[
    'This is a text without ANY bbcode',
    'This text features [b]bold[/b] text.',
    'This text [s]is epic[/s] combines features [u][b]bold underlined[/u][/b] text.',
    'This text features [url=https://mstruijk.nl]a link[/url].',
    'More complex examples can be added here...',
  ];

  static Future<void> _launchUrl(Uri uri) async {
    if (!await launchUrl(uri)) {
      throw 'Could not launch $uri';
    }
  }

  static final _implementedUrlTag = UrlTag(onTap: (url) {
    _launchUrl(Uri.parse(url));
  });

  static final styles = <HintedStyle>[
    HintedStyle(defaultBBStylesheet(), "Default style"),
    HintedStyle(
        defaultBBStylesheet(
            textStyle: const TextStyle(color: Colors.blue, fontSize: 28, height: 1)),
        "Default style with text style changed."),
    HintedStyle(BBStylesheet(tags: []), "Empty style sheet"),
    HintedStyle(defaultBBStylesheet().replaceTag(HeaderTag(3, 6)),
        "Default style, replaced H3 tag (smaller)."),
    HintedStyle(defaultBBStylesheet().replaceTag(_implementedUrlTag),
        "Default style, replaced URL tag with working URL launcher."),
    HintedStyle(
        BBStylesheet(tags: [
          BoldTag(),
          ItalicTag(),
        ]),
        "Only Bold and Italic tags"),
  ];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter BBCode Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(
        title: "Example BBCode outputs",
        examples: inputs,
        styles: styles,
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({
    Key? key,
    required this.title,
    required this.examples,
    required this.styles,
  }) : super(key: key);

  final String title;
  final List<String> examples;
  final List<HintedStyle?> styles;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentTextIndex = 0;
  int _currentStyleIndex = 0;

  String get _currentExampleText => widget.examples[_currentTextIndex];

  HintedStyle get _currentHintedStyle => widget.styles[_currentStyleIndex]!;

  bool selectable = false;

  void _showSnack(String text) {
    var sm = ScaffoldMessenger.of(context);
    sm.clearSnackBars();
    sm.showSnackBar(SnackBar(
      content: Text(text),
      behavior: SnackBarBehavior.fixed,
      duration: const Duration(seconds: 2),
    ));
  }

  void _selectNextExample() {
    setState(() {
      _currentTextIndex = (_currentTextIndex + 1) % widget.examples.length;
    });
  }

  void _selectNextStyle() {
    setState(() {
      _currentStyleIndex = (_currentStyleIndex + 1) % widget.styles.length;
    });

    _showSnack(_currentHintedStyle.hint);
  }

  void _toggleSelectableText() {
    setState(() {
      selectable = !selectable;
    });

    _showSnack("Selectable text: $selectable");
  }

  @override
  Widget build(BuildContext context) {
    var style = _currentHintedStyle.style?.copyWith(selectableText: selectable);

    Widget parsedBBCode = BBCodeText(
        errorBuilder: (context, error, stack) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text("Failed to parse BBCode correctly.",
                  style: TextStyle(color: Colors.red)),
              const Text(
                  "This usually means one of the tags is not properly handling unexpected input.\n"),
              Text(error.toString()),
            ],
          );
        },
        stylesheet: style,
        data: _currentExampleText);

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Center(child: parsedBBCode),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton.small(
            onPressed: _selectNextExample,
            tooltip: 'Next example text',
            child: const Icon(Icons.navigate_next),
          ),
          FloatingActionButton.small(
            onPressed: _selectNextStyle,
            child: const Icon(Icons.draw),
            tooltip: 'Next BBStylesheet',
          ),
          FloatingActionButton.small(
            onPressed: _toggleSelectableText,
            child: const Icon(Icons.select_all),
            tooltip: 'Toggle selectable text',
          ),
        ],
      ),
    );
  }
}

贡献项目

如果你有任何问题或建议,欢迎在 GitHub 上创建 issue 和 pull request。如果你喜欢这个项目,也欢迎给它点个星🌟。

希望这个插件能帮助你在 Flutter 应用中更好地处理和显示 BBCode!


更多关于Flutter BBCode解析插件flutter_bbcode的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter BBCode解析插件flutter_bbcode的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter BBCode解析插件flutter_bbcode的示例代码。这个插件允许你将BBCode格式的字符串解析为富文本格式。

首先,确保你已经在pubspec.yaml文件中添加了flutter_bbcode依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_bbcode: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,是一个简单的示例,展示如何使用flutter_bbcode解析BBCode并显示在Flutter应用中:

import 'package:flutter/material.dart';
import 'package:flutter_bbcode/flutter_bbcode.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter BBCode Parser Example'),
        ),
        body: BBCodeParserExample(),
      ),
    );
  }
}

class BBCodeParserExample extends StatelessWidget {
  final String bbcodeString = """
  [b]Bold Text[/b]
  [i]Italic Text[/i]
  [url=https://www.example.com]Clickable Link[/url]
  [color=red]Red Text[/color]
  [quote]This is a quote[/quote]
  """;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: BBCodeParser(
        bbcode: bbcodeString,
        buildTag: (context, element) {
          switch (element.tag) {
            case 'url':
              return InkWell(
                onTap: () => launchUrl(element.attributes['url']!),
                child: Text(
                  element.children.map((e) => e.toPlainText()).join(),
                  style: TextStyle(color: Colors.blue, decoration: TextDecoration.underline),
                ),
              );
            case 'quote':
              return Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                child: Card(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Text(
                      element.children.map((e) => e.toString()).join(),
                      style: TextStyle(color: Colors.grey),
                    ),
                  ),
                ),
              );
            case 'color':
              return Text(
                element.children.map((e) => e.toString()).join(),
                style: TextStyle(color: Color(int.parse(element.attributes['color']!, radix: 16))),
              );
            default:
              return Text(element.toString());
          }
        },
      ),
    );
  }

  Future<void> launchUrl(String url) async {
    if (await canLaunch(url)) {
      await launch(url);
    } else {
      throw 'Could not launch $url';
    }
  }
}

在这个示例中:

  1. 我们定义了一个包含BBCode字符串的变量bbcodeString
  2. 使用BBCodeParser小部件来解析这个BBCode字符串。
  3. buildTag参数允许我们自定义BBCode标签的渲染方式。例如,我们为url标签添加了一个点击事件,为quote标签添加了一个卡片样式,为color标签设置了文本颜色。
  4. launchUrl函数用于打开URL链接。

这个示例展示了如何解析BBCode并自定义其渲染效果。你可以根据需要扩展和修改这个示例,以适应你的具体需求。

回到顶部