I have a pageview.builder that is being used to display 1 user profile at a time and has pagination to it. There are few buttons, like shortlist, ignore etc., which are toggleable (icon & text changes). Tap on the button would call API and upon success it should toggle.
My PageView.builder is wrapped by Obx that is waiting for data on :
RxList<MatchesListModel> matches = <MatchesListModel>[].obs;
in controller to rebuild once it fetches the data.
When API call is success, I’m updating matches’ particular index shortlist, rather than fetching list again from controller’s toggleShortlist().
Everything works alright except, when I tap button it doesn’t rebuild to update new state. Is there a way to rebuild the current page so that it would show the new state.?
Implementation:
Main Layout
class HomeMatchesScreen extends StatelessWidget {
const HomeMatchesScreen({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder(
init: HomeMatchesController(),
builder: (gxC) {
return Scaffold(
appBar: AppBar(
title: const Text("Matches"),
),
body: Obx(() {
return PageView.builder(
onPageChanged: (index) {
if (index == gxC.matches.length - 1 && !gxC.pageEnd) {
gxC.getMatches();
}
},
physics: const CustomPageViewScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: gxC.matches.length + (gxC.isLoading.value ? 1 : 0),
itemBuilder: (context, index) {
if (gxC.matches.isNotEmpty && index == gxC.matches.length) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: LoaderListShimmer(
widgetColumn: CustomLoadingSets.matchesList(),
),
);
} else if (gxC.matches.isEmpty) {
return const NoDataFound(text: "No Matches found");
} else {
final item = gxC.matches[index];
return AdapterMatchesCard(
index: index,
onPressed: () => Get.to(() => const UserDetailsScreen(), arguments: item.id),
);
}
},
);
}),
);
});
}
}
Component :
class AdapterMatchesCard extends StatelessWidget {
final int index;
final VoidCallback onPressed;
const AdapterMatchesCard({
super.key,
required this.index,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return GetBuilder(
init: HomeMatchesController(),
builder: (gxC) {
return Obx(() {
var match = gxC.matches[index];
return Container(
margin: const EdgeInsets.fromLTRB(16.00, 16.00, 16.00, 80.00),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(...),
Padding(
padding: const EdgeInsets.fromLTRB(12.0, 2.00, 12.00, 12.00),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: ProfileActionButton(
assetPath: "assets/images/profile-ignore-inactive.svg",
title: "Ignore",
onTap: () {},
),
),
Expanded(
child: ProfileActionButton(
assetPath: match.shortlisted == 1
? "assets/images/profile-shortlist-active.svg"
: "assets/images/profile-shortlist-inactive.svg",
title: "Shortlist",
onTap: () async {
final bool res = await gxC.toggleShortlist(index);
// if (res) {
// shortlisted = !shortlisted;
// }
// setState(() {});
},
),
),
Expanded(
child: ProfileActionButton(
assetPath: "assets/images/profile-accept-inactive.svg",
title: "Accept!",
onTap: () {},
),
),
],
)
],
),
),
],
),
);
});
});
}
}
Controller:
RxList<MatchesListModel> matches = <MatchesListModel>[].obs;
Future<bool> toggleShortlist(int index) async {
var match = matches[index];
try {
globalLoader(true);
await _shortlistsRepo.shortlistToggle(userId: match.id, status: match.shortlisted ? 1 : 0);
globalLoader(false);
matches[index].shortlisted = !match.shortlisted;
showToast(match.shortlisted ? "Shortlisted" : "Removed from Shortlists!");
return true;
} catch (e) {
showToast(e.toString());
return false;
}
}