FLUTTER ECOSYSTEM

MelbourneDeveloper/arborio

アニメーション付きの洗練された柔軟なツリービュー。Flutterで階層データを表示します。

アーボリオ のプロジェクト画像
Stars
14
Forks
4
最終プッシュ(UTC)
2024/12/15
プロジェクト状態
公開中
Christian Findlay GitHub avatar
GITHUB User

Christian Findlay ↗

Building frameworks, tools and apps with AI in Melbourne, Australia

Melbourne, Australia公式サイト ↗
言語DartC++CMakeHTMLSwiftCShellKotlinObjective-C

技術トピック

使用している依存関係

依存関係一覧 6 件

元の README

以下は英語原文のスナップショットです。最新版は GitHub をご覧ください。

README を開く / 閉じる

Arborio

CI Coverage

An elegant, flexible Treeview with Animation. Display hierarchical data in Flutter.

Logo

Sample

Check out the live sample app here

Features

  • 🌳 Hierarchical data display with unlimited nesting
  • ✨ Smooth animations for expand/collapse operations
  • 🎨 Fully customizable node and expander appearance
  • 🔑 Global key support for programmatic control
  • 🎯 Type-safe with generics support
  • 📱 Responsive and mobile-friendly

Basic Usage

Here's a simple example of how to create a tree view:

import 'package:arborio/tree_view.dart';
import 'package:flutter/material.dart';

enum ElementType { file, folder }

// Define your data type
class FileSystemElement {
  FileSystemElement(this.name, this.type);
  final String name;
  final ElementType type;
}

// Create tree nodes
final nodes = [
  TreeNode<FileSystemElement>(
    const Key('root'),
    FileSystemElement('Documents', ElementType.folder),
    [
      TreeNode<FileSystemElement>(
        const Key('child1'),
        FileSystemElement('report.pdf', ElementType.file),
      ),
    ],
  ),
];

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
        home: Scaffold(
          body: TreeView<FileSystemElement>(
            nodes: nodes,
            builder: (context, node, isSelected, animation, select) => Row(
              children: [
                Icon(
                  node.data.type == ElementType.folder
                      ? Icons.folder
                      : Icons.file_copy,
                ),
                Text(node.data.name),
              ],
            ),
            expanderBuilder: (context, isExpanded, animation) =>
                RotationTransition(
              turns: animation,
              child: const Icon(Icons.chevron_right),
            ),
          ),
        ),
        debugShowCheckedModeBanner: false,
      );
}

Using TreeViewKey

The TreeViewKey allows programmatic control of the tree view:

// Create a key
const treeViewKey = TreeViewKey<FileSystemElement>();

// Use it in your TreeView
TreeView<FileSystemElement>(
  key: treeViewKey,
  nodes: nodes,
  builder: (context, node, isSelected, animation, select) {
    // ... node builder implementation
  },
  expanderBuilder: (context, isExpanded, animation) {
    return RotationTransition(
      turns: animation,
      child: const Icon(Icons.chevron_right),
    );
  },
)

Node Management

You can dynamically add or remove nodes using the tree's state. This example uses mutable state for simplicitly, but you can achieve the same result with immutable data classes.

// Add a new node
FloatingActionButton(
  onPressed: () => setState(() {
    nodes.add(
      TreeNode(
        const Key('newnode'),
        FileSystemElement('New Folder', ElementType.folder),
      ),
    );
  }),
  child: const Icon(Icons.add),
),

// Expand/collapse all nodes
FloatingActionButton(
  onPressed: () => setState(() {
    treeViewKey.currentState?.expandAll();
  }),
  child: const Icon(Icons.expand),
),

FloatingActionButton(
  onPressed: () => setState(() {
    treeViewKey.currentState?.collapseAll();
  }),
  child: const Icon(Icons.compress),
),

Handling Node Events

TreeView<FileSystemElement>(
  onExpansionChanged: (node, expanded) {
    print('Node ${node.data.name} is now ${expanded ? 'expanded' : 'collapsed'}');
  },
  onSelectionChanged: (node) {
    print('Selected node: ${node.data.name}');
  },
  expanderBuilder: (context, isExpanded, animation) {
    return RotationTransition(
      turns: animation,
      child: const Icon(Icons.chevron_right),
    );
  },
)

Customizing Node Appearance

The builder parameter gives you full control over node appearance, along with an animation variable so you can respond to changes over time:

builder: (context, node, isSelected, animation, select) {
  return InkWell(
    onTap: () => select(node),
    child: Container(
      color: isSelected ? Colors.blue.withOpacity(0.1) : null,
      padding: const EdgeInsets.all(8),
      child: Row(
        children: [
          if (node.data.type == ElementType.folder)
            RotationTransition(
              turns: animation,
              child: const Icon(Icons.folder),
            )
          else
            const Icon(Icons.file_copy),
          const SizedBox(width: 8),
          Text(node.data.name),
        ],
      ),
    ),
  );
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the BSD 3-Clause - see the LICENSE file for details.