admin管理员组

文章数量:1318564

I am trying to achieve same movement as the mac doc

here is the link

But here is my project, using ReorderableListView in flutter, i am not able to move the items vertically, i am only able to move items horizontally freely

i want if i select the items, i could drags and hover the item anywhere in the screen like macos doc, not just horizontal here is the link - what i am able to achieve -(here

here is my build function

@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Column(
        children: [
          SizedBox(
            height: MediaQuery.sizeOf(context).height * .12,
          ),
          const Center(
            child: Text(
              'Mac Dock',
              style: TextStyle(color: Colors.white, fontSize: 30),
            ),
          ),
          SizedBox(
            height: MediaQuery.sizeOf(context).height * .20,
          ),
          Center(
            child: Container(
              height: 70,
              decoration: const BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(10)),
                gradient: LinearGradient(colors: [
                  Colors.blueAccent,
                  Colors.greenAccent,
                ]),
              ),

              padding: EdgeInsets.all(controller.verticlItemsPadding),
              // 1.
              child: ReorderableListView(
                onReorderStart: (index) {
                  setState(() {
                    controller.hoveredIndex = null;
                  });
                },
                onReorderEnd: (index) {
                  setState(() {
                    controller.hoveredIndex = null;
                  });
                },
                proxyDecorator: proxyDecorator,
                shrinkWrap: true,
                onReorder: _update,
                
                buildDefaultDragHandles: false,
                scrollDirection: Axis.horizontal,
                children: List.generate(
                  iconslist.length,
                  (index) {
                    // 2.
                    return ReorderableDragStartListener(
                      index: index,
                      key: ValueKey(iconslist[index]),
                      child: MouseRegion(
                        cursor: SystemMouseCursors.click,
                        onEnter: ((event) {
                          setState(() {
                            controller.hoveredIndex = index.toDouble();
                          });
                        }),

                        onExit: (event) {
                          setState(() {
                            controller.hoveredIndex = null;
                          });
                        },
                        // 3.
                        child: AnimatedContainer(
                          
                          color: Colors.red,
                          duration: const Duration(
                            milliseconds: 150,
                          ),
                          transform: Matrix4.identity()
                            ..translate(
                              0.0,
                              controller.getTranslationY(index),
                              0.0,
                            ),
                          height:
                              controller.getScaledSize(index), //baseItemHeight,
                          width: controller
                              .getScaledSize(index), // baseItemHeight,

                          alignment: AlignmentDirectional.center,
                          margin: const EdgeInsets.symmetric(
                              // horizontal: 2,
                              ),
                          // 4.
                          child: iconslist[index],
                        ),
                      ),
                    );
                  },
                ).toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }

i tried to use reorderable listview for the problem, and it restrict my view to horizontal movement

I am trying to achieve same movement as the mac doc

here is the link

But here is my project, using ReorderableListView in flutter, i am not able to move the items vertically, i am only able to move items horizontally freely

i want if i select the items, i could drags and hover the item anywhere in the screen like macos doc, not just horizontal here is the link - what i am able to achieve -(here

here is my build function

@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Column(
        children: [
          SizedBox(
            height: MediaQuery.sizeOf(context).height * .12,
          ),
          const Center(
            child: Text(
              'Mac Dock',
              style: TextStyle(color: Colors.white, fontSize: 30),
            ),
          ),
          SizedBox(
            height: MediaQuery.sizeOf(context).height * .20,
          ),
          Center(
            child: Container(
              height: 70,
              decoration: const BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(10)),
                gradient: LinearGradient(colors: [
                  Colors.blueAccent,
                  Colors.greenAccent,
                ]),
              ),

              padding: EdgeInsets.all(controller.verticlItemsPadding),
              // 1.
              child: ReorderableListView(
                onReorderStart: (index) {
                  setState(() {
                    controller.hoveredIndex = null;
                  });
                },
                onReorderEnd: (index) {
                  setState(() {
                    controller.hoveredIndex = null;
                  });
                },
                proxyDecorator: proxyDecorator,
                shrinkWrap: true,
                onReorder: _update,
                
                buildDefaultDragHandles: false,
                scrollDirection: Axis.horizontal,
                children: List.generate(
                  iconslist.length,
                  (index) {
                    // 2.
                    return ReorderableDragStartListener(
                      index: index,
                      key: ValueKey(iconslist[index]),
                      child: MouseRegion(
                        cursor: SystemMouseCursors.click,
                        onEnter: ((event) {
                          setState(() {
                            controller.hoveredIndex = index.toDouble();
                          });
                        }),

                        onExit: (event) {
                          setState(() {
                            controller.hoveredIndex = null;
                          });
                        },
                        // 3.
                        child: AnimatedContainer(
                          
                          color: Colors.red,
                          duration: const Duration(
                            milliseconds: 150,
                          ),
                          transform: Matrix4.identity()
                            ..translate(
                              0.0,
                              controller.getTranslationY(index),
                              0.0,
                            ),
                          height:
                              controller.getScaledSize(index), //baseItemHeight,
                          width: controller
                              .getScaledSize(index), // baseItemHeight,

                          alignment: AlignmentDirectional.center,
                          margin: const EdgeInsets.symmetric(
                              // horizontal: 2,
                              ),
                          // 4.
                          child: iconslist[index],
                        ),
                      ),
                    );
                  },
                ).toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }

i tried to use reorderable listview for the problem, and it restrict my view to horizontal movement

Share Improve this question edited Jan 21 at 10:39 DarkBee 15.6k8 gold badges72 silver badges117 bronze badges asked Jan 21 at 10:34 Varun GoelVarun Goel 111 bronze badge 4
  • What's your controller? – Ravindra S. Patil Commented Jan 21 at 11:00
  • Please refer to this answer: ReorderableListview Implementation – aolsan Commented Jan 21 at 12:16
  • I want to freely able to drag the selected icon anywhere in the screen, but reorderable listview constrains me on one axis only (here horizonal axis). – Varun Goel Commented Jan 21 at 14:38
  • the controller is a getx controller, used to handle the animation stuff, like magnifying the icon on hover of the mouse – Varun Goel Commented Jan 21 at 14:39
Add a comment  | 

1 Answer 1

Reset to default 0

Track your desired vertical drag offset as a state variable, which is initially zero:

double _verticalDragOffset = 0;

Wrap each of your reorderable Widgets in a Listener that detects drags and updates your vertical drag offset accordingly:

Listener(
  // Make sure this doesn't block hit testing on the child.
  behavior: HitTestBehavior.translucent,
  onPointerMove: (event) {
    setState(() => _verticalDragOffset += event.delta.dy);
  },
  child: /* your child here */,
)

Use the proxyDecorator callback of ReorderableListView to reposition dragged items to the correct vertical offset using Transform.translate. The vertical offset needs to be interpolated using the proxy animation so that the dragged item animates to its final position when released.

Widget _proxyDecorator(child, index, Animation<double> animation) {
  return AnimatedBuilder(
    animation: animation,
    builder: (_, __) {
      // ReorderableListView uses Curves.easeOut internally, so you must use
      // Curves.easeOut here to ensure the vertical and horizontal positions
      // animate at the same rate.
      final double animValue = Curves.easeOut.transform(animation.value);
      final verticalOffset = animation.isForwardOrCompleted
          ? _verticalDragOffset
          : lerpDouble(0, _verticalDragOffset, animValue)!;

      return Transform.translate(
        offset: Offset(0, verticalOffset),
        child: child,
      );
    },
  );
}

Finally, the vertical drag offset needs to be reset whenever a new drag is started. You can do this in the onReorderStart callback of ReorderableListView. Also, pass our proxyDecorator implementation.

ReorderableListView(
  onReorderStart: (_) => setState(() => _verticalDragOffset = 0),
  proxyDecorator: _proxyDecorator,
  ...
)

Here's a complete example that puts this all together and uses the design in your post.

Result

Implementation

import 'dart:ui';

import 'package:flutter/material.dart';

void main() => runApp(const ReorderableApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: Scaffold(
        appBar: AppBar(title: const Text('ReorderableListView Sample')),
        body: const ReorderableExample(),
      ),
    );
  }
}

class ReorderableExample extends StatefulWidget {
  const ReorderableExample({super.key});

  @override
  State<ReorderableExample> createState() => _ReorderableExampleState();
}

class _ReorderableExampleState extends State<ReorderableExample> {
  final _items = [
    (Icons.person, Colors.amber),
    (Icons.camera, Colors.orange),
    (Icons.phone, Colors.blue),
    (Icons.message, Colors.green),
  ];

  double _verticalDragOffset = 0;

  Widget _proxyDecorator(child, index, Animation<double> animation) {
    return AnimatedBuilder(
      animation: animation,
      builder: (_, __) {
        // ReorderableListView uses Curves.easeOut internally, so you must use
        // Curves.easeOut here to ensure the vertical and horizontal positions
        // animate at the same rate.
        final double animValue = Curves.easeOut.transform(animation.value);
        final verticalOffset = animation.isForwardOrCompleted
            ? _verticalDragOffset
            : lerpDouble(0, _verticalDragOffset, animValue)!;

        return Transform.translate(
          offset: Offset(0, verticalOffset),
          child: child,
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        height: 75,
        decoration: const BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(15)),
          gradient: LinearGradient(colors: [
            Colors.blueAccent,
            Colors.greenAccent,
          ]),
        ),
        padding: const EdgeInsets.all(15),
        child: ReorderableListView(
          shrinkWrap: true,
          buildDefaultDragHandles: false,
          scrollDirection: Axis.horizontal,
          onReorderStart: (_) => setState(() => _verticalDragOffset = 0),
          proxyDecorator: _proxyDecorator,
          onReorder: (oldIndex, newIndex) => setState(() {
            if (oldIndex < newIndex) {
              newIndex -= 1;
            }
            final item = _items.removeAt(oldIndex);
            _items.insert(newIndex, item);
          }),
          children: [
            for (int index = 0; index < _items.length; index++)
              ReorderableDragStartListener(
                key: ObjectKey(_items[index].$1),
                index: index,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 5),
                  child: Listener(
                    behavior: HitTestBehavior.translucent,
                    onPointerMove: (event) {
                      setState(() => _verticalDragOffset += event.delta.dy);
                    },
                    child: AspectRatio(
                      aspectRatio: 1,
                      child: Container(
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(7),
                          color: _items[index].$2,
                        ),
                        child: Icon(_items[index].$1, color: Colors.white),
                      ),
                    ),
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

本文标签: flutterHow to move items freely in ReorderableListViewStack Overflow