Ориентированный граф флаттера. Могу ли я использовать класс 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 динамически.

9X_Ориентированный граф флаттера. Могу ли я использовать класс CustomPainter с настраиваемыми виджетами?_dart

12
1

  • какова ваша логика отношений между узлами?<p><span class="u ...
1
Общее количество ответов: 1

Ответ #1

Ответ на вопрос: Ориентированный граф флаттера. Могу ли я использовать класс CustomPainter с настраиваемыми виджетами?

Вам нужно разделить задачи.

  1. Сделайте масштабирование слоя и переместите всю сцену, вы можете использовать Виджет GestureDetector с событиями onScale + виджет Transform.scale, (проверьте пакет zoom_widget).
  2. Сделайте отдельный элемент перетаскиваемым. Используйте события GestureDetector + onPan.
  3. Нарисуйте линии соединения между элементами с помощью CustomPainter. Я провел прямые линии, чтобы показать основную логику.

.. добавить дополнительную 9X_flutter-sdk логику, как добавлять новые элементы.

Обновление: codepen interactive version создано 9X_flutter-layout @maks

9X_Ориентированный граф флаттера. Могу ли я использовать класс CustomPainter с настраиваемыми виджетами?_flutter-listview

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);
  }
}

25
2

  • @Kherel wooooooooow, это очень круто, спасибо, чувак<p ...