Flutter – Deslizante

Slidable en una aplicación se puede usar para realizar una amplia gama de tareas con solo deslizar el dedo hacia la derecha o hacia la izquierda en el mosaico. No solo hace que la interfaz de usuario sea muy fácil de usar, sino que también ahorra mucho tiempo al realizar tareas triviales que, si se realizan de otras maneras, pueden ser frenéticas y redundantes para el diseño. En este artículo, analizaremos el proceso de diseño de un deslizable para su aplicación.

Aquí construiremos una aplicación simple con mosaicos que cuando se deslizan de izquierda a derecha archivan el mosaico y cuando se deslizan de derecha a izquierda eliminan el mosaico. Para hacerlo, siga los siguientes pasos:

  • Agregue la dependencia flutter_slidable al archivo pubspec.yaml .
  • Importe la dependencia al archivo main.dart
  • Cree un StatelessWidget para darle una estructura a la aplicación
  • Use un StateFulWidget para agregar una página de inicio a la aplicación
  • Use SlidableCntroller para configurar las acciones de deslizamiento
  • Use FloatingActionButton para asignar acciones a los botones generados mientras desliza el mosaico
  • Use WidgetBuilder para construir los mosaicos en la página de inicio

Vamos a discutir los pasos en detalle.

Adición de dependencia:

Puedes importar la dependencia flutter_slidable en el archivo pubspec.yaml como se muestra a continuación:

dependency

Dependencia de importación:

Para importar la dependencia en el archivo main.dart, use lo siguiente:

import 'package:flutter_slidable/flutter_slidable.dart';

Creación de la estructura de la aplicación:

Use un StatelessWidget para darle a la aplicación una estructura simple como se muestra a continuación:

Dart

class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Slidable ',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'GeeksForGeeks'),
    );
  }
}

Crear página de inicio:

Use un StatefulWidget para configurar la página de inicio de la aplicación que en el futuro contendrá los mosaicos que se pueden deslizar en cualquier dirección para realizar las tareas que se les asignan, como se muestra a continuación:

Dart

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  
  final String title;
  
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
  
class _MyHomePageState extends State<MyHomePage> {
  SlidableController slidableController;
  final List<_HomeItem> items = List.generate(
    20,
        (i) => _HomeItem(
      i,
      'Slide Bar $i',
      _getSubtitle(i),
      _getAvatarColor(i),
    ),
  );

Diseño de las diapositivas:

Use SlidableController para configurar las diapositivas para la aplicación. Se puede hacer mediante el uso de Slidable Constructor o Slidable.builder Constructor . La aplicación que estamos construyendo tiene 4 componentes esenciales:

  1. Acciones de diapositivas
  2. Un widget de panel de acción de diapositivas
  3. Una relación de extensión entre una extensión de acción deslizante y la extensión del elemento.
  4. Un niño

Para diseñar el deslizable usa lo siguiente:

Dart

Slidable(
  actionPane: SlidableDrawerActionPane(),
  actionExtentRatio: 0.25,
  child: Container(
    color: Colors.white,
    child: ListTile(
      leading: CircleAvatar(
        backgroundColor: Colors.indigoAccent,
        child: Text('$3'),
        foregroundColor: Colors.white,
      ),
      title: Text('Tile $3'),
      subtitle: Text('SlidableDrawerDelegate'),
    ),
  ),
  actions: <Widget>[
    IconSlideAction(
      caption: 'Archive',
      color: Colors.blue,
      icon: Icons.archive,
      onTap: () => _showSnackBar('Archive'),
    ),
    IconSlideAction(
      caption: 'Share',
      color: Colors.indigo,
      icon: Icons.share,
      onTap: () => _showSnackBar('Share'),
    ),
  ],
  secondaryActions: <Widget>[
    IconSlideAction(
      caption: 'More',
      color: Colors.black45,
      icon: Icons.more_horiz,
      onTap: () => _showSnackBar('More'),
    ),
    IconSlideAction(
      caption: 'Delete',
      color: Colors.red,
      icon: Icons.delete,
      onTap: () => _showSnackBar('Delete'),
    ),
  ],
);

Asignación de acciones:

A medida que se deslizan las diapositivas, aparecerá un botón de acción flotante según la dirección de la diapositiva. En ambos casos, se asignarán dos acciones a cada deslizamiento de la siguiente manera:

  • Para deslizamiento de izquierda a derecha:
  1. Mosaico de archivo
  2. Compartir mosaico
  • Para la diapositiva de derecha a izquierda:
  1. Eliminar mosaico
  2. Más

En aras de la simplicidad, solo asignaremos acciones al botón Archivar mosaico y eliminaremos el botón mosaico que archivará y eliminará el mosaico respectivamente. Para ello utiliza lo siguiente:

Dart

@protected
void initState() {
  slidableController = SlidableController(
    onSlideAnimationChanged: handleSlideAnimationChanged,
    onSlideIsOpenChanged: handleSlideIsOpenChanged,
  );
  super.initState();
}
 
Animation<double> _rotationAnimation;
Color _fabColor = Colors.blue;
 
void handleSlideAnimationChanged(Animation<double> slideAnimation) {
  setState(() {
    _rotationAnimation = slideAnimation;
  });
}
 
void handleSlideIsOpenChanged(bool isOpen) {
  setState(() {
    _fabColor = isOpen ? Colors.green : Colors.blue;
  });
}
 
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
      backgroundColor: Colors.green,
    ),
    body: Center(
      child: OrientationBuilder(
        builder: (context, orientation) => _buildList(
            context,
            orientation == Orientation.portrait
                ? Axis.vertical
                : Axis.horizontal),
      ),
    ),
    floatingActionButton: FloatingActionButton(
      backgroundColor: _fabColor,
      onPressed: null,
      child: _rotationAnimation == null
          ? Icon(Icons.add)
          : RotationTransition(
        turns: _rotationAnimation,
        child: Icon(Icons.add),
      ),
    ),
  );
}
 
Widget _buildList(BuildContext context, Axis direction) {
  return ListView.builder(
    scrollDirection: direction,
    itemBuilder: (context, index) {
      final Axis slidableDirection =
      direction == Axis.horizontal ? Axis.vertical : Axis.horizontal;
      var item = items[index];
      if (item.index < 8) {
        return _getSlidableWithLists(context, index, slidableDirection);
      } else {
        return _getSlidableWithDelegates(context, index, slidableDirection);
      }
    },
    itemCount: items.length,
  );
}
 
Widget _getSlidableWithLists(
    BuildContext context, int index, Axis direction) {
  final _HomeItem item = items[index];
  return Slidable(
    key: Key(item.title),
    controller: slidableController,
    direction: direction,
    dismissal: SlidableDismissal(
      child: SlidableDrawerDismissal(),
      onDismissed: (actionType) {
        _showSnackBar(
            context,
            actionType == SlideActionType.primary
                ? 'Dismiss Archive'
                : 'Dismiss Delete');
        setState(() {
          items.removeAt(index);
        });
      },
    ),
    actionPane: _getActionPane(item.index),
    actionExtentRatio: 0.25,
    child: direction == Axis.horizontal
        ? VerticalListItem(items[index])
        : HorizontalListItem(items[index]),
    actions: <Widget>[
      IconSlideAction(
        caption: 'Archive',
        color: Colors.blue,
        icon: Icons.archive,
        onTap: () => _showSnackBar(context, 'Archive'),
      ),
      IconSlideAction(
        caption: 'Share',
        color: Colors.indigo,
        icon: Icons.share,
        onTap: () => _showSnackBar(context, 'Share'),
      ),
    ],
    secondaryActions: <Widget>[
      Container(
        height: 800,
        color: Colors.green,
        child: Text('a'),
      ),
      IconSlideAction(
        caption: 'More',
        color: Colors.grey.shade200,
        icon: Icons.more_horiz,
        onTap: () => _showSnackBar(context, 'More'),
        closeOnTap: false,
      ),
      IconSlideAction(
        caption: 'Delete',
        color: Colors.red,
        icon: Icons.delete,
        onTap: () => _showSnackBar(context, 'Delete'),
      ),
    ],
  );
}

Código fuente completo:

Dart

import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
  
void main() => runApp(MyApp());
  
class MyApp extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Slidable ',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'GeeksForGeeks'),
    );
  }
}
  
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  
  final String title;
  
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
  
class _MyHomePageState extends State<MyHomePage> {
  SlidableController slidableController;
  final List<_HomeItem> items = List.generate(
    20,
        (i) => _HomeItem(
      i,
      'Slide Bar $i',
      _getSubtitle(i),
      _getAvatarColor(i),
    ),
  );
  
  @protected
  void initState() {
    slidableController = SlidableController(
      onSlideAnimationChanged: handleSlideAnimationChanged,
      onSlideIsOpenChanged: handleSlideIsOpenChanged,
    );
    super.initState();
  }
  
  Animation<double> _rotationAnimation;
  Color _fabColor = Colors.blue;
  
  void handleSlideAnimationChanged(Animation<double> slideAnimation) {
    setState(() {
      _rotationAnimation = slideAnimation;
    });
  }
  
  void handleSlideIsOpenChanged(bool isOpen) {
    setState(() {
      _fabColor = isOpen ? Colors.green : Colors.blue;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        backgroundColor: Colors.green,
      ),
      body: Center(
        child: OrientationBuilder(
          builder: (context, orientation) => _buildList(
              context,
              orientation == Orientation.portrait
                  ? Axis.vertical
                  : Axis.horizontal),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: _fabColor,
        onPressed: null,
        child: _rotationAnimation == null
            ? Icon(Icons.add)
            : RotationTransition(
          turns: _rotationAnimation,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
  
  Widget _buildList(BuildContext context, Axis direction) {
    return ListView.builder(
      scrollDirection: direction,
      itemBuilder: (context, index) {
        final Axis slidableDirection =
        direction == Axis.horizontal ? Axis.vertical : Axis.horizontal;
        var item = items[index];
        if (item.index < 8) {
          return _getSlidableWithLists(context, index, slidableDirection);
        } else {
          return _getSlidableWithDelegates(context, index, slidableDirection);
        }
      },
      itemCount: items.length,
    );
  }
  
  Widget _getSlidableWithLists(
      BuildContext context, int index, Axis direction) {
    final _HomeItem item = items[index];
    //final int t = index;
    return Slidable(
      key: Key(item.title),
      controller: slidableController,
      direction: direction,
      dismissal: SlidableDismissal(
        child: SlidableDrawerDismissal(),
        onDismissed: (actionType) {
          _showSnackBar(
              context,
              actionType == SlideActionType.primary
                  ? 'Dismiss Archive'
                  : 'Dismiss Delete');
          setState(() {
            items.removeAt(index);
          });
        },
      ),
      actionPane: _getActionPane(item.index),
      actionExtentRatio: 0.25,
      child: direction == Axis.horizontal
          ? VerticalListItem(items[index])
          : HorizontalListItem(items[index]),
      actions: <Widget>[
        IconSlideAction(
          caption: 'Archive',
          color: Colors.blue,
          icon: Icons.archive,
          onTap: () => _showSnackBar(context, 'Archive'),
        ),
        IconSlideAction(
          caption: 'Share',
          color: Colors.indigo,
          icon: Icons.share,
          onTap: () => _showSnackBar(context, 'Share'),
        ),
      ],
      secondaryActions: <Widget>[
        Container(
          height: 800,
          color: Colors.green,
          child: Text('a'),
        ),
        IconSlideAction(
          caption: 'More',
          color: Colors.grey.shade200,
          icon: Icons.more_horiz,
          onTap: () => _showSnackBar(context, 'More'),
          closeOnTap: false,
        ),
        IconSlideAction(
          caption: 'Delete',
          color: Colors.red,
          icon: Icons.delete,
          onTap: () => _showSnackBar(context, 'Delete'),
        ),
      ],
    );
  }
  
  Widget _getSlidableWithDelegates(
      BuildContext context, int index, Axis direction) {
    final _HomeItem item = items[index];
  
    return Slidable.builder(
      key: Key(item.title),
      controller: slidableController,
      direction: direction,
      dismissal: SlidableDismissal(
        child: SlidableDrawerDismissal(),
        closeOnCanceled: true,
        onWillDismiss: (item.index != 10)
            ? null
            : (actionType) {
          return showDialog<bool>(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: Text('Delete'),
                content: Text('Item will be deleted'),
                actions: <Widget>[
                  FlatButton(
                    child: Text('Cancel'),
                    onPressed: () => Navigator.of(context).pop(false),
                  ),
                  FlatButton(
                    child: Text('Ok'),
                    onPressed: () => Navigator.of(context).pop(true),
                  ),
                ],
              );
            },
          );
        },
        onDismissed: (actionType) {
          _showSnackBar(
              context,
              actionType == SlideActionType.primary
                  ? 'Dismiss Archive'
                  : 'Dismiss Delete');
          setState(() {
            items.removeAt(index);
          });
        },
      ),
      actionPane: _getActionPane(item.index),
      actionExtentRatio: 0.25,
      child: direction == Axis.horizontal
          ? VerticalListItem(items[index])
          : HorizontalListItem(items[index]),
      actionDelegate: SlideActionBuilderDelegate(
          actionCount: 2,
          builder: (context, index, animation, renderingMode) {
            if (index == 0) {
              return IconSlideAction(
                caption: 'Archive',
                color: renderingMode == SlidableRenderingMode.slide
                    ? Colors.blue.withOpacity(animation.value)
                    : (renderingMode == SlidableRenderingMode.dismiss
                    ? Colors.blue
                    : Colors.green),
                icon: Icons.archive,
                onTap: () async {
                  var state = Slidable.of(context);
                  var dismiss = await showDialog<bool>(
                    context: context,
                    builder: (context) {
                      return AlertDialog(
                        title: Text('Delete'),
                        content: Text('Item will be deleted'),
                        actions: <Widget>[
                          FlatButton(
                            child: Text('Cancel'),
                            onPressed: () => Navigator.of(context).pop(false),
                          ),
                          FlatButton(
                            child: Text('Ok'),
                            onPressed: () => Navigator.of(context).pop(true),
                          ),
                        ],
                      );
                    },
                  );
  
                  if (dismiss) {
                    state.dismiss();
                  }
                },
              );
            } else {
              return IconSlideAction(
                caption: 'Share',
                color: renderingMode == SlidableRenderingMode.slide
                    ? Colors.indigo.withOpacity(animation.value)
                    : Colors.indigo,
                icon: Icons.share,
                onTap: () => _showSnackBar(context, 'Share'),
              );
            }
          }),
      secondaryActionDelegate: SlideActionBuilderDelegate(
          actionCount: 2,
          builder: (context, index, animation, renderingMode) {
            if (index == 0) {
              return IconSlideAction(
                caption: 'More',
                color: renderingMode == SlidableRenderingMode.slide
                    ? Colors.grey.shade200.withOpacity(animation.value)
                    : Colors.grey.shade200,
                icon: Icons.more_horiz,
                onTap: () => _showSnackBar(context, 'More'),
                closeOnTap: false,
              );
            } else {
              return IconSlideAction(
                caption: 'Delete',
                color: renderingMode == SlidableRenderingMode.slide
                    ? Colors.red.withOpacity(animation.value)
                    : Colors.red,
                icon: Icons.delete,
                onTap: () => _showSnackBar(context, 'Delete'),
              );
            }
          }),
    );
  }
  
  static Widget _getActionPane(int index) {
    switch (index % 4) {
      case 0:
        return SlidableBehindActionPane();
      case 1:
        return SlidableStrechActionPane();
      case 2:
        return SlidableScrollActionPane();
      case 3:
        return SlidableDrawerActionPane();
      default:
        return null;
    }
  }
  
  static Color _getAvatarColor(int index) {
    switch (index % 4) {
      case 0:
        return Colors.red;
      case 1:
        return Colors.green;
      case 2:
        return Colors.blue;
      case 3:
        return Colors.indigoAccent;
      default:
        return null;
    }
  }
  
  static String _getSubtitle(int index) {
    switch (index % 4) {
      case 0:
        return ' ';
      case 1:
        return ' ';
      case 2:
        return ' ';
      case 3:
        return ' ';
      default:
        return null;
    }
  }
  
  void _showSnackBar(BuildContext context, String text) {
    Scaffold.of(context).showSnackBar(SnackBar(content: Text(text)));
  }
}
  
class HorizontalListItem extends StatelessWidget {
  HorizontalListItem(this.item);
  final _HomeItem item;
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      width: 160.0,
      child: Column(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Expanded(
            child: CircleAvatar(
              backgroundColor: item.color,
              child: Text('${item.index}'),
              foregroundColor: Colors.white,
            ),
          ),
          Expanded(
            child: Center(
              child: Text(
                item.subtitle,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
  
class VerticalListItem extends StatelessWidget {
  VerticalListItem(this.item);
  final _HomeItem item;
  
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () =>
      Slidable.of(context)?.renderingMode == SlidableRenderingMode.none
          ? Slidable.of(context)?.open()
          : Slidable.of(context)?.close(),
      child: Container(
        color: Colors.white,
        child: ListTile(
          leading: CircleAvatar(
            backgroundColor: item.color,
            child: Text('${item.index}'),
            foregroundColor: Colors.white,
          ),
          title: Text(item.title),
          subtitle: Text(item.subtitle),
        ),
      ),
    );
  }
}
  
class _HomeItem {
  const _HomeItem(
      this.index,
      this.title,
      this.subtitle,
      this.color,
      );
  
  final int index;
  final String title;
  final String subtitle;
  final Color color;
}

Producción:

Publicación traducida automáticamente

Artículo escrito por ddeevviissaavviittaa y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *