142 lines
4.4 KiB
Dart
142 lines
4.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'tree_view_controller.dart';
|
|
import 'tree_view_theme.dart';
|
|
import 'tree_node.dart';
|
|
import 'models/node.dart';
|
|
|
|
/// Defines the [TreeView] widget.
|
|
///
|
|
/// This is the main widget for the package. It requires a controller
|
|
/// and allows you to specify other optional properties that manages
|
|
/// the appearance and handle events.
|
|
///
|
|
/// ```dart
|
|
/// TreeView(
|
|
/// controller: _treeViewController,
|
|
/// allowParentSelect: false,
|
|
/// supportParentDoubleTap: false,
|
|
/// onExpansionChanged: _expandNodeHandler,
|
|
/// onNodeTap: (key) {
|
|
/// setState(() {
|
|
/// _treeViewController = _treeViewController.copyWith(selectedKey: key);
|
|
/// });
|
|
/// },
|
|
/// theme: treeViewTheme
|
|
/// ),
|
|
/// ```
|
|
class TreeView extends InheritedWidget {
|
|
/// The controller for the [TreeView]. It manages the data and selected key.
|
|
final TreeViewController controller;
|
|
|
|
/// The tap handler for a node. Passes the node key.
|
|
final Function(String)? onNodeTap;
|
|
|
|
/// Custom builder for nodes. Parameters are the build context and tree node.
|
|
final Widget Function(BuildContext, Node)? nodeBuilder;
|
|
|
|
/// The double tap handler for a node. Passes the node key.
|
|
final Function(String)? onNodeDoubleTap;
|
|
|
|
/// The expand/collapse handler for a node. Passes the node key and the
|
|
/// expansion state.
|
|
final Function(String, bool)? onExpansionChanged;
|
|
|
|
/// The theme for [TreeView].
|
|
final TreeViewTheme theme;
|
|
|
|
/// Determines whether the user can select a parent node. If false,
|
|
/// tapping the parent will expand or collapse the node. If true, the node
|
|
/// will be selected and the use has to use the expander to expand or
|
|
/// collapse the node.
|
|
final bool allowParentSelect;
|
|
|
|
/// How the [TreeView] should respond to user input.
|
|
final ScrollPhysics? physics;
|
|
|
|
/// Whether the extent of the [TreeView] should be determined by the contents
|
|
/// being viewed.
|
|
///
|
|
/// Defaults to false.
|
|
final bool shrinkWrap;
|
|
|
|
/// Whether the [TreeView] is the primary scroll widget associated with the
|
|
/// parent PrimaryScrollController..
|
|
///
|
|
/// Defaults to true.
|
|
final bool primary;
|
|
|
|
/// Determines whether the parent node can receive a double tap. This is
|
|
/// useful if [allowParentSelect] is true. This allows the user to double tap
|
|
/// the parent node to expand or collapse the parent when [allowParentSelect]
|
|
/// is true.
|
|
/// ___IMPORTANT___
|
|
/// _When true, the tap handler is delayed. This is because the double tap
|
|
/// action requires a short delay to determine whether the user is attempting
|
|
/// a single or double tap._
|
|
final bool supportParentDoubleTap;
|
|
|
|
TreeView({
|
|
Key? key,
|
|
required this.controller,
|
|
this.onNodeTap,
|
|
this.onNodeDoubleTap,
|
|
this.physics,
|
|
this.onExpansionChanged,
|
|
this.allowParentSelect: false,
|
|
this.supportParentDoubleTap: false,
|
|
this.shrinkWrap: false,
|
|
this.primary: true,
|
|
this.nodeBuilder,
|
|
TreeViewTheme? theme,
|
|
}) : this.theme = theme ?? const TreeViewTheme(),
|
|
super(
|
|
key: key,
|
|
child: _TreeViewData(
|
|
controller,
|
|
shrinkWrap: shrinkWrap,
|
|
primary: primary,
|
|
physics: physics,
|
|
),
|
|
);
|
|
|
|
static TreeView? of(BuildContext context) =>
|
|
context.dependOnInheritedWidgetOfExactType(aspect: TreeView);
|
|
|
|
@override
|
|
bool updateShouldNotify(TreeView oldWidget) {
|
|
return oldWidget.controller.children != this.controller.children ||
|
|
oldWidget.onNodeTap != this.onNodeTap ||
|
|
oldWidget.onExpansionChanged != this.onExpansionChanged ||
|
|
oldWidget.theme != this.theme ||
|
|
oldWidget.supportParentDoubleTap != this.supportParentDoubleTap ||
|
|
oldWidget.allowParentSelect != this.allowParentSelect;
|
|
}
|
|
}
|
|
|
|
class _TreeViewData extends StatelessWidget {
|
|
final TreeViewController _controller;
|
|
final bool? shrinkWrap;
|
|
final bool? primary;
|
|
final ScrollPhysics? physics;
|
|
|
|
const _TreeViewData(this._controller,
|
|
{this.shrinkWrap, this.primary, this.physics});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
ThemeData _parentTheme = Theme.of(context);
|
|
return Theme(
|
|
data: _parentTheme.copyWith(hoverColor: Colors.grey.shade100),
|
|
child: ListView(
|
|
shrinkWrap: shrinkWrap!,
|
|
primary: primary,
|
|
physics: physics,
|
|
padding: EdgeInsets.zero,
|
|
children: _controller.children.map((Node node) {
|
|
return TreeNode(node: node);
|
|
}).toList(),
|
|
),
|
|
);
|
|
}
|
|
}
|