I want to sort a list of items and to add a custom title/header on top of some items from the list like in the photo attached below:
What I try to achieve is that if the first element from the list have the property "isHooked = true" then I want to add on top of first row a header called "Current Trailer" and on top of second row I want to add a header called "Past Trailers" which will include the other items from the list.
Can you help me to understand what I’m doing wrong in my code ?
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class Trailer {
Trailer({this.trailerPlate, this.isHookup, this.time});
String? trailerPlate = "";
bool? isHookup = false;
String? time = "";
}
List<Trailer> trailersHistory = [
Trailer(trailerPlate: "Trailer4", isHookup: true, time: "16:00"),
Trailer(trailerPlate: "Trailer3", isHookup: false, time: "15:00"),
Trailer(trailerPlate: "Trailer2", isHookup: false, time: "14:00"),
Trailer(trailerPlate: "Trailer1", isHookup: false, time: "13:00"),
];
class MyWidget extends StatelessWidget {
Widget customCard({required Widget widget, required Color cardColor}) {
return Card(
color: cardColor,
child: Padding(padding: const EdgeInsets.all(8.0), child: widget),
);
}
Widget displayTrailersHistoryTable() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(trailersHistory.first.isHookup ?? false) == true
? const Text("Current Trailer",
style: TextStyle(color: Colors.green))
: const Text("Past Trailers", style: TextStyle(color: Colors.red)),
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
scrollDirection: Axis.vertical,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
itemCount: trailersHistory.length,
itemBuilder: (BuildContext context, int index) {
Trailer currentTrailer = trailersHistory[index];
return customCard(
widget: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(currentTrailer.trailerPlate ?? ""),
(currentTrailer.isHookup ?? false)
? const Icon(
Icons.add_circle,
color: Colors.green,
size: 30.0,
)
: const Icon(
Icons.remove_circle,
color: Colors.red,
size: 30.0,
),
Text("@ ${currentTrailer.time}")
]),
cardColor: Colors.grey);
},
),
),
),
],
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
alignment: FractionalOffset.center,
child: displayTrailersHistoryTable(),
);
}
}
Here is also a link to my small demo:
Dart Pad Link for Demo
2
Answers
Thanks to @AtMaintx I managed to implement the solution. Here is the full code:
Seem like you want "Past Trailers" to be between the items made by the itemBuilder. Here is a possible solution.
At the start of the function displayTrailersHistoryTable put:
bool hasCurrentTrailer = (trailersHistory.first.isHookup ?? false);
. Then make itemCount into:itemCount: hasCurrentTrailer ? trailersHistory.length+1 : trailersHistory.length,
. At the start of the item builder put:int newIndex = index;
. Then next line is:if(hasCurrentTrailer) { if(index == 1) return const Text("Past Trailers", style: TextStyle(color: Colors.red)); if(index > 1) newIndex--; }
. Now you just have to get the trailer from trailer history using newIndex instead of index. With these changes you will get "Past Trailers" in between the first and second item in the case that the first item isHookup equals true.— Update, steps to make top text scrollable —
Remove the first child from the columns children as we move it to the itemBuilder. Set itemCount to
itemCount: hasCurrentTrailer ? trailersHistory.length+2 : trailersHistory.length+1,
.The first line in itemBuilder will be:
if(index == 0) return hasCurrentTrailer ? const Text("Current Trailer", style: TextStyle(color: Colors.green)) : const Text("Past Trailers", style: TextStyle(color: Colors.red));
.Update the line before currentTrailer to:
if(hasCurrentTrailer) { if(index == 2) return const Text("Past Trailers", style: TextStyle(color: Colors.red)); if(index > 2) newIndex--; }
.Finally change
trailersHistory[newIndex]
totrailersHistory[newIndex-1]
.Now the top text is the first item in the list and is now scrollable.