animated_reorderable_list 1.1.1 copy "animated_reorderable_list: ^1.1.1" to clipboard
animated_reorderable_list: ^1.1.1 copied to clipboard

A Flutter Reorderable Animated List with simple implementation and smooth transition.

example/lib/main.dart

import 'dart:ui';

import 'package:animated_reorderable_list/animated_reorderable_list.dart';
import 'package:example/utils/animation_provider.dart';
import 'package:example/utils/extension.dart';
import 'package:example/utils/item_card.dart';
import 'package:example/utils/item_tile.dart';
import 'package:flutter/material.dart';

import 'model/user_model.dart';

void main() {
  runApp(const MaterialApp(title: 'Motion List Example', home: HomePage()));
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  AnimationType appliedStyle = AnimationType.fadeIn;
  List<User> list =
      List.generate(8, (index) => User(name: "User $index", index: index));
  int addedNumber = 9;
  bool isGrid = true;

  List<AnimationEffect> animations = [];

  void insert() {
    addedNumber += 1;
    setState(() {
      list.insert(1, User(name: "User $addedNumber", index: addedNumber));
    });
  }

  void remove() {
    setState(() {
      if (list.isNotEmpty && list.length > 1) list.removeAt(1);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.teal,
          title: Row(
            children: [
              const SizedBox(
                width: 10,
              ),
              DropdownButtonHideUnderline(
                child: DropdownButton<AnimationType>(
                    iconEnabledColor: Colors.black87,
                    value: appliedStyle,
                    items:
                        AnimationType.values.map((AnimationType animationType) {
                      return DropdownMenuItem<AnimationType>(
                        value: animationType,
                        child: Text(
                          animationType.name.capitalize(),
                          style: const TextStyle(
                              fontSize: 20,
                              color: Colors.black87,
                              fontWeight: FontWeight.w500),
                        ),
                      );
                    }).toList(),
                    onChanged: (AnimationType? animationType) {
                      if (animationType == null) {
                        return;
                      }
                      animations = [];
                      AnimationEffect animation =
                          AnimationProvider.buildAnimation(animationType);
                      animations.add(animation);
                      setState(() {
                        appliedStyle = animationType;
                      });
                    }),
              )
            ],
          ),
          actions: [
            TextButton(
                onPressed: insert,
                child: const Text(
                  'ADD',
                  style: TextStyle(
                      color: Colors.black,
                      fontSize: 20,
                      fontWeight: FontWeight.w500),
                )),
            TextButton(
                onPressed: remove,
                child: const Text(
                  'DEL',
                  style: TextStyle(
                      color: Colors.black,
                      fontSize: 20,
                      fontWeight: FontWeight.w500),
                ))
          ],
        ),
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.teal,
                      ),
                      onPressed: () {
                        setState(() {
                          if (isGrid != false) {
                            isGrid = false;
                          }
                        });
                      },
                      child: const Padding(
                        padding: EdgeInsets.all(8.0),
                        child: Text(
                          'List',
                          style: TextStyle(fontSize: 25),
                        ),
                      )),
                  ElevatedButton(
                    style:
                        ElevatedButton.styleFrom(backgroundColor: Colors.teal),
                    onPressed: () {
                      setState(() {
                        if (isGrid != true) {
                          isGrid = true;
                        }
                      });
                    },
                    child: const Padding(
                      padding: EdgeInsets.all(8.0),
                      child: Text(
                        'Grid',
                        style: TextStyle(fontSize: 25),
                      ),
                    ),
                  ),
                ],
              ),
              const SizedBox(
                height: 16,
              ),
              Expanded(
                child: isGrid
                    ? AnimatedReorderableGridView(
                        items: list,
                        scrollDirection: Axis.vertical,
                        itemBuilder: (BuildContext context, int index) {
                          return ItemCard(
                              key: ValueKey(list[index].index),
                              index: list[index].index);
                        },
                        sliverGridDelegate:
                            SliverReorderableGridDelegateWithFixedCrossAxisCount(
                                crossAxisCount: 4),
                        enterTransition: animations,
                        exitTransition: animations,
                        insertDuration: const Duration(milliseconds: 300),
                        removeDuration: const Duration(milliseconds: 300),
                        onReorder: (int oldIndex, int newIndex) {
                          setState(() {
                            final User user = list.removeAt(oldIndex);
                            list.insert(newIndex, user);
                          });
                        },
                        onReorderEnd: (int index) {
                          print(" End index :  $index");
                        },
                        onReorderStart: (int index) {
                          print(" Start index :  $index");
                        },
                        proxyDecorator: proxyDecorator

                        /*  A custom builder that is for inserting items with animations.

                              insertItemBuilder: (Widget child, Animation<double> animation){
                                 return ScaleTransition(
                                       scale: animation,
                                       child: child,
                                     );
                                    },


                      */
                        /*  A custom builder that is for removing items with animations.

                                  removeItemBuilder: (Widget child, Animation<double> animation){
                                     return ScaleTransition(
                                       scale: animation,
                                       child: child,
                                     );
                                    },
                      */
                        )
                    : AnimatedReorderableListView(
                        items: list,
                        itemBuilder: (BuildContext context, int index) {
                          return ItemTile(
                              key: ValueKey(list[index].index),
                              index: list[index].index);
                        },
                        enterTransition: animations,
                        exitTransition: animations,
                        insertDuration: const Duration(milliseconds: 300),
                        removeDuration: const Duration(milliseconds: 300),
                        onReorder: (int oldIndex, int newIndex) {
                          final User user = list.removeAt(oldIndex);
                          list.insert(newIndex, user);
                          for (int i = 0; i < list.length; i++) {
                            list[i] = list[i].copyWith(index: list[i].index);
                          }
                          setState(() {});
                        },
                        proxyDecorator: proxyDecorator,
                        isSameItem: (a, b) => a.index == b.index

                        /*  A custom builder that is for inserting items with animations.

                              insertItemBuilder: (Widget child, Animation<double> animation){
                                 return ScaleTransition(
                                       scale: animation,
                                       child: child,
                                     );
                                    },


                      */
                        /*  A custom builder that is for removing items with animations.

                                  removeItemBuilder: (Widget child, Animation<double> animation){
                                     return ScaleTransition(
                                       scale: animation,
                                       child: child,
                                     );
                                    },
                      */
                        ),
              ),
            ],
          ),
        ));
  }
}

Widget proxyDecorator(Widget child, int index, Animation<double> animation) {
  return AnimatedBuilder(
    animation: animation,
    builder: (BuildContext context, Widget? child) {
      final double animValue = Curves.easeInOut.transform(animation.value);
      final double elevation = lerpDouble(0, 6, animValue)!;
      return Material(
        elevation: elevation,
        color: Colors.grey,
        shadowColor: Colors.black,
        child: child,
      );
    },
    child: child,
  );
}
93
likes
160
pub points
92%
popularity

Publisher

verified publishercanopas.com

A Flutter Reorderable Animated List with simple implementation and smooth transition.

Repository (GitHub)
View/report issues

Topics

#animated-list #reorderable-list #reorderable-grid #drag-and-drop #list

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on animated_reorderable_list