Flutter图书馆管理插件open_library的使用

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

Flutter图书馆管理插件open_library的使用

open_library

一个实现了openlibrary.org API的Flutter库。

特性

  • 使用ISBN从openlibrary.org API获取书籍信息。
  • 支持10位和13位ISBN号码。
  • 将作者和封面添加到书籍结果对象中。
  • 可以轻松地在Flutter中使用内存图像(MemoryImage)作为封面,通过Uint8List传递。
  • 支持按书名、作者、ISBN和统一查询进行搜索。
  • 新的搜索模式包括主题、地点、人物、语言和出版商。
  • 加载封面时可以选择小、中、大尺寸或禁用加载。

示例应用

安装

在你的Flutter项目的pubspec.yaml文件中,添加以下依赖:

dependencies:
  open_library: <latest_version>

在你的库中添加以下导入语句:

import 'package:open_library/open_library.dart';

入门指南

示例代码

import 'package:flutter/material.dart';
import 'package:open_library/open_library.dart';
import 'package:provider/provider.dart';
import 'screens/book_screen.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Provider(
        create: (_) => OpenLibrary(),
        dispose: (_, OpenLibrary service) => service.dispose(),
        child: MaterialApp(
          title: '图书示例',
          home: BookScreen()
        ));
  }
}

import 'package:flutter/material.dart';
import 'package:open_library/models/ol_book_model.dart';
import 'package:open_library/models/ol_search_model.dart';
import 'package:open_library/open_library.dart';
import 'package:provider/provider.dart';

const ISBN1 = '9783608980806';
const ISBN2 = '0674995171';
const ISBN3 = '3596191130';

class BookScreen extends StatefulWidget {
  BookScreen({Key? key}) : super(key: key);

  final List<OLBook> books = [];

  [@override](/user/override)
  State<BookScreen> createState() => _BookScreenState();
}

class _BookScreenState extends State<BookScreen> {
  final TextEditingController controller =
      TextEditingController(text: "Lord of the Rings");
  late bool isLoading = false;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey,
      body: !isLoading
          ? Column(
              children: [
                const SizedBox(height: 50.0),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    SizedBox(
                      width: MediaQuery.of(context).size.width * 0.6,
                      height: 60.0,
                      child: TextField(
                        controller: controller,
                        cursorColor: Colors.white,
                        style: const TextStyle(color: Colors.white),
                        decoration: const InputDecoration(
                          label: Text("书名:"),
                          labelStyle: TextStyle(color: Colors.white),
                          focusColor: Colors.white,
                        ),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(left: 10.0),
                      child: GestureDetector(
                        onTap: () async {
                          setState(() {
                            isLoading = true;
                          });
                          final OLSearchBase search =
                              await Provider.of<OpenLibrary>(context,
                                      listen: false)
                                  .query(q: controller.text, limit: 4);
                          if (search is OLSearch) {
                              widget.books.clear();
                              print("搜索结果:\n$search");
                              for (var doc in search.docs) {
                                final OLBook book = OLBook(
                                  title: doc.title,
                                  authors: doc.authors,
                                  covers: doc.covers,
                                );
                                widget.books.add(book);
                              }
                          }
                          setState(() {
                            isLoading = false;
                          });
                        },
                        child: const Icon(
                          Icons.search,
                          color: Colors.white,
                        ),
                      ),
                    ),
                  ],
                ),
                const SizedBox(
                  height: 20.0,
                ),
                const Center(
                    child: Text(
                      "点击按钮搜索这些ISBN",
                      style: TextStyle(color: Colors.white),
                    )),
                const SizedBox(
                  height: 20.0,
                ),
                const Center(
                    child: Text(
                  "ISBN1:$ISBN1",
                  style: TextStyle(color: Colors.white),
                )),
                const SizedBox(height: 20.0),
                const Center(
                    child: Text(
                  "ISBN2:$ISBN2",
                  style: TextStyle(color: Colors.white),
                )),
                const SizedBox(height: 20.0),
                const Center(
                    child: Text(
                  "ISBN3:$ISBN3",
                  style: TextStyle(color: Colors.white),
                )),
                const SizedBox(height: 20.0),
                SingleChildScrollView(
                  child: ListView.builder(
                    shrinkWrap: true,
                    itemCount: widget.books.length,
                    itemBuilder: (context, index) {
                      return bookWidget(
                          book: widget.books[index], context: context);
                    },
                  ),
                )
              ],
            )
          : const Center(child: CircularProgressIndicator(color: Colors.white,)),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          setState(() {
            isLoading = true;
          });
          widget.books.clear();
          const bool loadCovers = true;
          const CoverSize size = CoverSize.S;
          final OLBookBase book1 =
              await Provider.of<OpenLibrary>(context, listen: false)
                  .getBookByISBN(
                      isbn: ISBN1, loadCover: loadCovers, coverSize: size);
          print(book1.toString());
          if (book1 is OLBook) {
            widget.books.add(book1);
          }
          final OLBookBase book2 =
              await Provider.of<OpenLibrary>(context, listen: false)
                  .getBookByISBN(
                      isbn: ISBN2, loadCover: loadCovers, coverSize: size);
          print(book2.toString());
          if (book2 is OLBook) {
            widget.books.add(book2);
          }
          final OLBookBase book3 =
              await Provider.of<OpenLibrary>(context, listen: false)
                  .getBookByISBN(
                      isbn: ISBN3, loadCover: loadCovers, coverSize: size);
          print(book3.toString());
          if (book3 is OLBook) {
            widget.books.add(book3);
          }
          setState(() {
            isLoading = false;
          });
        },
        child: const Icon(Icons.book),
      ),
    );
  }

  Widget bookWidget({required OLBook book, required BuildContext context}) {
    String author = '';
    if (book.authors.isNotEmpty) {
      author = book.authors.first.name.trim();
    }
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Container(
        width: MediaQuery.of(context).size.width * 0.8,
        height: 80.0,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.circular(10.0),
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Padding(
                  padding:
                      const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 20.0),
                  child: SizedBox(
                    width: MediaQuery.of(context).size.width * 0.6,
                    child: Text(
                      book.title,
                      overflow: TextOverflow.ellipsis,
                      style: const TextStyle(
                          color: Colors.black,
                          fontSize: 14,
                          fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
                Padding(
                  padding:
                      const EdgeInsets.only(top: 4.0, bottom: 4.0, left: 20.0),
                  child: Text(
                    author,
                    style: const TextStyle(color: Colors.black, fontSize: 12),
                  ),
                ),
              ],
            ),
            Padding(
              padding: const EdgeInsets.only(right: 20.0),
              child: SizedBox(
                height: book.covers.isNotEmpty ? 64.0 : 0,
                child: book.covers.isNotEmpty
                    ? Image.memory(book.covers.first)
                    : null,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

示例代码

import 'package:flutter/material.dart';
import 'package:open_library/open_library.dart';
import 'screens/book_screen.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Provider(
        create: (_) => OpenLibrary(),
        dispose: (_, OpenLibrary ol) => ol.dispose(),
        child: MaterialApp(
            title: '图书示例',
            home: BookScreen()
        ));
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用open_library插件的示例代码。open_library是一个假定的插件名称,用于演示目的,因为实际上可能没有一个广泛知名的名为open_library的Flutter插件专门用于图书馆管理。但我会基于一个类似的假设插件功能来编写代码示例,展示如何集成和使用一个图书管理插件。

首先,你需要确保你的Flutter项目中已经添加了该插件。在pubspec.yaml文件中添加依赖项(注意:这里open_library是一个假设的包名,你需要替换为实际的包名):

dependencies:
  flutter:
    sdk: flutter
  open_library: ^x.y.z  # 替换为实际的版本号

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

接下来,在你的Flutter应用中,你可以按照以下方式使用open_library插件(假设它提供了图书的增删改查功能):

import 'package:flutter/material.dart';
import 'package:open_library/open_library.dart'; // 导入假设的open_library插件

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Library Management',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LibraryScreen(),
    );
  }
}

class LibraryScreen extends StatefulWidget {
  @override
  _LibraryScreenState createState() => _LibraryScreenState();
}

class _LibraryScreenState extends State<LibraryScreen> {
  final OpenLibrary _library = OpenLibrary(); // 实例化插件
  List<Book> _books = []; // 用于存储图书列表

  @override
  void initState() {
    super.initState();
    _fetchBooks(); // 初始化时获取图书列表
  }

  Future<void> _fetchBooks() async {
    setState(() {
      // 显示加载指示器
    });
    try {
      _books = await _library.getBooks(); // 假设getBooks()方法返回图书列表
      setState(() {}); // 更新UI
    } catch (e) {
      print('Error fetching books: $e');
    }
  }

  Future<void> _addBook(String title, String author) async {
    Book newBook = Book(title: title, author: author);
    try {
      await _library.addBook(newBook); // 假设addBook()方法添加新书
      _fetchBooks(); // 重新获取图书列表以更新UI
    } catch (e) {
      print('Error adding book: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Library Management'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: <Widget>[
            Expanded(
              child: _books.isEmpty
                  ? Center(child: CircularProgressIndicator()) // 显示加载指示器如果图书列表为空
                  : ListView.builder(
                      itemCount: _books.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: Text(_books[index].title),
                          subtitle: Text(_books[index].author),
                        );
                      },
                    ),
            ),
            TextField(
              decoration: InputDecoration(labelText: 'Book Title'),
              onSubmitted: (title) {
                _showAuthorDialog(title);
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 显示一个对话框让用户输入书名和作者
          _showTitleDialog();
        },
        tooltip: 'Add Book',
        child: Icon(Icons.add),
      ),
    );
  }

  Future<void> _showTitleDialog() async {
    final TextEditingController _titleController = TextEditingController();
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Enter Book Title'),
          content: TextField(
            controller: _titleController,
            decoration: InputDecoration(labelText: 'Title'),
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('Cancel'),
            ),
            TextButton(
              onPressed: () async {
                String title = _titleController.text;
                if (title.isEmpty) return;
                await _showAuthorDialog(title);
                Navigator.of(context).pop();
              },
              child: Text('OK'),
            ),
          ],
        );
      },
    );
  }

  Future<void> _showAuthorDialog(String title) async {
    final TextEditingController _authorController = TextEditingController();
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Enter Book Author'),
          content: TextField(
            controller: _authorController,
            decoration: InputDecoration(labelText: 'Author'),
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('Cancel'),
            ),
            TextButton(
              onPressed: () async {
                String author = _authorController.text;
                if (author.isEmpty) return;
                await _addBook(title, author);
                Navigator.of(context).pop();
              },
              child: Text('OK'),
            ),
          ],
        );
      },
    );
  }
}

// 假设的Book类
class Book {
  final String title;
  final String author;

  Book({required this.title, required this.author});
}

// 假设的OpenLibrary类(实际上这个类将由open_library插件提供)
class OpenLibrary {
  Future<List<Book>> getBooks() async {
    // 这里应该是与后端服务或本地数据库交互的代码
    // 为了演示,我们返回一个硬编码的图书列表
    return [
      Book(title: 'Book One', author: 'Author A'),
      Book(title: 'Book Two', author: 'Author B'),
    ];
  }

  Future<void> addBook(Book book) async {
    // 这里应该是将新书添加到后端服务或本地数据库的代码
    // 为了演示,我们不实际添加,只是打印信息
    print('Added book: ${book.title} by ${book.author}');
  }
}

请注意,上述代码中的OpenLibrary类和Book类是基于假设的。在实际使用中,open_library插件应该会提供这些类或相应的API来管理图书。你需要参考该插件的官方文档来了解具体的API和使用方法。如果open_library插件实际上存在,并且提供了不同的API,你需要根据插件的文档相应地调整代码。

回到顶部