'In Flutter is it possible to increase the transparency of a Dismissible widget the further it is dismissed?
I have a Dismissible widget in my application that I drag down to dismiss. There is a requirement that the transparency of the Dismissible should increase the further it is dragged down. So it should look as if it is fading out as it is dismissed. If it were to be dragged back up, its transparency should decrease.
As a simple test I tried wrapping the Dismissible in a Listener and Opacity widget. The opacity value is set to a variable tracked in state. The Listener widget listens to the total "y" axis movement of the Dismissible and when it reaches a certain threshold, decreases the the opacity value tracked in state. See code below for example:
import 'package:flutter/material.dart';
class FadingDismissible extends StatefulWidget {
@override
_FadingDismissible createState() => _FadingDismissible();
}
class _FadingDismissible extends State<FadingDismissible> {
double _totalMovement = 0;
double _opacity;
@override
void initState() {
super.initState();
_opacity = 1.0;
}
_setOpacity(double opacityValue) {
setState(() {
_opacity = opacityValue;
});
}
@override
Widget build(BuildContext context) {
return Listener(
onPointerMove: (PointerMoveEvent event) {
_totalMovement += event.delta.dy;
if (_totalMovement > 200) {
_setOpacity(0.5);
}
},
onPointerUp: (PointerUpEvent event) {
_setOpacity(1.0);
_totalMovement = 0;
},
child: Opacity(
opacity: _opacity,
child: Dismissible(
direction: DismissDirection.down,
key: UniqueKey(),
onDismissed: (direction) {
Navigator.pop(context);
},
child: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {},
),
body: Container(color: Colors.blue),
),
),
),
);
}
}
The issue is, whenever the state is set, the widget is re-built and the Dismissible jumps back to the top.
Right now I'm not sure of another way around this. Is there a way to change the transparency of a Dismissible widget as it is dragged? Or will I have to use a different widget altogether?
Thanks!
Solution 1:[1]
I think might be the closest if you do not want to create your own Dismissible widget:
class FadingDismissible extends StatefulWidget {
final String text;
FadingDismissible({@required this.text});
@override
_FadingDismissibleState createState() => _FadingDismissibleState();
}
class _FadingDismissibleState extends State<FadingDismissible> {
double opacity = 1.0;
StreamController<double> controller = StreamController<double>();
Stream stream;
double startPosition;
@override
void initState() {
super.initState();
stream = controller.stream;
}
@override
void dispose() {
super.dispose();
controller.close();
}
@override
Widget build(BuildContext context) {
return Dismissible(
key: GlobalKey(),
child: StreamBuilder(
stream: stream,
initialData: 1.0,
builder: (context, snapshot) {
return Listener(
child: Opacity(
opacity: snapshot.data,
child: Text(widget.text),
),
onPointerDown: (event) {
startPosition = event.position.dx;
},
onPointerUp: (event) {
opacity = 1.0;
controller.add(opacity);
},
onPointerMove: (details) {
if (details.position.dx > startPosition) {
var move = details.position.dx - startPosition;
move = move / MediaQuery.of(context).size.width;
opacity = 1 - move;
controller.add(opacity);
}
},
);
},
),
);
}
}
Solution 2:[2]
Here is another method, similar to the one posted by @Sneider but uses a ValueNotifier
and ValueListenableBuilder
instead of Stream
and `StreamBuilder.
import 'package:flutter/material.dart';
class FadingDismissible extends StatefulWidget {
const FadingDismissible({Key? key}) : super(key: key);
@override
State<FadingDismissible> createState() => _FadingDismissibleState();
}
class _FadingDismissibleState extends State<FadingDismissible> {
final ValueNotifier<double> _opacity = ValueNotifier(1.0);
late double _startPosition;
@override
Widget build(BuildContext context) {
return Dismissible(
key: UniqueKey(),
child: Listener(
onPointerDown: (event) {
_startPosition = event.position.dx;
},
onPointerUp: (event) {
_opacity.value = 1.0;
},
onPointerMove: (event) {
if (event.position.dx < _startPosition) {
// Dismiss Left
var move = _startPosition - event.position.dx;
move = move / MediaQuery.of(context).size.width;
_opacity.value = 1.0 - move;
} else {
// Dismiss Right
var move = event.position.dx - _startPosition;
move = move / MediaQuery.of(context).size.width;
_opacity.value = 1.0 - move;
}
},
child: ValueListenableBuilder(
valueListenable: _opacity,
builder: (BuildContext context, double opacity, Widget? child) {
return Opacity(
opacity: opacity > 0.2 ? opacity : 0.2,
child: Container(
color: Colors.red,
width: 100,
height: 100,
),
);
},
),
),
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Snieder |
Solution 2 | Chris |