Ориентированный граф флаттера. Могу ли я использовать класс CustomPainter с настраиваемыми виджетами?
Я хочу построить ориентированный граф, как 9X_flutter-provider на картинке ниже, с флаттером. Я не знаю, с 9X_flutter-appbar чего начать. Я безуспешно искал в Интернете. Какие 9X_flutter алгоритмы мне нужны для такого графа? Я 9X_flutter попытался построить этот график с помощью 9X_dart пользовательского класса рисовальщика. Я 9X_flutter-layout не знаю, как использовать пользовательские 9X_flutter виджеты внутри пользовательского класса 9X_dart художника. (например, прямоугольник с изображением 9X_dart человека и текстом рядом). Я мог рисовать 9X_flutter-widget только прямоугольники и линии ... Масштабирование 9X_flutter-sdk и панорамирование Я думал, что могу обойтись 9X_flutter-layout классом GestureDetector. График должен настраиваться 9X_flutter-listview динамически.
- какова ваша логика отношений между узлами?<p><span class="u ...
Ответ #1
Ответ на вопрос: Ориентированный граф флаттера. Могу ли я использовать класс CustomPainter с настраиваемыми виджетами?
Вам нужно разделить задачи.
- Сделайте масштабирование слоя и переместите всю сцену, вы можете использовать Виджет GestureDetector с событиями onScale + виджет Transform.scale, (проверьте пакет zoom_widget).
- Сделайте отдельный элемент перетаскиваемым. Используйте события GestureDetector + onPan.
- Нарисуйте линии соединения между элементами с помощью CustomPainter. Я провел прямые линии, чтобы показать основную логику.
.. добавить дополнительную 9X_flutter-sdk логику, как добавлять новые элементы.
Обновление: codepen interactive version создано 9X_flutter-layout @maks
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Container( alignment: Alignment.center, child: ItemsScene(), decoration: BoxDecoration( border: Border.all( color: Colors.blueAccent, ), ), ), ), ), ); } } class ItemsScene extends StatefulWidget { @override _ItemsSceneState createState() => _ItemsSceneState(); } class _ItemsSceneState extends State { List items = [ ItemModel(offset: Offset(70, 100), text: 'text1'), ItemModel(offset: Offset(200, 100), text: 'text2'), ItemModel(offset: Offset(200, 230), text: 'text3'), ]; Function onDragStart(int index) => (x, y) { setState(() { items[index] = items[index].copyWithNewOffset(Offset(x, y)); }); }; @override Widget build(BuildContext context) { return Stack( children: [ CustomPaint( size: Size(double.infinity, double.infinity), painter: CurvedPainter( offsets: items.map((item) => item.offset).toList(), ), ), ..._buildItems() ], ); } List _buildItems() { final res = []; items.asMap().forEach((ind, item) { res.add(_Item( onDragStart: onDragStart(ind), offset: item.offset, text: item.text, )); }); return res; } } class _Item extends StatelessWidget { _Item({ Key key, this.offset, this.onDragStart, this.text, }); final double size = 100; final Offset offset; final Function onDragStart; final String text; _handleDrag(details) { print(details); var x = details.globalPosition.dx; var y = details.globalPosition.dy; onDragStart(x, y); } @override Widget build(BuildContext context) { return Positioned( left: offset.dx - size / 2, top: offset.dy - size / 2, child: GestureDetector( onPanStart: _handleDrag, onPanUpdate: _handleDrag, child: Container( width: size, height: size, child: Text(text), decoration: BoxDecoration( color: Colors.white, border: Border.all( color: Colors.blueAccent, ), ), ), ), ); } } class CurvedPainter extends CustomPainter { CurvedPainter({this.offsets}); final List offsets; @override void paint(Canvas canvas, Size size) { if (offsets.length > 1) { offsets.asMap().forEach((index, offset) { if (index == 0) return; canvas.drawLine( offsets[index - 1], offsets[index], Paint() ..color = Colors.red ..strokeWidth = 2, ); }); } } @override bool shouldRepaint(CurvedPainter oldDelegate) => true; } class ItemModel { ItemModel({this.offset, this.text}); final Offset offset; final String text; ItemModel copyWithNewOffset(Offset offset) { return ItemModel(offset: offset, text: text); } }
- @Kherel wooooooooow, это очень круто, спасибо, чувак<p ...
-
1
-
1
-
3
-
2
-
5
-
4
-
9
-
5
-
15
-
20
-
5
-
17
-
8
-
14
-
10
-
2
-
2
-
5
-
5
-
3
-
13
-
6
-
3
-
9
-
5
-
5
-
4
-
10
-
2
-
1
-
8
-
5
-
10
-
15
-
2
-
2
-
10
-
2
-
15
-
8
-
1
-
13
-
3
-
5
-
2
-
5
-
2
-
2
-
3
-
2