美文网首页
18.flutter-两级折叠List

18.flutter-两级折叠List

作者: ChaosHeart | 来源:发表于2022-08-13 17:22 被阅读0次

    插件部分

    ///初始数据
    abstract class BaseBean {
      bool isOpen = true;
      int index = 0;
      int getChildSize();
    }
    
    
    import 'package:flutter/material.dart';
    
    import 'base_bean.dart';
    
    typedef GroupChildViewCreate = Widget Function(int parentIndex, int childIndex);
    typedef SectionViewCreate = Widget Function(int index);
    
    ///折叠列表 - 2
    class TwoLevelWidget<T extends BaseBean> extends StatefulWidget {
      final GroupChildViewCreate groupChildViewCreate;
      final SectionViewCreate sectionViewCreate;
      final T data;
      TwoLevelWidget(
        this.groupChildViewCreate,
        this.sectionViewCreate,
        this.data,
      );
    
      @override
      State<StatefulWidget> createState() => _TwoLevelWidgetState();
    }
    
    class _TwoLevelWidgetState extends State<TwoLevelWidget> {
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            Container(
              width: double.infinity,
              child: widget.sectionViewCreate(widget.data.index),
            ),
            widget.data.isOpen
                ? Padding(
                    padding: EdgeInsets.only(left: 30),
                    child: ListView.builder(
                      itemBuilder: (context, index) {
                        return widget.groupChildViewCreate(widget.data.index, index);
                      },
                      itemCount: widget.data.getChildSize(),
                      //内嵌listView 这个值要设置成true
                      shrinkWrap: true,
                      primary: true,
                      //嵌套滑动这个也得限制 不然 滑动子列表 外层不滚动
                      physics: NeverScrollableScrollPhysics(),
                    ))
                : Container()
          ],
        );
      }
    }
    
    
    import 'package:flutter/gestures.dart';
    import 'package:flutter/material.dart';
    
    import 'base_bean.dart';
    import 'two_level_widget.dart';
    
    ///折叠列表 - 1
    class GroupListView<T extends BaseBean> extends StatefulWidget {
      ///Function which returns the number of items(rows) in a specified section.
      final int Function(int section) countOfItemInSection;
    
      ///Fields from ListView.builder constructor
    
      /// The axis along which the scroll view scrolls.
      ///
      /// Defaults to [Axis.vertical].
      final Axis scrollDirection;
    
      /// Whether the scroll view scrolls in the reading direction.
      ///
      /// For example, if the reading direction is left-to-right and
      /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from
      /// left to right when [reverse] is false and from right to left when
      /// [reverse] is true.
      ///
      /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view
      /// scrolls from top to bottom when [reverse] is false and from bottom to top
      /// when [reverse] is true.
      ///
      /// Defaults to false.
      final bool reverse;
    
      /// An object that can be used to control the position to which this scroll
      /// view is scrolled.
      ///
      /// Must be null if [primary] is true.
      ///
      /// A [ScrollController] serves several purposes. It can be used to control
      /// the initial scroll position (see [ScrollController.initialScrollOffset]).
      /// It can be used to control whether the scroll view should automatically
      /// save and restore its scroll position in the [PageStorage] (see
      /// [ScrollController.keepScrollOffset]). It can be used to read the current
      /// scroll position (see [ScrollController.offset]), or change it (see
      /// [ScrollController.animateTo]).
      final ScrollController controller;
    
      /// Whether this is the primary scroll view associated with the parent
      /// [PrimaryScrollController].
      ///
      /// When this is true, the scroll view is scrollable even if it does not have
      /// sufficient content to actually scroll. Otherwise, by default the user can
      /// only scroll the view if it has sufficient content. See [physics].
      ///
      /// On iOS, this also identifies the scroll view that will scroll to top in
      /// response to a tap in the status bar.
      ///
      /// Defaults to true when [scrollDirection] is [Axis.vertical] and
      /// [controller] is null.
      final bool primary;
    
      /// How the scroll view should respond to user input.
      ///
      /// For example, determines how the scroll view continues to animate after the
      /// user stops dragging the scroll view.
      ///
      /// Defaults to matching platform conventions. Furthermore, if [primary] is
      /// false, then the user cannot scroll if there is insufficient content to
      /// scroll, while if [primary] is true, they can always attempt to scroll.
      ///
      /// To force the scroll view to always be scrollable even if there is
      /// insufficient content, as if [primary] was true but without necessarily
      /// setting it to true, provide an [AlwaysScrollableScrollPhysics] physics
      /// object, as in:
      ///
      /// ```dart
      ///   physics: const AlwaysScrollableScrollPhysics(),
      /// ```
      ///
      /// To force the scroll view to use the default platform conventions and not
      /// be scrollable if there is insufficient content, regardless of the value of
      /// [primary], provide an explicit [ScrollPhysics] object, as in:
      ///
      /// ```dart
      ///   physics: const ScrollPhysics(),
      /// ```
      ///
      /// The physics can be changed dynamically (by providing a new object in a
      /// subsequent build), but new physics will only take effect if the _class_ of
      /// the provided object changes. Merely constructing a new instance with a
      /// different configuration is insufficient to cause the physics to be
      /// reapplied. (This is because the final object used is generated
      /// dynamically, which can be relatively expensive, and it would be
      /// inefficient to speculatively create this object each frame to see if the
      /// physics should be updated.)
      final ScrollPhysics physics;
    
      /// Whether the extent of the scroll view in the [scrollDirection] should be
      /// determined by the contents being viewed.
      ///
      /// If the scroll view does not shrink wrap, then the scroll view will expand
      /// to the maximum allowed size in the [scrollDirection]. If the scroll view
      /// has unbounded constraints in the [scrollDirection], then [shrinkWrap] must
      /// be true.
      ///
      /// Shrink wrapping the content of the scroll view is significantly more
      /// expensive than expanding to the maximum allowed size because the content
      /// can expand and contract during scrolling, which means the size of the
      /// scroll view needs to be recomputed whenever the scroll position changes.
      ///
      /// Defaults to false.
      final bool shrinkWrap;
    
      /// The amount of space by which to inset the children.
      final EdgeInsetsGeometry padding;
    
      /// If non-null, forces the children to have the given extent in the scroll
      /// direction.
      ///
      /// Specifying an [itemExtent] is more efficient than letting the children
      /// determine their own extent because the scrolling machinery can make use of
      /// the foreknowledge of the children's extent to save work, for example when
      /// the scroll position changes drastically.
      final double itemExtent;
    
      /// Whether to wrap each child in an [AutomaticKeepAlive].
      ///
      /// Typically, children in lazy list are wrapped in [AutomaticKeepAlive]
      /// widgets so that children can use [KeepAliveNotification]s to preserve
      /// their state when they would otherwise be garbage collected off-screen.
      ///
      /// This feature (and [addRepaintBoundaries]) must be disabled if the children
      /// are going to manually maintain their [KeepAlive] state. It may also be
      /// more efficient to disable this feature if it is known ahead of time that
      /// none of the children will ever try to keep themselves alive.
      ///
      /// Defaults to true.
      final bool addAutomaticKeepAlives;
    
      /// Whether to wrap each child in a [RepaintBoundary].
      ///
      /// Typically, children in a scrolling container are wrapped in repaint
      /// boundaries so that they do not need to be repainted as the list scrolls.
      /// If the children are easy to repaint (e.g., solid color blocks or a short
      /// snippet of text), it might be more efficient to not add a repaint boundary
      /// and simply repaint the children during scrolling.
      ///
      /// Defaults to true.
      final bool addRepaintBoundaries;
    
      /// Whether to wrap each child in an [IndexedSemantics].
      ///
      /// Typically, children in a scrolling container must be annotated with a
      /// semantic index in order to generate the correct accessibility
      /// announcements. This should only be set to false if the indexes have
      /// already been provided by an [IndexedChildSemantics] widget.
      ///
      /// Defaults to true.
      ///
      /// See also:
      ///
      ///  * [IndexedChildSemantics], for an explanation of how to manually
      ///    provide semantic indexes.
      final bool addSemanticIndexes;
    
      /// {@macro flutter.rendering.viewport.cacheExtent}
      final double cacheExtent;
    
      /// The number of children that will contribute semantic information.
      ///
      /// Some subtypes of [ScrollView] can infer this value automatically. For
      /// example [ListView] will use the number of widgets in the child list,
      /// while the [new ListView.separated] constructor will use half that amount.
      ///
      /// For [CustomScrollView] and other types which do not receive a builder
      /// or list of widgets, the child count must be explicitly provided. If the
      /// number is unknown or unbounded this should be left unset or set to null.
      ///
      /// See also:
      ///
      ///  * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property.
      final int semanticChildCount;
    
      /// {@macro flutter.widgets.scrollable.dragStartBehavior}
      final DragStartBehavior dragStartBehavior;
      final GroupChildViewCreate groupChildViewCreate;
      final List<T> data;
      final SectionViewCreate sectionViewCreate;
    
      const GroupListView(
          {Key key,
          @required this.countOfItemInSection,
          this.scrollDirection = Axis.vertical,
          this.reverse = false,
          this.controller,
          this.primary,
          this.physics,
          this.shrinkWrap = false,
          this.padding,
          this.itemExtent,
          this.addAutomaticKeepAlives = true,
          this.addRepaintBoundaries = true,
          this.addSemanticIndexes = true,
          this.cacheExtent,
          this.semanticChildCount,
          this.dragStartBehavior = DragStartBehavior.start,
          this.groupChildViewCreate,
          @required this.data,
          @required this.sectionViewCreate})
          : assert(data != null),
            assert(countOfItemInSection != null),
            super(key: key);
    
      @override
      _GroupListViewState createState() => _GroupListViewState();
    }
    
    class _GroupListViewState extends State<GroupListView> {
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          scrollDirection: widget.scrollDirection,
          reverse: widget.reverse,
          controller: widget.controller,
          primary: widget.primary,
          physics: widget.physics,
          shrinkWrap: widget.shrinkWrap,
          padding: widget.padding,
          itemExtent: widget.itemExtent,
          addAutomaticKeepAlives: widget.addAutomaticKeepAlives,
          addRepaintBoundaries: widget.addRepaintBoundaries,
          addSemanticIndexes: widget.addSemanticIndexes,
          cacheExtent: widget.cacheExtent,
          semanticChildCount: widget.semanticChildCount,
          dragStartBehavior: widget.dragStartBehavior,
          itemCount: widget.data.length,
          itemBuilder: _itemBuilder,
        );
      }
    
      Widget _itemBuilder(BuildContext context, int index) {
        return TwoLevelWidget(widget.groupChildViewCreate, widget.sectionViewCreate, widget.data[index]);
      }
    }
    
    

    使用部分

    import 'package:flutter_fold_list/group_list/base_bean.dart';
    
    ///数据
    class GroupBean extends BaseBean {
      String title;
      List<ChildBean> childBeans = [];
    
      @override
      int getChildSize() => childBeans.length;
    }
    
    class ChildBean {
      int childIndex;
      String childTitle;
    }
    
    
    import 'dart:core';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_fold_list/group_bean.dart';
    
    import 'group_list/group_list_view.dart';
    
    ///实例界面
    class GroupListPage extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _GroupListPageState();
    }
    
    class _GroupListPageState extends State<GroupListPage> {
      List<GroupBean> _parentBeans = [];
    
      @override
      void initState() {
        super.initState();
        initData();
      }
    
      void initData() {
        for (int i = 0; i < 10; i++) {
          GroupBean parentData = GroupBean();
          parentData.index = i;
          parentData.title = "title$i";
          List<ChildBean> childBeans = [];
          for (int j = 0; j < 10; j++) {
            ChildBean childBean = ChildBean();
            childBean.childIndex = j;
            childBean.childTitle = "childTitl$j";
            childBeans.add(childBean);
          }
          parentData.childBeans = childBeans;
          _parentBeans.add(parentData);
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          backgroundColor: Colors.blue,
          appBar: AppBar(
            centerTitle: true,
            title: Text("二级折叠List"),
          ),
          body: GroupListView<GroupBean>(
            //总数据
            data: _parentBeans,
            //标题列表 - 1
            sectionViewCreate: (section) {
              return GestureDetector(
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8),
                  child: Text(
                    _parentBeans[section].title,
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: Colors.red),
                  ),
                ),
                onTap: () {
                  _parentBeans[section].isOpen = !_parentBeans[section].isOpen;
                  setState(() {});
                },
              );
            },
            //标题 对应 列表的个数 - 2
            countOfItemInSection: (int parentIndex) {
              return _parentBeans[parentIndex].childBeans.length;
            },
            //列表中的item - 2
            groupChildViewCreate: (parentIndex, childIndex) {
              return Text(
                _parentBeans[parentIndex].childBeans[childIndex].childTitle,
                style: TextStyle(color: Colors.white, fontSize: 18),
              );
            },
          ),
        );
      }
    }
    
    

    参考:
    https://www.jianshu.com/p/336a2ce21dfc

    相关文章

      网友评论

          本文标题:18.flutter-两级折叠List

          本文链接:https://www.haomeiwen.com/subject/xtiqgrtx.html