Flutter - Скользящий

Опубликовано: 5 Января, 2022

Slidable в приложении можно использовать для выполнения широкого круга задач, просто проведя пальцем вправо или влево по плитке. Это не только делает пользовательский интерфейс очень удобным для пользователя, но и экономит много времени при выполнении тривиальных задач, которые, если их выполнять другими способами, могут быть беспокойными и избыточными для проектирования. В этой статье мы рассмотрим процесс разработки слайдера для вашего приложения.

Здесь мы создадим простое приложение с плитками, которое при смахивании слева направо архивирует плитку, а при смахивании справа налево удаляет плитку. Для этого выполните следующие действия:

  • Добавьте flutter_slidable зависимость к файлу pubspec.yaml.
  • Импортировать зависимость в файл main.dart
  • Создайте StatelessWidget, чтобы дать приложению структуру
  • Используйте StateFulWidget, чтобы добавить домашнюю страницу в приложение
  • Используйте SlidableCntroller для настройки действий слайда
  • Используйте FloatingActionButton для назначения действий кнопкам, созданным при перемещении плитки
  • Используйте WidgetBuilder для создания плиток на домашней странице

Давайте подробно обсудим шаги.

Добавление зависимости:

Вы можете импортировать flutter_slidable зависимости в файле pubspec.yaml , как показано ниже:

Импорт зависимости:

Чтобы импортировать зависимость в файл main.dart, используйте следующее:

 import 'package: flutter_slidable / flutter_slidable.dart';

Создание структуры приложения:

Используйте StatelessWidget, чтобы дать приложению простую структуру, как показано ниже:

Дротик

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

Создание домашней страницы:

Используйте StatefulWidget, чтобы настроить домашнюю страницу для приложения, которое в будущем будет содержать плитки, которые можно перемещать в любом направлении для выполнения назначенных им задач, как показано ниже:

Дротик

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),
),
);

Оформление слайдов:

Используйте SlidableController, чтобы настроить слайды для приложения. Это можно сделать с помощью конструктора Slidable или конструктора Slidable.builder . Приложение, которое мы создаем, состоит из 4 основных компонентов:

  1. Действия со слайдом
  2. Виджет панели действий слайда
  3. Соотношение экстента между экстентом действия слайда и экстентом элемента.
  4. Ребенок

Для создания выдвижной конструкции используйте следующее:

Дротик

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' ),
),
],
);

Назначение действий:

Когда слайды будут перемещены , появится кнопка FloatingActionButton в зависимости от направления слайда. В обоих случаях каждому смахиванию будут назначены два действия:

  • Для слайдов слева направо:
  1. Архивная плитка
  2. Поделиться плиткой
  • Для слайда справа налево:
  1. Удалить плитку
  2. Более

Для простоты мы назначим действия только кнопке «Архивировать плитку» и удалим кнопку плитки, которая будет архивировать и удалять плитку соответственно. Для этого используйте следующее:

Дротик

@ 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' ),
),
],
);
}

Полный исходный код:

Дротик

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 ),