DavideBelsole / great_list_view

pub.dev library for flutter
MIT License
39 stars 21 forks source link

How to use proxyDecorator like in flutter's ReorderableListView #27

Closed AhsanSarwar45 closed 1 year ago

AhsanSarwar45 commented 1 year ago

Flutter's ReorderableListView allows us to specify the proxyDecorator property, which allows us to style the item when it is being reordered. We can specify things like elevation, borderRadius, shadowColor etc. My list item component has rounded border and I want to the shadow to have rounded borders as well when we start dragging the item. Does this package provide any such option?

DavideBelsole commented 1 year ago

Sure you can! Here's an example:

import 'package:flutter/material.dart';
import 'package:great_list_view/great_list_view.dart';

void main() {
  Executor().warmUp();
  runApp(App());
}

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Test App',
        home: SafeArea(
            child: Scaffold(
          body: Body(key: gkey),
        )));
  }
}

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

  @override
  _BodyState createState() => _BodyState();
}

class _BodyState extends State<Body> {
  late List<Item> currentList;

  @override
  void initState() {
    super.initState();
    currentList = listA;
  }

  void swapList() {
    setState(() {
      if (currentList == listA) {
        currentList = listB;
      } else {
        currentList = listA;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scrollbar(
      child: AutomaticAnimatedListView<Item>(
        addAnimatedElevation: 0.0, // we want to use a custom Material
        list: currentList,
        comparator: AnimatedListDiffListComparator<Item>(
            sameItem: (a, b) => a.id == b.id,
            sameContent: (a, b) => a.color == b.color),
        itemBuilder: (context, item, data) => item.build(context, data),
        listController: controller,
        reorderModel: AutomaticAnimatedListReorderModel(currentList),
        detectMoves: true,
      ),
    );
  }
}

class Item {
  final int id;
  final Color color;
  final double? fixedHeight;
  const Item(this.id, [this.color = Colors.blue, this.fixedHeight]);

  Widget build(BuildContext context, AnimatedWidgetBuilderData data) {
    return data.measuring
        ? Container(
            margin: EdgeInsets.all(5),
            padding: EdgeInsets.all(15),
            child: const Center(
              child: Text(
                'Item 999',
                style: TextStyle(fontSize: 16),
              ),
            ),
          )
        : Material(
            elevation: data.dragging ? 10 : 0,
            shadowColor: Colors.red,
            borderRadius: BorderRadius.all(Radius.circular(20)),
            child: GestureDetector(
              onTap: () => gkey.currentState?.swapList(),
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 500),
                margin: EdgeInsets.all(5),
                padding: EdgeInsets.all(15),
                decoration: BoxDecoration(
                  color: color,
                  border: Border.all(color: Colors.black12, width: 0),
                  borderRadius: BorderRadius.all(Radius.circular(20)),
                ),
                child: Center(
                  child: Text(
                    'Item $id',
                    style: TextStyle(fontSize: 16),
                  ),
                ),
              ),
            ),
          );
  }
}

List<Item> listA = [
  Item(1, Colors.orange),
  Item(2),
  Item(3),
  Item(4, Colors.cyan),
  Item(5),
  Item(8, Colors.green)
];
List<Item> listB = [
  Item(4, Colors.cyan),
  Item(2),
  Item(6),
  Item(5, Colors.pink, 100),
  Item(7),
  Item(8, Colors.yellowAccent),
];

final controller = AnimatedListController();
final gkey = GlobalKey<_BodyState>();