聽詩吧-APP端分享總結

乖丨摸摸頭發表於2020-02-25

簡介

聽詩吧 是一個集 詩詞/詩人推薦、搜尋、簡介、賞析、朗讀(下個版本) 於一體的詩詞興趣 APP。涵蓋了從古代到近代的 20,000 位詩人的 500,000 首詩詞作品,敘事詩、抒情詩、送別詩、邊塞詩、山水田園詩、懷古詩、悼亡詩,詠物詩 應有盡有?。

  • APP 端基於 Google 最新研發的 Flutter UI 框架,一套程式碼庫高效構建多平臺精美應用(移動、Web、桌面和嵌入式平臺)?,配合 MaterialDesign 的設計風格 和 卡片式佈局 讓你眼前一亮。更有微信分享功能,好東西當然要分享?~

專案地址: github.com/mmtou/liste…
下載體驗: github.com/mmtou/liste…

聽詩吧-APP端分享總結

  • API 端基於 SpringBoot 微服務架構 和 輕量級的 MySQL 資料庫,給你帶來高效、穩定的服務體驗。更整合了百度的語音合成技術,讓你暢快的享受詩詞帶來的樂趣?。

先睹為快

聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結
聽詩吧-APP端分享總結

app端專案結構

├── components // 元件
│   ├── avatar.dart // 頭像元件,前期根據名稱生成對應顏色的頭像
│   ├── empty.dart // 置空元件
│   ├── poet.dart // 詩人列表
│   ├── poet_item.dart // 單個詩人
│   ├── poetry.dart // 詩詞列表
│   ├── poetry_item.dart // 單個詩詞
│   └── recommend.dart // 推薦頁元件
├── main.dart
├── utils // 工具類
│   ├── common.dart // 通用工具
│   ├── constant.dart // 常量
│   ├── favorite.dart // 點愛心的管理
│   ├── http.dart // 網路請求
└── views // 頁面
    ├── feedback.dart // 反饋
    ├── index.dart // 首頁
    ├── poet_detail.dart // 詩人
    ├── poetry_detail.dart // 詩詞
    └── search.dart // 搜尋
複製程式碼

核心程式碼

  1. APP 啟動時從本地讀取點贊列表
void main() {
  if (Platform.isAndroid) {
    SystemUiOverlayStyle systemUiOverlayStyle =
        SystemUiOverlayStyle(statusBarColor: Colors.transparent);
    SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
  }

  WidgetsFlutterBinding.ensureInitialized();
  run();
}

void run() async {
  await Favorite.getInstance();
  runApp(MyApp());
}
...

class Favorite {
  ...

  static Future<bool> getInstance() async {
    prefs = await SharedPreferences.getInstance();
    favorites = prefs.getStringList('favorites') ?? [];
    return true;
  }
  
  ...
}
複製程式碼
  1. 頭像元件,根據詩人名稱,計算16位UTF-16程式碼單元,然後根據規定的顏色陣列長度取餘,得到index,從顏色陣列的中得到某個色值,即為頭像的背景色。
Widget build(BuildContext context) {
    String name = Common.getShortName(authorName);
    int index = name.codeUnitAt(0) % Constant.avatarColors.length;
    Color color = Constant.avatarColors[index];

    return InkWell(
      onTap: () {
        if (authorId != null) {
          Common.toPoetDetail(context, authorId);
        }
      },
      child: CircleAvatar(
        backgroundColor: color,
        child: Center(
          child: Text(
            name,
            style: TextStyle(
              fontWeight: FontWeight.w600,
              color: Colors.white,
            ),
          ),
        ),
      ),
    );
  }
複製程式碼
  1. 微信分享,整合 fluwx 第三方外掛,快速實現微信分享、登入、支付等功能。
    1. 建立 keystore,修改相應配置
    2. 檢視簽名,執行keytool -list -v -keystore key.keystore命令後的MD5去掉:轉為小寫即為微信開放平臺的簽名。
    3. 登入微信開放平臺建立應用,填寫包名、簽名等資訊
    fluwx.registerWxApi(
        appId: "xxxx",
        universalLink: "xxxx");
    fluwx.shareToWeChat(WeChatShareTextModel(
        text: content,
        transaction: "transaction}",
        scene: WeChatScene.SESSION));
    複製程式碼

請移步 flutterchina.club/android-rel… 檢視簽名配置

  1. http.dart單例模式,減少資源浪費
import 'package:bot_toast/bot_toast.dart';
import 'package:dio/dio.dart';

import './constant.dart';

class Http {
  Dio _dio;

  // 工廠模式
  factory Http() => _getInstance();

  static Http get instance => _getInstance();
  static Http _instance;

  Http._internal() {
    // 初始化

    if (_dio == null) {
      _dio = Dio(
        BaseOptions(
            baseUrl: Constant.host,
            connectTimeout: 10000,
            receiveTimeout: 6000,
            headers: {'Content-Type': 'application/json'}),
      );

      _dio.interceptors
          .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
        BotToast.showLoading();
        return options; //continue
      }, onResponse: (Response response) async {
        BotToast.closeAllLoading();
        var data = response.data;
        if (!data['success']) {
          BotToast.showText(text: data['message']);
          throw (data['message']);
        }
        return response.data['result']; // continue
      }, onError: (DioError e) async {
        BotToast.closeAllLoading();
        if ('DioErrorType.DEFAULT' == e.type.toString()) {
          BotToast.showText(text: e.error);
        } else {
          BotToast.showText(text: '伺服器異常');
        }
        // Do something with response error
        return e; //continue
      }));
    }
  }

  static Http _getInstance() {
    if (_instance == null) {
      _instance = Http._internal();
    }
    return _instance;
  }

  Future get(uri, {queryParameters}) async {
    try {
      Response response = await _dio.get(uri, queryParameters: queryParameters);
      print(response);
      return response.data;
    } catch (e) {
      print(e);
    }
  }

  Future post(uri, {json}) async {
    try {
      Response response = await _dio.post(uri, data: json);
      return response.data;
    } catch (e) {
      print(e);
    }
  }
}
複製程式碼
  1. 使用TabView時,避免頁面重繪,造成資源浪費和體驗下降;子元件整合AutomaticKeepAliveClientMixin實現快取策略,且在build中加入super.build(context);
class Poetry extends StatefulWidget {
  @override
  _PoetryState createState() => _PoetryState();
}

class _PoetryState extends State<Poetry> with AutomaticKeepAliveClientMixin {
  List list;
  int pageNum = 1;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return EasyRefresh(
      header:
          BezierCircleHeader(backgroundColor: Theme.of(context).primaryColor),
      footer:
          BezierBounceFooter(backgroundColor: Theme.of(context).primaryColor),
      onRefresh: () => refresh(),
      onLoad: () => onLoad(),
      child: this.list == null
          ? Empty('暫無資料~')
          : ListView.separated(
              padding: EdgeInsets.all(16),
              itemCount: this.list.length,
              separatorBuilder: (BuildContext context, int index) => Container(
                    height: 12,
                  ),
              itemBuilder: (BuildContext context, int index) {
                var item = this.list[index];
                return PoetryItem(item);
              }),
    );
  }

  refresh() async {
    this.pageNum = 1;
    this.list = [];
    await this.getList();
    return true;
  }

  onLoad() async {
    pageNum += 1;
    await this.getList();
    return true;
  }

  // 詩詞列表
  getList() async {
    var data = await Http().get('/poetry/list?pageNum=$pageNum');
    if (data != null) {
      List list = data['list'];
      this.list = this.list ?? [];
      setState(() {
        this.list.addAll(list);
      });
    }
  }

  @override
  void initState() {
    super.initState();
    this.getList();
  }

  @override
  bool get wantKeepAlive => true;
複製程式碼
  1. InkWell元件可以實現點選後的波紋反饋效果,但是InkWell的child不能設定背景色,不然會覆蓋掉波紋的效果。需要你又需要背景色怎麼辦呢?可以在InkWell上包一層Ink
Ink(
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
      ),
      child: InkWell(
        onTap: () => Common.toPoetryDetail(context, widget.poetry),
        child: Container(
          padding: EdgeInsets.all(12),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
          ),
        ),
      )
    );
複製程式碼

功能

  • 推薦
  • 廣場
  • 詩人
  • 詩詞詳情
  • 詩人詳情
  • 微信分享
  • 搜尋
  • 詩詞朗讀
  • 登入

最後

未完待續~

聽詩吧-APP端分享總結

願你走出半生,歸來仍是少年。

相關文章