In my flutter application I have a scrolling animation every time a list is updated via firebase. This animation works perfectly, but I noticed that when the elements in the list are so few that scrolling is not possible, the animation starts from above the container that should contain it. I provide the list structure code:
class _HomePageState extends State<HomePage> {
final CollectionReference pensieri =
FirebaseFirestore.instance.collection("Pensieri");
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF800020),
body: SafeArea(
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 40, bottom: 15),
child: Center(
child: Text(
"Cronologia",
style: TextStyle(
color: Color.fromRGBO(255, 240, 245, 0.75),
fontSize: 18,
),
),
),
),
Expanded(
child: Container(
height: 200,
margin: const EdgeInsets.symmetric(horizontal: 40),
decoration: BoxDecoration(
border: Border.all(
width: 10,
color: const Color(0xFF9B111E),
),
borderRadius: BorderRadius.circular(50),
),
child: ShaderMask(
shaderCallback: (Rect bounds) {
return const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Colors.transparent,
Colors.transparent,
Colors.black,
],
stops: [0.0, 0.05, 0.95, 1.0],
).createShader(bounds);
},
blendMode: BlendMode.dstOut,
child: StreamBuilder(
stream: pensieri
.orderBy('time', descending: true)
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
final int docCount =
streamSnapshot.data!.docs.length;
if (docCount == 0) {
return const Center(
child: Text(
"Non c'รจ ancora nulla qui!\nChe aspetti?",
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(255, 240, 245, 0.75),
fontSize: 18,
),
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(25),
itemCount: docCount,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
Timestamp timestamp = documentSnapshot['time'];
DateTime dateTime = timestamp.toDate();
String formattedDate =
DateFormat('dd/MM/yyyy - HH:mm')
.format(dateTime);
return SlideInAnimation(
key: ValueKey(documentSnapshot.id),
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(50),
),
child: ListTile(
contentPadding: const EdgeInsets.all(2.5),
title: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Text(
documentSnapshot['id'] == 0
? "๐ฑ๐ปโโ๏ธ"
: "๐จ๐ป",
style: const TextStyle(
fontSize: 30,
color: Color(0xFFFFF0F5)),
),
Text(
formattedDate,
style: const TextStyle(
color: Color(0xFFFFF0F5),
fontSize: 18,
),
),
],
),
),
),
);
},
);
}
return const Center(
child: CircularProgressIndicator(
color: Color(0xFF9B111E),
),
);
}),
),
),
),
const HeartButton(),
],
),
),
),
);
}
}
I also provide the code of the class containing my animation:
class SlideInAnimationState extends State<SlideInAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_slideAnimation = Tween<Offset>(
begin: const Offset(0, -1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInCubic,
));
_controller.forward();
}
@override
void didUpdateWidget(covariant SlideInAnimation oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.key != widget.key) {
_controller.forward(from: 0.0);
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SlideTransition(
position: _slideAnimation,
child: widget.child,
);
}
}
I think the problem may be dictated by the fact that in reality the animation is always wrong, but the scroll effect hides the error; therefore, when the scroll is not performed, the error is visible.
It was enough to wrap the ShaderMask on the home page with a ClipRect. This solved my problem
class _HomePageState extends State<HomePage> {
final CollectionReference pensieri =
FirebaseFirestore.instance.collection("Pensieri");
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFF800020),
body: SafeArea(
child: Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 40, bottom: 15),
child: Center(
child: Text(
"Cronologia",
style: TextStyle(
color: Color.fromRGBO(255, 240, 245, 0.75),
fontSize: 18,
),
),
),
),
Expanded(
child: Container(
constraints: const BoxConstraints(maxWidth: 425),
height: 200,
margin: const EdgeInsets.symmetric(horizontal: 40),
decoration: BoxDecoration(
border: Border.all(
width: 10,
color: const Color(0xFF9B111E),
),
borderRadius: BorderRadius.circular(50),
),
child: ClipRect(
child: ShaderMask(
shaderCallback: (Rect bounds) {
return const LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black,
Colors.transparent,
Colors.transparent,
Colors.black,
],
stops: [0.0, 0.05, 0.95, 1.0],
).createShader(bounds);
},
blendMode: BlendMode.dstOut,
child: StreamBuilder(
stream: pensieri
.orderBy('time', descending: true)
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
final int docCount =
streamSnapshot.data!.docs.length;
if (docCount == 0) {
return const Center(
child: Text(
"Non c'รจ ancora nulla qui!\nChe aspetti?",
textAlign: TextAlign.center,
style: TextStyle(
color:
Color.fromRGBO(255, 240, 245, 0.75),
fontSize: 18,
),
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(25),
itemCount: docCount,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
Timestamp timestamp =
documentSnapshot['time'];
DateTime dateTime = timestamp.toDate();
String formattedDate =
DateFormat('dd/MM/yyyy - HH:mm')
.format(dateTime);
return SlideInAnimation(
key: ValueKey(documentSnapshot.id),
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(50),
),
child: ListTile(
contentPadding:
const EdgeInsets.all(2.5),
title: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Text(
documentSnapshot['id'] == 0
? "๐ฑ๐ปโโ๏ธ"
: "๐จ๐ป",
style: const TextStyle(
fontSize: 30,
color: Color(0xFFFFF0F5)),
),
Text(
formattedDate,
style: const TextStyle(
color: Color(0xFFFFF0F5),
fontSize: 18,
),
),
],
),
),
),
);
},
);
}
return const Center(
child: CircularProgressIndicator(
color: Color(0xFF9B111E),
),
);
}),
),
),
),
),
const HeartButton(),
],
),
),
),
);
}
}