Today we are sharing the ReaorderableListView Widget
Nuclea.solutions - MEXICO
Hi everyone I hope you like this custom widget. At nuclea.solutions we create widgets constantly, and we are so thrill to share some of them with all of you.
Here is a link of a working example:
This is a video of a tutorial of how this works (Spanish):
NOTE: For this code to work you will need a Local State variable of type List of Strings called "listaResultado". In this variable the new list will be saved in case there is a new order.
The initial list has to be asigned to the parameter "list".
If you have any question, request or comment don´t be afraid to ask or share your insights.
Here is the widget Settings:
Here is the code exactly how it is on the FlutterFlow code editor
// Automatic FlutterFlow imports
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'dart:ui';
class ReorderList extends StatefulWidget {
const ReorderList({
Key? key,
this.width,
this.height,
required this.list,
required this.animationColor,
required this.boxFillColor,
required this.boxBorderColor,
required this.icon,
required this.showDragIcon,
}) : super(key: key);
final double? width;
final double? height;
final List<String> list;
final Color animationColor;
final Color boxFillColor;
final Color boxBorderColor;
final Widget icon;
final bool showDragIcon;
@override
_ReorderListState createState() => _ReorderListState();
}
class _ReorderListState extends State<ReorderList> {
@override
Widget build(BuildContext context) {
//Se crea una lista temporal con los elementos del parametro list
var listTemp = widget.list;
//Si listaResultado es 0 significa que es la primera carga del widget
//si este es el caso se asigna a la listaTemp los valores iniciales
//de lo contrario se asigna a listaTemp el estado actual de la lista
if (FFAppState().listaResultado.length == 0) {
listTemp = widget.list;
} else {
listTemp = FFAppState().listaResultado;
}
//Se crea un Decorador para añadir el Shadow al mover un elemento
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)!;
//Se asigna el color del Shadow de la animación
final Color draggableItemColor = widget.animationColor;
//Se regresa el Material del Shadow de la animacion
return Material(
elevation: elevation,
//Se define como transparente para que solo se muestre la Sombra
color: Color(0xFFFFFF),
//Se asigna el color de sombra
shadowColor: draggableItemColor,
child: child,
);
},
child: child,
);
}
//Se regresa la Lista con sus elementos.
return ReorderableListView(
buildDefaultDragHandles: false,
proxyDecorator: proxyDecorator,
scrollDirection: Axis.vertical,
padding: const EdgeInsets.symmetric(horizontal: 40),
//Se crean los hijos de la lista. Uno por cada elemento de listTemp.
children: <Widget>[
for (int index = 0; index < listTemp.length; index += 1)
Padding(
key: Key('$index'),
padding: EdgeInsetsDirectional.fromSTEB(6, 6, 6, 6),
child: Container(
width: double.infinity,
height: 60,
//Se asignan los colores de fondo y del borde.
decoration: BoxDecoration(
color: widget.boxFillColor,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: widget.boxBorderColor,
),
),
//
//
/*
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
//Se asigna el texto a cada elemento
'${FFAppState().listaResultado[index]}',
style: FlutterFlowTheme.of(context).bodyText1),
),
*/
//
child: Stack(
alignment: AlignmentDirectional(0, 0),
children: [
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(36, 12, 36, 12),
child: Text(
'${FFAppState().listaResultado[index]}',
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context).bodyMedium,
),
),
),
Visibility(
visible: (widget.showDragIcon),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: ReorderableDragStartListener(
index: index,
child: Container(
width: MediaQuery.of(context).size.width * 0.95,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 0, 12, 0),
child: widget.icon),
]),
),
),
),
),
],
),
//
)),
],
//Se cambian los indices de la lista al reordenar
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final String item = listTemp.removeAt(oldIndex);
listTemp.insert(newIndex, item);
FFAppState().update(() {
FFAppState().listaResultado = listTemp;
//FFAppState().lista = listTemp;
});
/*FFAppState().update(() {
FFAppState().listaResultado = FFAppState().listaResultado;
});*/
});
},
);
}
}