Как провести / перетащить 2 или более кнопок в сетке кнопок с помощью флаттера - PullRequest
0 голосов
/ 01 июня 2018

Я сделал сетку кнопок, используя флаттер, но теперь я хочу провести двумя или более кнопками одним перетаскиванием, чтобы все кнопки, через которые я перетаскивал, были выделены.

Я проверил несколько вопросов на тот же вопрос, и меня перенаправили на использование детектора жестов, но этого недостаточно.Мне нужны определенные свойства или лучше пример кода, чтобы я мог работать с ним.

пример перетаскиваемого приложения: http://a5.mzstatic.com/us/r30/Purple60/v4/6f/00/35/6f0035d3-1bab-fcbb-cb13-8ab46cf3c44d/screen696x696.jpeg

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Вы можете вручную нажать test RenderBox и извлечь определенный RenderObject по вашему выбору.

Мы могли бы, например, добавить следующий renderobject над нашими кнопками:

class Foo extends SingleChildRenderObjectWidget {
  final int index;

  Foo({Widget child, this.index, Key key}) : super(child: child, key: key);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _Foo()..index = index;
  }

  @override
  void updateRenderObject(BuildContext context, _Foo renderObject) {
    renderObject..index = index;
  }
}

class _Foo extends RenderProxyBox {
  int index;
}

Затем использовать Listener дляизвлечь все _Foo найденные под указателем.

Вот полное приложение, использующее этот принцип:

enter image description here

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Grid(),
    );
  }
}

class Grid extends StatefulWidget {
  @override
  GridState createState() {
    return new GridState();
  }
}

class GridState extends State<Grid> {
  final Set<int> selectedIndexes = Set<int>();
  final key = GlobalKey();
  final Set<_Foo> _trackTaped = Set<_Foo>();

  _detectTapedItem(PointerEvent event) {
    final RenderBox box = key.currentContext.findRenderObject();
    final result = BoxHitTestResult();
    Offset local = box.globalToLocal(event.position);
    if (box.hitTest(result, position: local)) {
      for (final hit in result.path) {
        /// temporary variable so that the [is] allows access of [index]
        final target = hit.target;
        if (target is _Foo && !_trackTaped.contains(target)) {
          _trackTaped.add(target);
          _selectIndex(target.index);
        }
      }
    }
  }

  _selectIndex(int index) {
    setState(() {
      selectedIndexes.add(index);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: _detectTapedItem,
      onPointerMove: _detectTapedItem,
      onPointerUp: _clearSelection,
      child: GridView.builder(
        key: key,
        itemCount: 6,
        physics: NeverScrollableScrollPhysics(),
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          childAspectRatio: 1.0,
          crossAxisSpacing: 5.0,
          mainAxisSpacing: 5.0,
        ),
        itemBuilder: (context, index) {
          return Foo(
            index: index,
            child: Container(
              color: selectedIndexes.contains(index) ? Colors.red : Colors.blue,
            ),
          );
        },
      ),
    );
  }

  void _clearSelection(PointerUpEvent event) {
    _trackTaped.clear();
    setState(() {
      selectedIndexes.clear();
    });
  }
}

class Foo extends SingleChildRenderObjectWidget {
  final int index;

  Foo({Widget child, this.index, Key key}) : super(child: child, key: key);

  @override
  _Foo createRenderObject(BuildContext context) {
    return _Foo()..index = index;
  }

  @override
  void updateRenderObject(BuildContext context, _Foo renderObject) {
    renderObject..index = index;
  }
}

class _Foo extends RenderProxyBox {
  int index;
}
0 голосов
/ 02 октября 2018

Мне вообще не нравится этот код, но, похоже, он работает

import 'package:flutter/material.dart';

class TestScaffold extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TestScaffoldState();
}

List<_SquareButton> _selectedList = [];

class _TestScaffoldState extends State<TestScaffold> {

  List<_SquareButton> buttons = [
    _SquareButton('1'),
    _SquareButton('2'),
    _SquareButton('3'),
    _SquareButton('4'),
    _SquareButton('5'),
    _SquareButton('6'),
    _SquareButton('7'),
    _SquareButton('8'),
    _SquareButton('9'),
    _SquareButton('10'),
    _SquareButton('11'),
    _SquareButton('12'),
    _SquareButton('13'),
    _SquareButton('14'),
    _SquareButton('15'),
    _SquareButton('16'),
  ];
  Map<Rect, _SquareButton> positions = {};

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Test'),),
      body: GestureDetector(
        onPanDown: (details) {
          checkGesture(details.globalPosition);
        },
        onPanUpdate: (details) {
          checkGesture(details.globalPosition);
        },
        child: GridView.count(crossAxisCount: 4,
        physics: NeverScrollableScrollPhysics(),
        children: buttons,),)
    );
  }

  initPositions() {
    if (positions.isNotEmpty) return;
    buttons.forEach((btn) {
      RenderBox box = btn.bKey.currentContext.findRenderObject();
      Offset start = box.localToGlobal(Offset.zero);
      Rect rect = Rect.fromLTWH(start.dx, start.dy, box.size.width, box.size.height);
      positions.addAll({rect: btn});
    });
  }

  checkGesture(Offset position) {
    initPositions();
    positions.forEach((rect, btn) {
      if (rect.contains(position)) {
        if (!_selectedList.contains(btn)) {
            _selectedList.add(btn);
        btn.state.setState((){});
        }
      }
    });
  }
}

class _SquareButton extends StatefulWidget {
  _SquareButton(this.title);
  final String title;
  final GlobalKey bKey = GlobalKey();
  State state;
  @override
  State<StatefulWidget> createState() {
    state = _SquareButtonState();
    return state;
  }
}

class _SquareButtonState extends State<_SquareButton> {
  @override
  Widget build(BuildContext context) {
    return Padding(key: widget.bKey, padding: EdgeInsets.all(4.0), child: Container(
        color: _selectedList.contains(widget) ? Colors.tealAccent : Colors.teal,
        child: Text(widget.title),
        alignment: Alignment.center,
      ),);
  }
}

Есть момент.Если вы включите прокрутку - GestureDetector не всегда работает с вертикальными движениями

...