正确使用Flutter的Listview

  • Post author:
  • Post category:其他


使用了很长时间的flutte 和 listview;  感觉没有Android 那样便捷使用; 既然flutter不提供,我们只能自己造轮子了;

适配器封装

/// CommonListView的适配器
abstract class BaseListViewAdapter<T> {
  ///数据源
  final List<T> _list;

  ///item 点击事件
  OnItemClickListener<T>? onItemClickListener;

  /// item中小组件点击事件回调
  OnChildClickListener<T>? onChildClickListener;

  BaseListViewAdapter(this._list,
      {this.onItemClickListener, this.onChildClickListener});

  void setOnItemClickListener(OnItemClickListener<T>? onItemClickListener) {
    this.onItemClickListener = onItemClickListener;
  }

  void setOnChildClickListener(OnChildClickListener<T>? onChildClickListener) {
    this.onChildClickListener = onChildClickListener;
  }

  ///重置数据
  void setData(List<T> list) {
    _list.clear();
    _list.addAll(list);
  }

  ///添加数据
  void addData(List<T> list) {
    _list.addAll(list);
  }

  int getItemCount() {
    return _list.length;
  }

  List<T> getData() {
    return _list;
  }

  T getItemData(int position) {
    return _list[position];
  }

  ///外部获取条目
  Widget getContentWidget(int index) {
    T data = getItemData(index);  
    return _buildContentWidget(index, data);
  }

  _buildContentWidget(int index, T data) {
    return InkWell(
      onTap: checkDoubleClick(() {
        onItemClickListener?.call(index, data);
      }),
      child: buildContentWidget(index, data),
    );
  }

  /// 条目widget
  Widget buildContentWidget(int index, T data);

  /// 分割线widget; 可重写
  Widget buildSeparatorBuilder(int index) {
    return SizedBox(
      height: 24.h,
    );
  }


}
/// ================================================
/// author : Alex
/// version:
/// Description:
/// <p>  CommonListView 集成了 SmartRefresher 和 缺省也;
///      根据 controller 判断是否添加 SmartRefresher
///      是否实现 onRefresh onLoading; 决定了是否开始刷新和加载;
///
///      根据 viewState 判断是否添加 buildPartBaseView
/// Created by  on 2022/9/13
/// ================================================

enum ListViewType { builder, separated }

typedef OnItemClickListener<T> = void Function(int index, T item);

typedef OnChildClickListener<T> = void Function(int index, String tag, T item);

class CommonListView extends StatelessWidget {
  ///布局适配器
  final BaseListViewAdapter commonListViewAdapter;

  ///obx 更新列表用
  final int itemListCount;

  ///listview 类型
  final ListViewType? liveViewType;

  /// 刷新控制器
  final RefreshController? controller;

  ///刷新回调
  final VoidCallback? onRefresh;

  /// 加载回调
  final VoidCallback? onLoading;

  ///布局状态
  final int viewState;

  ///listview的属性
  final bool shrinkWrap;
  final bool enableScroll;
  final EdgeInsetsGeometry padding;

  ///空布局展位图
  final String? emptyImage;
  final Widget? emptyWidget;
  final String? emptyText;
  final EdgeInsetsGeometry baseViewPadding;

  /// 失败重试
  final VoidCallback? onRetry;

  ///listview控制器
  final ScrollController? listController;

  const CommonListView(
    this.commonListViewAdapter,
    this.itemListCount, {
    Key? key,
    this.emptyImage,
    this.emptyText,
    this.onRetry,
    this.liveViewType = ListViewType.builder,
    this.controller,
    this.onRefresh,
    this.onLoading,
    this.emptyWidget,
    this.baseViewPadding = EdgeInsets.zero,
    this.viewState = -1,
    this.shrinkWrap = false,
    this.enableScroll = true,
    this.padding = EdgeInsets.zero,
    this.listController,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (controller == null) {
      return _buildListView(context);
    }

    return SmartRefresher(
      header: ClassicHeader(),
      enablePullDown: onRefresh != null,
      enablePullUp: onLoading != null,
      controller: controller!,
      onRefresh: () {
        onRefresh?.call();
      },
      onLoading: () {
        onLoading?.call();
      },
      child: _buildListView(context),
    );
  }

  Widget _buildListView(BuildContext context) {
    Widget? listView;
    switch (liveViewType!) {
      case ListViewType.builder:
        listView = ListView.builder(
            controller: listController,
            padding: padding,
            shrinkWrap: shrinkWrap,
            physics: enableScroll ? null : NeverScrollableScrollPhysics(),
            itemBuilder: (BuildContext context, int index) {
              return commonListViewAdapter.getContentWidget(index);
            },
            itemCount: itemListCount);
        break;
      case ListViewType.separated:
        listView = ListView.separated(
          controller: listController,
          physics: enableScroll ? null : NeverScrollableScrollPhysics(),
          padding: padding,
          shrinkWrap: shrinkWrap,
          itemCount: itemListCount,
          itemBuilder: (BuildContext context, int index) {
            return commonListViewAdapter.getContentWidget(index);
          },
          separatorBuilder: (BuildContext context, int index) {
            return commonListViewAdapter.buildSeparatorBuilder(index);
          },
        );
        break;
    }

    if (viewState == -1) {
      return listView;
    }

    return buildPartBaseView(
        viewState != TYPE_NORMAL
            ? viewState
            : (itemListCount == 0 ? TYPE_EMPTY : viewState),
        context,
        listView,
        emptyImage: emptyImage,
        emptyText: emptyText,
        onRetry: onRetry,
        emptyWidget: emptyWidget,
        padding: baseViewPadding);
  }
}

使用案例

class TestListAdapter extends BaseListViewAdapter<String> {
  TestListAdapter (List<String> list)
      : super(list);

  @override
  Widget buildContentWidget(int index, Stringdata) {
    return Container(),
    );
  }
CommonListView(
                  state.adapter,
                  state.itemList().length,
                  viewState: state.getViewState(),
                  controller: state.refreshController,
                  liveViewType: ListViewType.separated,
                  padding: EdgeInsets.all(24.w),
                  onRefresh: () => logic.initData(false),
                  onLoading: () =>
                      logic.onRequestListData(current: logic.state.currentPage),
                  emptyText: "暂无数据",
                  baseViewPadding: EdgeInsets.only(bottom: 68.w),
                )



版权声明:本文为qq_41628942原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。