Skip to content

Commit

Permalink
Allow to prevent reordering (#106)
Browse files Browse the repository at this point in the history
* Add lockedItem

* Add lockedItem

* Update documentation

* Fix dragged issue for different instances

* Update documentation

* Minor change

* Minor change

* Update README.md

* Update README.md
  • Loading branch information
cp-sneha-s authored Dec 31, 2024
1 parent dfab4d0 commit 5c71ba0
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 59 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.1.5

### Improvements
- Add `lockedItems` to make items locked and non-draggable.
- Fix issue with `nonDraggableItems` for different instances of the list.

## 1.1.4

### Improvements
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ drag-and-drop functionality in Flutter.
- [x] Pre-built animation like fade,scale, slide, flip etc for Flutter list.
- [x] Provides support for both lists and grids
- [x] Supports large lists and creates items on demand as they come into the viewport.
- [x] Enable/disable drag and drop functionality.
- [x] Control reordering of item / locked an item.

## Demo

### Reorderable List

| ![Image 1](https://github.com/user-attachments/assets/f68812ad-5106-4154-9e9a-7a09e7d23015?raw=true) | ![Image 2](https://github.com/user-attachments/assets/e954b616-1820-4004-9c0e-23b002a6b36f?raw=true) | ![Image 3](https://github.com/user-attachments/assets/9b5c695b-7874-4ea3-86b0-1b00b2bf8d65?raw=true) |
| ![Image 1](https://github.com/user-attachments/assets/7a31a2c0-f49b-4280-ac8c-b4bc35e5a3db?raw=true) | ![Image 2](https://github.com/user-attachments/assets/3a7d34ec-eb2f-491c-af8f-43b569607d91?raw=true) | ![Image 3](https://github.com/user-attachments/assets/68c1b0f7-481e-4e6e-b995-e1b754354d1f?raw=true) |
| :---: | :---: | :---: |
| ReorderableGridView | ReorderableListView | Swap Animation |

Expand Down
47 changes: 35 additions & 12 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ class _HomePageState extends State<HomePage> {
bool isGrid = true;

List<User> nonDraggableItems = [];
List<User> lockedItems = [];

List<AnimationEffect> animations = [];

@override
void initState() {
super.initState();
list = List.generate(8, (index) => User(name: "User $index", id: index));
nonDraggableItems = list.where((user) => user.id == 0).toList();
nonDraggableItems = list.where((user) => user.id == 1).toList();
lockedItems = list.where((user) => user.id == 0).toList();
}

void insert() {
Expand All @@ -63,9 +65,9 @@ class _HomePageState extends State<HomePage> {
actions: [
IconButton(
onPressed: () {
final child1 = list[1];
final child1 = list[2];
final child2 = list[7];
list[1] = child2;
list[2] = child2;
list[7] = child1;
setState(() {});
},
Expand Down Expand Up @@ -103,6 +105,7 @@ class _HomePageState extends State<HomePage> {
key: ValueKey(user.id),
id: user.id,
dragEnabled: !nonDraggableItems.contains(user),
isLocked: lockedItems.contains(user),
);
},
sliverGridDelegate:
Expand All @@ -113,12 +116,24 @@ class _HomePageState extends State<HomePage> {
insertDuration: const Duration(milliseconds: 300),
removeDuration: const Duration(milliseconds: 300),
onReorder: (int oldIndex, int newIndex) {
final Map<User, int> lockedItemPositions = {
for (int i = 0; i < list.length; i++)
if (lockedItems.contains(list[i])) list[i]: i
};
setState(() {
final User user = list.removeAt(oldIndex);
list.insert(newIndex, user);
for (var entry in lockedItemPositions.entries) {
list.remove(entry.key);
list.insert(
entry.value,
entry
.key); // Insert based on original position (id in this case)
}
});
},
nonDraggableItems: nonDraggableItems,
lockedItems: lockedItems,
dragStartDelay: const Duration(milliseconds: 300),
onReorderEnd: (int index) {
// print(" End index : $index");
Expand Down Expand Up @@ -158,24 +173,32 @@ class _HomePageState extends State<HomePage> {
key: ValueKey(user.id),
id: user.id,
dragEnabled: !nonDraggableItems.contains(user),
isLocked: lockedItems.contains(user),
);
},
enterTransition: animations,
exitTransition: animations,
insertDuration: const Duration(milliseconds: 300),
removeDuration: const Duration(milliseconds: 300),
nonDraggableItems: nonDraggableItems,
lockedItems: lockedItems,
dragStartDelay: const Duration(milliseconds: 300),
onReorder: (int oldIndex, int newIndex) {
final User user = list.removeAt(oldIndex);
list.insert(newIndex, user);

// Add isSameItem to compare objects when creating new

for (int i = 0; i < list.length; i++) {
list[i] = list[i].copyWith(id: list[i].id);
}
setState(() {});
final Map<User, int> lockedItemPositions = {
for (int i = 0; i < list.length; i++)
if (lockedItems.contains(list[i])) list[i]: i
};
setState(() {
final User user = list.removeAt(oldIndex);
list.insert(newIndex, user);
for (var entry in lockedItemPositions.entries) {
list.remove(entry.key);
list.insert(
entry.value,
entry
.key); // Insert based on original position (id in this case)
}
});
},
proxyDecorator: proxyDecorator,
isSameItem: (a, b) => a.id == b.id
Expand Down
18 changes: 0 additions & 18 deletions example/lib/model/user_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,4 @@ class User {
final int id;

User({required this.name, required this.id});

User copyWith({
String? name,
int? id,
}) {
return User(
name: name ?? this.name,
id: id ?? this.id,
);
}

@override
bool operator ==(Object other) {
return other is User && other.name == name && other.id == id;
}

@override
int get hashCode => Object.hash(name, id);
}
14 changes: 10 additions & 4 deletions example/lib/utils/item_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@ import 'package:flutter/material.dart';
class ItemCard extends StatelessWidget {
final int id;
final bool dragEnabled;
final bool isLocked;

const ItemCard({super.key, required this.id, this.dragEnabled = true});
const ItemCard(
{super.key,
required this.id,
this.dragEnabled = true,
this.isLocked = false});

@override
Widget build(BuildContext context) {
return SizedBox(
height: 150.0,
width: 150,
child: Card(
color: !dragEnabled
color: isLocked
? containerLowColor
: Colors.primaries[id % Colors.primaries.length],
: Colors.primaries[id % Colors.primaries.length]
.withValues(alpha: dragEnabled ? 1 : 0.3),
child: Center(
child: dragEnabled
child: !isLocked
? Text((id).toString(),
style: const TextStyle(fontSize: 22, color: Colors.black))
: const Icon(Icons.lock, color: Colors.white),
Expand Down
14 changes: 8 additions & 6 deletions example/lib/utils/item_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import '../theme/colors.dart';
class ItemTile extends StatelessWidget {
final int id;
final bool dragEnabled;
final bool isLocked;

const ItemTile({
super.key,
required this.id,
this.dragEnabled = true,
this.isLocked = false,
});

@override
Expand All @@ -18,13 +20,13 @@ class ItemTile extends StatelessWidget {
width: double.infinity,
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: !dragEnabled
? containerLowColor
: Colors.primaries[id % Colors.primaries.length],
),
borderRadius: BorderRadius.circular(10),
color: isLocked
? containerLowColor
: Colors.primaries[id % Colors.primaries.length]
.withValues(alpha: dragEnabled ? 1 : 0.3)),
child: Center(
child: dragEnabled
child: !isLocked
? Text(
'Item $id',
style: const TextStyle(fontSize: 25),
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ packages:
path: ".."
relative: true
source: path
version: "1.1.3"
version: "1.1.5"
args:
dependency: transitive
description:
Expand Down
5 changes: 5 additions & 0 deletions lib/src/animated_reorderable_gridview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ class AnimatedReorderableGridView<E extends Object> extends StatefulWidget {
/// The item can't be draggable, but it can be reordered.
final List<E> nonDraggableItems;

/// A list of items that are locked and can't be reordered.
final List<E> lockedItems;

/// Whether to enable swap animation when changing the order of the items.
///
/// Defaults to true.
Expand Down Expand Up @@ -377,6 +380,7 @@ class AnimatedReorderableGridView<E extends Object> extends StatefulWidget {
required this.isSameItem,
this.dragStartDelay = const Duration(milliseconds: 500),
this.nonDraggableItems = const [],
this.lockedItems = const [],
this.enableSwap = true})
: super(key: key);

Expand Down Expand Up @@ -467,6 +471,7 @@ class AnimatedReorderableGridViewState<E extends Object>
isSameItem: widget.isSameItem,
dragStartDelay: widget.dragStartDelay,
nonDraggableItems: widget.nonDraggableItems,
lockedItems: widget.lockedItems,
enableSwap: widget.enableSwap,
),
),
Expand Down
7 changes: 7 additions & 0 deletions lib/src/animated_reorderable_listview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ class AnimatedReorderableListView<E extends Object> extends StatefulWidget {
/// The item can't be draggable, but it can be reordered.
final List<E> nonDraggableItems;

/// A list of items that are locked and can't be reordered and dragged.
///
/// Add elements in this list if all the elements in the list has same height. If the elements has different height, the reordered items will not be placed in the correct position.
final List<E> lockedItems;

/// Whether to enable swap animation when changing the order of the items.
///
/// Defaults to true.
Expand Down Expand Up @@ -393,6 +398,7 @@ class AnimatedReorderableListView<E extends Object> extends StatefulWidget {
required this.isSameItem,
this.dragStartDelay = const Duration(milliseconds: 500),
this.nonDraggableItems = const [],
this.lockedItems = const [],
this.enableSwap = true,
}) : super(key: key);

Expand Down Expand Up @@ -483,6 +489,7 @@ class AnimatedReorderableListViewState<E extends Object>
isSameItem: widget.isSameItem,
dragStartDelay: widget.dragStartDelay,
nonDraggableItems: widget.nonDraggableItems,
lockedItems: widget.lockedItems,
enableSwap: widget.enableSwap,
),
),
Expand Down
Loading

0 comments on commit 5c71ba0

Please sign in to comment.