Drag and Reorder animation in mobile app

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
Drag and Reorder animation in mobile app
Medium
from 1 business day to 3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Drag & Reorder Animation Implementation in Mobile Apps

Drag & Reorder lets users drag list items to change their order. User long-presses an item; the list understands intent (item rises and slightly scales); then drag works: other items move aside, showing insertion point.

Technically this is one of the most complex list animations: track drag in real time, compute target insertion position, animate neighboring elements without re-layout the entire list.

iOS: UICollectionView with Reordering

UICollectionView has built-in interactive reordering support via UICollectionViewDragDelegate and UICollectionViewDropDelegate (iOS 11+):

collectionView.dragDelegate = self
collectionView.dropDelegate = self
collectionView.dragInteractionEnabled = true

// UICollectionViewDragDelegate:
func collectionView(_ collectionView: UICollectionView,
                    itemsForBeginning session: UIDragSession,
                    at indexPath: IndexPath) -> [UIDragItem] {
    let item = items[indexPath.item]
    let itemProvider = NSItemProvider(object: item.id as NSString)
    let dragItem = UIDragItem(itemProvider: itemProvider)
    dragItem.localObject = item
    return [dragItem]
}

// UICollectionViewDropDelegate:
func collectionView(_ collectionView: UICollectionView,
                    performDropWith coordinator: UICollectionViewDropCoordinator) {
    guard let destinationIndexPath = coordinator.destinationIndexPath,
          let item = coordinator.items.first,
          let sourceIndexPath = item.sourceIndexPath else { return }

    collectionView.performBatchUpdates {
        items.move(fromOffsets: IndexSet(integer: sourceIndexPath.item),
                   toOffset: destinationIndexPath.item)
        collectionView.moveItem(at: sourceIndexPath, to: destinationIndexPath)
    }
    coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
}

UICollectionView automatically animates neighboring cell movement—this is the most valuable part. No manual offset calculation and animation for each element.

For UITableView, use UITableViewDragDelegate/UITableViewDropDelegate, or the older editingStyle approach:

tableView.isEditing = true
// Delegate method:
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    items.move(fromOffsets: IndexSet(integer: sourceIndexPath.row),
               toOffset: destinationIndexPath.row)
}

In SwiftUI, use List with .onMove:

List {
    ForEach(items) { item in
        ItemRow(item: item)
    }
    .onMove { source, destination in
        items.move(fromOffsets: source, toOffset: destination)
    }
}
.environment(\.editMode, .constant(.active))

.onMove adds standard drag handles. For custom long-press drag without edit mode, use DragGesture with .onChanged and .onEnded, plus manual target index computation. More complex but gives full control over appearance.

Android Compose: LazyColumn + reorderable

Compose has no built-in reorder—use library sh.calvin.reorderable:reorderable:2.4.0:

val listState = rememberLazyListState()
var list by remember { mutableStateOf(items) }
val reorderState = rememberReorderableLazyListState(listState) { from, to ->
    list = list.toMutableList().apply { add(to.index, removeAt(from.index)) }
}

LazyColumn(
    state = listState,
    modifier = Modifier.reorderable(reorderState)
) {
    items(list, key = { it.id }) { item ->
        ReorderableItem(reorderState, key = item.id) { isDragging ->
            val elevation by animateDpAsState(if (isDragging) 8.dp else 0.dp)
            val scale by animateFloatAsState(if (isDragging) 1.05f else 1f)

            Card(
                modifier = Modifier
                    .fillMaxWidth()
                    .scale(scale)
                    .shadow(elevation),
            ) {
                Row {
                    Text(item.title, modifier = Modifier.weight(1f).padding(16.dp))
                    Icon(
                        Icons.Default.DragHandle,
                        contentDescription = null,
                        modifier = Modifier
                            .detectReorderAfterLongPress(reorderState)  // or draggableHandle()
                            .padding(16.dp)
                    )
                }
            }
        }
    }
}

isDragging enables animation of raised element—scale and shadow via animateFloatAsState and animateDpAsState. Other elements animate automatically through LazyColumn's item placement animation.

For custom spacing animation—use Modifier.animateItem() on Compose 1.7+:

items(list, key = { it.id }) { item ->
    ItemRow(item, modifier = Modifier.animateItem())
}

animateItem() automatically animates appearance, disappearance, and offset changes in LazyColumn when the list changes.

Flutter

// pubspec: reorderable_list: ^0.2.2 or built-in ReorderableListView
ReorderableListView.builder(
  itemCount: items.length,
  itemBuilder: (context, index) {
    return ListTile(
      key: ValueKey(items[index].id),
      title: Text(items[index].title),
      trailing: ReorderableDragStartListener(
        index: index,
        child: const Icon(Icons.drag_handle),
      ),
    );
  },
  onReorder: (oldIndex, newIndex) {
    setState(() {
      if (newIndex > oldIndex) newIndex--;
      final item = items.removeAt(oldIndex);
      items.insert(newIndex, item);
    });
  },
  proxyDecorator: (child, index, animation) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        final scale = Tween<double>(begin: 1.0, end: 1.05)
            .evaluate(CurvedAnimation(parent: animation, curve: Curves.easeOut));
        return Transform.scale(scale: scale, child: child);
      },
      child: child,
    );
  },
)

proxyDecorator is a replacement widget for the dragged element. Use it to add scale and shadow effects without changing the original ListTile.

Common Mistakes

Lists without key on elements—on reorder, framework can't match old and new positions; animation jumps or breaks. key: ValueKey(item.id) is mandatory.

Mutating list without notifying framework—in Compose use mutableStateOf with list.toMutableList() before mutation. In Flutter use setState. Without this, UI doesn't update.

Saving new order: after onReorder, immediately send new order to backend or local storage. If user leaves—order is saved. Optimistic update: apply to UI immediately, rollback on network error.

Timeline

Drag & Reorder for simple list via built-in API (UITableView, ReorderableListView): half a day. Custom drag with animated proxy, neighbor spacing, and storage persistence: 1–2 days. Cost is calculated individually.