Flutter内容管理插件contentful_flutter的使用

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

Flutter内容管理插件contentful_flutter的使用

Static Badge License: MIT

contentful_flutter 是一个用于 Flutter 的 Contentful 客户端库,提供了以下功能:

  • ✅ 获取条目(Entries)
  • ✅ 按 ID 获取条目
  • ✅ 条目是一个泛型类型,可以自定义
  • ✅ 实现了 ContentfulFlutterBuilder,帮助你快速实现文章内容的展示,特别是支持项目符号和编号列表

Demo

观看视频

Watch the video

安装 💻

在你的 pubspec.yaml 文件中添加 contentful_flutter

dependencies:
  contentful_flutter:

安装依赖:

flutter packages get

示例代码

以下是一个完整的示例代码,展示了如何使用 contentful_flutter 插件来获取和显示 Contentful 中的内容。

example/lib/main.dart

import 'package:contentful_flutter/contentful_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:url_launcher/url_launcher.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Contentful Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Contentful Flutter Home Page'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  Widget build(BuildContext context) {
    const repository = ContentfulDeliveryAPIRepository(
      client: ContentfulClient(
        spaceId: 'xwoyh2py4618',
        accessToken: 'XhHrIcwi6AqI_TxuuH9qbexLq9e_KQdXADnUU1_v9oE',
      ),
    );
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: FutureBuilder(
          future: repository.getEntries<Entry<ExampleDataModel>>(
            fromJsonT: (json) => Entry.fromJson(
              json as Map<String, dynamic>,
              (json) => ExampleDataModel.fromJson(json as Map<String, dynamic>),
            ),
          ),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Center(child: Text(snapshot.error.toString()));
            }
            if (snapshot.hasData) {
              final textStyle =
                  Theme.of(context).textTheme.bodyMedium ?? const TextStyle();
              final data = snapshot.data
                  as ContentfulDeliveryDataModel<Entry<ExampleDataModel>>;
              final bodyContents = data.items.first.fields.body.contentList;

              if (bodyContents?.isEmpty ?? true) return const SizedBox.shrink();
              return SingleChildScrollView(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: bodyContents!.map(
                    (content) {
                      final contentData = repository.getDataFrom(
                        content: content,
                        includes: data.includes,
                      );
                      if (contentData == null) return const SizedBox.shrink();
                      return Column(
                        children: [
                          ContentfulFlutterBuilder(
                            data: contentData,
                            includes: data.includes,
                            textBuilder: (
                              content,
                              style,
                              ignorePadding,
                              padding,
                            ) {
                              return Text(
                                content.value ?? '',
                                style: style,
                                softWrap: false,
                                overflow: TextOverflow.visible,
                              );
                            },
                            blockQuoteBuilder: (child) {
                              return Row(
                                children: [
                                  Flexible(
                                    child: Container(
                                      width: 3,
                                      height: 40,
                                      color: Colors.grey,
                                    ),
                                  ),
                                  const SizedBox(width: 8),
                                  Expanded(
                                    child: child,
                                  ),
                                  const SizedBox(width: 8),
                                ],
                              );
                            },
                            linkWidgetBuilder: (uri, child) => InkWell(
                              onTap: () => _launchUrl(Uri.parse(uri ?? '')),
                              child: child,
                            ),
                            imageBuilder: (imageUrl) => imageUrl.endsWith('svg')
                                ? SvgPicture.network(imageUrl)
                                : Image.network(imageUrl),
                            dividerBuilder: () => const Divider(),
                            listIdentationPadding: const EdgeInsets.only(left: 16),
                            textStyle: textStyle,
                            headingOneStyle: textStyle.copyWith(fontSize: 32),
                            headingTwoStyle: textStyle.copyWith(fontSize: 24),
                            headingThreeStyle: textStyle.copyWith(fontSize: 18),
                            headingFourStyle: textStyle.copyWith(fontSize: 16),
                            headingFiveStyle: textStyle.copyWith(fontSize: 14),
                            headingSixStyle: textStyle.copyWith(fontSize: 12),
                          ),
                          const SizedBox(height: 8)
                        ],
                      );
                    },
                  ).toList(),
                ),
              );
            }
            return const Center(
              child: CircularProgressIndicator(),
            );
          },
        ),
      ),
    );
  }
}

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

ExampleDataModel

为了使示例代码完整,还需要定义 ExampleDataModel 类。以下是一个简单的示例:

class ExampleDataModel {
  final String title;
  final List<dynamic> body;

  ExampleDataModel({required this.title, required this.body});

  factory ExampleDataModel.fromJson(Map<String, dynamic> json) {
    return ExampleDataModel(
      title: json['title'] as String,
      body: json['body'] as List<dynamic>,
    );
  }
}

运行示例

  1. 确保你已经安装了 Flutter 和 Dart。
  2. 将上述代码保存到你的 Flutter 项目中。
  3. 在终端中运行 flutter run 命令启动应用。

通过以上步骤,你可以成功地使用 contentful_flutter 插件从 Contentful 获取并显示内容。希望这个示例对你有所帮助!


更多关于Flutter内容管理插件contentful_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter内容管理插件contentful_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用contentful_flutter插件的示例代码。这个插件允许你从Contentful CMS中获取内容并在你的Flutter应用中展示。

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

dependencies:
  flutter:
    sdk: flutter
  contentful_flutter: ^latest_version  # 请替换为最新的版本号

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

接下来,你需要从Contentful获取Space ID和Access Token。这些信息可以在你的Contentful管理后台找到。

以下是一个完整的示例,展示如何使用contentful_flutter从Contentful获取内容并显示在一个简单的Flutter应用中:

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Client _client;
  late Entry<dynamic>? _entry;

  @override
  void initState() {
    super.initState();
    // 替换为你的Space ID和Access Token
    const String spaceId = 'your_space_id';
    const String accessToken = 'your_access_token';

    _client = Client(space: spaceId, accessToken: accessToken);

    // 获取一个特定ID的Entry
    final String entryId = 'your_entry_id';
    _client.getEntry<Map<String, dynamic>>(entryId).then((entry) {
      setState(() {
        _entry = entry;
      });
    }).catchError((error) {
      print('Error fetching entry: $error');
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Contentful Flutter Example'),
        ),
        body: Center(
          child: _entry != null
              ? Text(_entry!.fields!['your_field_name'] as String)
              : CircularProgressIndicator(),
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们首先导入了必要的包。
  2. 创建了一个MyApp类,它是一个有状态的Widget。
  3. initState方法中,我们初始化了Client实例,并使用Space ID和Access Token进行配置。
  4. 使用getEntry方法获取特定ID的Entry,并在获取成功后更新状态。
  5. build方法中,我们根据_entry的状态显示内容或加载指示器。

请注意,你需要将your_space_idyour_access_tokenyour_entry_id替换为你从Contentful获取的实际值,并且your_field_name应该替换为你想要展示的字段名。

此外,你可能需要根据你的Contentful模型调整getEntry方法的泛型参数和字段访问方式。这个示例假设Entry的内容是一个Map,并且你想要展示的字段是一个String类型。如果你的内容结构不同,你需要相应地调整代码。

回到顶部