-
-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to close a Slidable from outside its widget tree? #323
Comments
@kyuberi Do yo have any solution for workaround? |
@kyuberi Have you tried static method Slidable.of(BuildContext context) which returns SlidableController? |
@chrisalex-w have you managed to find a solution for that? I'm having a similar issue. It used to be that with an opened slidable you could tap anywhere and it would close, now it is not the case. I tried to wrap my entire app in the SlidableAutoCloseBehavior but it only works if another slidable in the same group is tapped. @letsar any idea how to get that behaviour back? |
@letsar Do you have any solution for this problem? |
Hi @chrisalex-w, you can get a |
Actually, you may try something like this: import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SlidableOwner(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: const Text('Slidable from outside'),
),
body: SlidableAutoCloseBehavior(
closeWhenOpened: true,
closeWhenTapped: false,
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return MyTile(index: index);
},
),
),
),
),
);
}
}
class MyTile extends StatelessWidget {
final int index;
const MyTile({
super.key,
required this.index,
});
@override
Widget build(BuildContext context) {
return Slidable(
closeOnScroll: false,
startActionPane: const ActionPane(
dragDismissible: false,
motion: ScrollMotion(),
children: [
SlidableAction(
backgroundColor: Color(0xFFe0e0e0),
icon: Icons.remove_circle_outline_outlined,
autoClose: false,
onPressed: null,
),
SlidableAction(
backgroundColor: Color(0xFFe0e0e0),
icon: Icons.add_circle_outline_outlined,
autoClose: false,
onPressed: null,
),
],
),
child: SlidableOwnerTarget(
id: index,
child: Container(
padding: const EdgeInsets.all(24),
child: TextFormField(
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.grey[800],
),
decoration: const InputDecoration(
isDense: true,
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
),
initialValue: '25.000',
// Close specific registered Slidable
onTap: () => SlidableOwner.of(context).close(index + 1),
),
),
),
);
}
}
class SlidableOwnerScope extends InheritedWidget {
final SlidableOwnerState state;
const SlidableOwnerScope({
super.key,
required super.child,
required this.state,
});
@override
bool updateShouldNotify(SlidableOwnerScope oldWidget) {
return false;
}
}
class SlidableOwner extends StatefulWidget {
final Widget child;
const SlidableOwner({
super.key,
required this.child,
});
@override
State<SlidableOwner> createState() => SlidableOwnerState();
static SlidableOwnerState of(BuildContext context) {
return context.getInheritedWidgetOfExactType<SlidableOwnerScope>()!.state;
}
}
class SlidableOwnerState extends State<SlidableOwner> {
final _controllers = <Object, SlidableController>{};
@override
Widget build(BuildContext context) {
return SlidableOwnerScope(
state: this,
child: widget.child,
);
}
Future<void> close(Object id) async {
final controller = _controllers[id];
if (controller == null) return;
return controller.close();
}
Future<void> closeAll() async =>
await Future.wait(_controllers.values.map((e) => e.close()).toList());
}
class SlidableOwnerTarget extends StatefulWidget {
final Widget child;
final Object id;
const SlidableOwnerTarget({
super.key,
required this.child,
required this.id,
});
@override
State<SlidableOwnerTarget> createState() => _SlidableOwnerTargetState();
}
class _SlidableOwnerTargetState extends State<SlidableOwnerTarget> {
late SlidableOwnerState _slidableOwnerState;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_slidableOwnerState = SlidableOwner.of(context);
_slidableOwnerState._controllers[widget.id] = Slidable.of(context)!;
}
@override
void dispose() {
super.dispose();
_slidableOwnerState._controllers.remove(widget.id);
}
@override
Widget build(BuildContext context) {
return widget.child;
}
} |
doesn't work with AutomaticKeepAliveClientMixin |
I have a
ListView
and each one of its items is wrapped with aSlidable
. These tiles are composed by aTextFormField
. I would like to be able to close a Slidable by tapping another tile. To be more precise, by tapping the TextFormField of another tile.There are three tiles with Slidables attached to them.
In the following images, from left to right:
TextFormField
of the third tile.Slidable
of the second tile should be closed.Simple App:
Tile:
From what I understand, in old versions of this package you used a
SlidableController
, but it has changed now. A recommended way is to wrap the list with aSlidableAutoCloseBehavior
, but it can't control each Slidable independently.The parameter
closeWhenTapped
is the closest to a solution because if I set this totrue
, it let me close the tile after tapping in another tile, but, I have to tap twice, hence the TextFormField is not selectable at first touch. So I set it tofalse
in order to let me select the TextFormField although without being able to close the Slidable automatically.The text was updated successfully, but these errors were encountered: