flutter_boot 0.0.7 copy "flutter_boot: ^0.0.7" to clipboard
flutter_boot: ^0.0.7 copied to clipboard

outdated

Libraries that enable rapid development of Flutter, the current implementation of the ViewModel framework layer, lifecycle aware network request encapsulation, and common convenient methods。

助力Flutter快速开发的库、目前实现ViewModel框架层、生命周期感知的网络请求封装及常用便捷方法。

功能 #

  • MVI
  • 网络请求,基于Dio 封装,生命周期感知。
  • LiveViewModel 。
  • 常用工具 ,便捷方法拓展。
  • 功能性组件
    • LayoutOnCreated :首次渲染完成回调
  • 外观组件
    • Dot 小圆点

开始 #

flutter pub add flutter_boot

ViewModel #

配合ViewModelStateBuilder用于观察多个状态变化。


ViewModelStateBuilder(
    //状态,要观察的 view model 的状态
    state: [viewModel.stateCounter],
    builder: (context, child) {
      var counterValue = viewModel.stateCounter.value;

      return Text(
        // 计数
        '${counterValue.num}',
        style: Theme.of(context)
            .textTheme
            .headlineMedium
            ?.copyWith(color: counterValue.color),
      );
    })

基础网络请求 #

基于Dio封装的网络请求,简化请求参数。

import 'dart:convert';

import 'package:example/model/base_model.dart';
import 'package:example/model/bili_bili.dart';
import 'package:example/model/words.dart';
import 'package:flutter/material.dart';
import 'package:flutter_boot/http.dart';

class BaseHttpPage extends StatefulWidget {
  const BaseHttpPage({super.key, required this.title});

  final String title;

  @override
  State<BaseHttpPage> createState() => _BaseHttpPageState();
}

class _BaseHttpPageState extends State<BaseHttpPage> {
  var textController = TextEditingController(text: "厚德载物");
  var wordsTip = "";
  var recordCount = 0;
  var isLoading = false;

  void showLoadingDialog(BuildContext context) {
    if (isLoading) {
      return;
    }
    this.isLoading = true;
    showDialog(
        context: context,
        builder: (ctx) {
          return Dialog(
            child: SizedBox(
              height: 100,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  CircularProgressIndicator(),
                ],
              ),
            ),
          );
        });
  }

  void dismissLoadingDialog(BuildContext context) {
    if (this.isLoading) {
      this.isLoading = false;
      Navigator.pop(context);
    }
  }

  void _searchWords() async {
    showLoadingDialog(context);

    var words = textController.text;
    //词语查询
    var wardsParam = Param.url("https://v.api.aa1.cn/api/api-chengyu/index.php")
        .tie("msg", words, type: ParamType.query);

    AnHttp.anHttpJson<Words>(wardsParam,
        convertor: (value) => Words.fromJson(value)).then((value) {
      if (value.code == "1") {
        setState(() {
          wordsTip = value.cyjs ?? "";
        });
      } else {
        setState(() {
          wordsTip = value.error ?? "";
        });
      }
      dismissLoadingDialog(context);
    });
  }

  void _clickRequest() async {
    showLoadingDialog(context);
    //哔哩哔哩每周必看
    var param = Param.url("https://tenapi.cn/v2/{id}")
        .tie("num", 120, type: ParamType.query) // query 参数
        .tie("id", "weekly", type: ParamType.path); //path 参数

    //网络请求
    AnHttp.anHttp<String>(param, method: HttpMethodType.get).then((value) {
      var jsonMap = jsonDecode(value.data!);
      var bili = BaseModel<BiliBili>.fromJson(
          jsonMap, (json) => BiliBili.fromJson(json));

      if (bili.data != null) {
        setState(() {
          recordCount = bili.data?.list.length ?? 0;
        });
      }
      dismissLoadingDialog(context);
    }).catchError((err) {
      print("------err:${err}");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Container(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Padding(
                padding:
                    const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
                child: Row(
                  children: [
                    Expanded(
                        child: TextField(
                      controller: textController,
                      decoration: InputDecoration(labelText: "词语查询"),
                    )),
                    OutlinedButton(onPressed: _searchWords, child: Text("查询"))
                  ],
                ),
              ),
              Padding(
                padding:
                    const EdgeInsets.symmetric(vertical: 8, horizontal: 20),
                child: Container(
                  color: Colors.blueGrey,
                  child: Text(wordsTip),
                  padding: EdgeInsets.all(12),
                  width: double.infinity,
                ),
              ),
              Center(
                  child: OutlinedButton(
                      onPressed: _clickRequest, child: Text("哔哩哔哩每周必看"))),
              Text("记录数量:${recordCount}")
            ],
          ),
        ),
      ),
    );
  }
}

MVI #

LiveViewModel与AnHttpViewModelScope来请求接口。实现关闭页面自动断开请求。

import 'dart:async';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:example/http_view_model.dart';
import 'package:example/model/bili_bili_record.dart';
import 'package:flutter/material.dart';
import 'package:flutter_boot/lifecycle.dart';

class HttpViewModelPage extends StatefulWidget {
  final String title;

  const HttpViewModelPage({super.key, required this.title});

  @override
  State<HttpViewModelPage> createState() => _HttpViewModelPageState();
}

class _HttpViewModelPageState extends State<HttpViewModelPage>
    with AnHttpViewModelScope<HttpViewModelPage> {
  //自定义 RefreshIndicatorState 类型的 Key
  final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey();

  //ViewModel 初始化
  late var viewModel = HttpPageViewModel(this);
  var scrollerController = ScrollController();

  @override
  void initState() {
    super.initState();
    scrollerController.addListener(() {
      if (scrollerController.position.pixels ==
          scrollerController.position.maxScrollExtent) {
        viewModel.loadBiliBili();
      }
    });
  }

  @override
  FutureOr<void> onRendered(BuildContext context) {
    _refreshKey.currentState?.show();
  }

  /// 处理接收到的通知
  @override
  void onNotify(String message, {int? what, Object? data}) {
    if(what==10){
      print('收到通知:${message}  标识:${what}  数据:${data}');
    }
  }

  Future _onRefresh() async {
    viewModel.currentPage = 1;
    return viewModel.loadBiliBili();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: RefreshIndicator(
          key: _refreshKey,
          onRefresh: _onRefresh,
          // ViewModelStateBuilder 监听状态
          child: ViewModelStateBuilder(
              state: [viewModel.recordState],
              builder: (context, child) {
                var records = viewModel.recordState.value;
                return ListView.separated(
                    controller: scrollerController,
                    separatorBuilder: (context, index) {
                      return const Divider(
                        height: 1,
                      );
                    },
                    itemCount: records.length,
                    itemBuilder: (context, index) {
                      var item = records[index];
                      return itemWidget(
                          context, item, index == records.length - 1);
                    });
              })),
    );
  }

  Widget itemWidget(BuildContext context, BiliBiliRecord item, bool last) {
    return Container(
      color: Colors.white,
      child: Column(
        children: [
          ListTile(
            leading: CachedNetworkImage(
              imageUrl: item.cover,
              placeholder: (context, url) => Icon(Icons.downloading),
              errorWidget: (context, url, error) => Icon(Icons.error),
            ),
            title: Text(item.title),
            subtitle: Text(item.reason),
          ),
          if (last)
            Container(
              padding: const EdgeInsets.symmetric(vertical: 12),
              child: const Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  SizedBox(
                    width: 16,
                    height: 16,
                    child: CircularProgressIndicator(),
                  ),
                  SizedBox(
                    width: 12,
                  ),
                  Text("加载更多")
                ],
              ),
            )
        ],
      ),
    );
  }
}

2
likes
0
points
360
downloads

Publisher

verified publisherymex.cn

Weekly Downloads

Libraries that enable rapid development of Flutter, the current implementation of the ViewModel framework layer, lifecycle aware network request encapsulation, and common convenient methods。

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, flutter

More

Packages that depend on flutter_boot