KosherHotDog
KosherHotDog

Reputation: 93

Flutter: Scroll Down When Draggable Reaches Bottom of Screen

I am attempting to create a Drag and Drop with a GridView.custom. What I desire to have happen, is that when dragging an item, if it reaches the top or bottom of the screen, the gridview scrolls. Is there a build in way to do that, or is there a work around that has to be implemented. I am using the flutter_staggered_grid_view package in this case.

GridView.custom(
      shrinkWrap: true,
      primary: false,
      scrollDirection: Axis.vertical,
      gridDelegate: SliverQuiltedGridDelegate(
        crossAxisCount: 4,
        mainAxisSpacing: 10,
        crossAxisSpacing: 10,
        repeatPattern: QuiltedGridRepeatPattern.inverted,
        pattern: widget.pattern,
      ),
      childrenDelegate: SliverChildBuilderDelegate(
        childCount: widget.children.length,
        (context, index) {
          var selectedWidget = widget.children[index];
          LongPressDraggable<GlobalKey>(
                  data: selectedWidget.key,
                  onDragStarted: _onDragStarted,
                  onDragEnd: _onDragEnd,
                  feedback:
                      SizedBox(width: 100, height: 100, child: selectedWidget),
                  childWhenDragging: Container(),
                  child: DragTarget<GlobalKey>(
                    builder: (context, accepted, rejected) => selectedWidget,
                    onWillAccept: (GlobalKey? accept) {
                      return true;
                    },
                    onAccept: (GlobalKey item) {
                      int startIndex =
                          widget.children.indexWhere((x) => x.key == item);
                      int endIndex = widget.children
                          .indexWhere((x) => x.key == selectedWidget.key);
                      widget.onReorder(startIndex, endIndex);
                    },
                  ),
                )
              },
            ),
           );

Upvotes: 1

Views: 1220

Answers (2)

KosherHotDog
KosherHotDog

Reputation: 93

After some research, I cobbled together a method that created the effect I desired.



return Stack(
      children: [
        renderDraggableGrid(),
        _isDragStart
            ? Align(
                alignment: Alignment.topCenter,
                child: DragTarget(
                  builder: (context, accepted, rejected) => Container(
                    height: 40,
                    width: double.infinity,
                    color: Colors.transparent,
                  ),
                  onWillAccept: (GlobalKey? accept) {
                    _moveUp();
                    return false;
                  },
                ),
              )
            : Container(),
        _isDragStart
            ? Align(
                alignment: Alignment.bottomCenter,
                child: DragTarget(
                  builder: (context, accepted, rejected) => Container(
                    height: 40,
                    width: double.infinity,
                    color: Colors.transparent,
                  ),
                  onWillAccept: (GlobalKey? accept) {
                    _moveDown();
                    return false;
                  },
                ),
              )
            : Container()
      ],
    );

_moveUp() {
    _scrollController!.animateTo(_scrollController!.offset - _gridViewHeight,
        curve: Curves.linear, duration: Duration(milliseconds: 500));
  }

  _moveDown() {
    _scrollController!.animateTo(_scrollController!.offset + _gridViewHeight,
        curve: Curves.linear, duration: Duration(milliseconds: 500));
  }

I also added ClampingScrollPhysics() to avoid over scrolling. Credit to https://github.com/DevOrbiter/drag_and_drop_gridview/ for giving me the base code.

Upvotes: 3

200_OK
200_OK

Reputation: 1

compare Draggable position of the Y axis in GridView area.

Here is the sample; Scroll up if Draggle positions on a top area where is height 20, scroll down if it positions on a bottom area where is height 20.

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  final List<int> droppedIndexList = [];
  late final ScrollController scrollController;

  final GlobalKey gridViewKey = GlobalKey();

  void initState() {
    super.initState();
    scrollController = ScrollController();
    Timer.periodic(const Duration(milliseconds: 100), (_) {
      if(scrollDirection == 0) {
        return;
      } else if(scrollDirection == 1) { // scroll down
        scrollController.animateTo(
          min(scrollController.offset + 20, scrollController.position.maxScrollExtent),
          duration: const Duration(milliseconds: 100),
          curve: Curves.linear,
        );
      } else if(scrollDirection == -1) { // scroll up
        scrollController.animateTo(
          max(scrollController.offset - 20, scrollController.position.minScrollExtent),
          duration: const Duration(milliseconds: 100),
          curve: Curves.linear,
        );
      }
    });
  }

  int scrollDirection = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 100),
          child: SizedBox(
            width: 600,
            child: Column(

              children: [
                SizedBox(
                  height: 200,
                  child: Center(
                    child: Draggable(
                      onDragUpdate: (details) {
                        final s = gridViewKey.currentContext!.size!;
                        final p = (gridViewKey.currentContext!.findRenderObject() as RenderBox).globalToLocal(details.globalPosition);

                        print(p.dy);

                        if(0 <= p.dy && p.dy <= 20) {
                          scrollDirection = -1;
                        } else if(s.height - 20 <= p.dy && p.dy <= s.height) {
                          scrollDirection = 1;
                        } else {
                          scrollDirection = 0;
                        }
                      },
                      data: Colors.black,
                      feedback: Container(
                        width: 100,
                        height: 100,
                        color: Colors.black,
                      ),
                      child: Container(
                        width: 100,
                        height: 100,
                        color: Colors.black,
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: GridView.builder(
                    key: gridViewKey,
                    controller: scrollController,
                    gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: 3,
                    ),
                    itemCount: 300,
                    itemBuilder: (context, index) {
                      return DragTarget<Color>(
                        onAccept: (color) {
                          setState(() {
                            droppedIndexList.add(index);
                          });
                        },
                        builder: (BuildContext context, List<Color?> candidateData, List<dynamic> rejectedData) {

                          return Container(
                            width: 200,
                            height: 200,
                            decoration: BoxDecoration(
                              border: Border.all(
                                color: Colors.black,
                                width: 1,
                              ),
                              color: droppedIndexList.contains(index) ? Colors.black : Colors.transparent,
                            ),
                            child: Center(
                              child: Text(
                                  "$index"
                              ),
                            ),
                          );
                        },
                      );
                    }
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Upvotes: 0

Related Questions