In my app I have an index screen with some bottom nav that can show or go to another screen on click using setState to change the _selectedIndex and the screen are in a list
class IndexPage extends StatefulWidget {
const IndexPage({Key? key}) : super(key: key);
@override
State<IndexPage> createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
int _selectedIndex = 0;
final List<Widget> _widgetOptions = <Widget>[
const HomeScreen(),
const ExploreScreen(),
const InvestScreen(),
const WalletScreen(),
const MoreScreen(),
];
@override
void initState() {
connectRequiredApi();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: _widgetOptions[_selectedIndex],
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: _selectedIndex == 0
? const Icon(IconlyBold.home, size: 22)
: const Icon(IconlyLight.home, size: 22),
label: "Home",
),
//.......//
BottomNavigationBarItem(
icon: _selectedIndex == 4
? const Icon(IconlyBold.category, size: 22)
: const Icon(IconlyLight.category, size: 22),
label: 'More',
),
],
currentIndex: _selectedIndex,
//...
onTap: itemTapped,
),
);
}
void itemTapped(int index) {
if (index == 2) {
showToast(context, "Coming Soon");
} else {
setState(() {
_selectedIndex = index;
});
}
}
void connectRequiredApi() async {
await Get.find<MapController>().checkLocationPermission();
//...//
}
}
And in my HomeScreen();
I have an initState that calls an http request to my backend and it calls it only once when am on the homescreen. But the problem am having now is that whenever I click on the bottom nav to switch screen and then go back to my HomeScreen()
it gets rebuilt and calls the initState again making another http request showing my loading shimmer even after i have tried to maintain the state of the page
HomeScreen();
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen>
with AutomaticKeepAliveClientMixin<HomeScreen> {
@override
void initState() {
getLocation();
super.initState();
}
getLocation() async {
await Get.find<PropertyController>().getFeaturedProperty();
}
@override
Widget build(BuildContext context) {
super.build(context);
ColorScheme theme = Theme.of(context).colorScheme;
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: GetBuilder<PropertyController>(
id: "home_page.dart",
builder: (propertyController) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//.....//
propertyController.homeLoading
? ListView.builder(
itemCount: 4,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (ctx, idx) {
return const GFShimmer(child: HomeShimmer());
})
: propertyController.featuredPropertyList.isEmpty
? const SizedBox()
: ListView.builder(
itemCount:
propertyController.featuredPropertyList.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (ctx, idx) {
return HouseCard(
property: propertyController
.featuredPropertyList[idx],
);
}),
//...//
propertyController.homeLoading
? ListView.builder(
itemCount: 4,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (ctx, idx) {
return const GFShimmer(child: HomeShimmer());
})
: propertyController.popularPropertyList.isEmpty
? const NotFound(
icon: Icons.domain_disabled_outlined,
message: "No property listed",
)
: SizedBox(
height: 240,
child: ListView.builder(
shrinkWrap: true,
itemCount:
propertyController.popularPropertyList.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return PopularHouse(
propertyModel: propertyController
.popularPropertyList[index],
);
},
),
)
],
);
}),
);
}
@override
bool get wantKeepAlive => true;
}
My PropertyController
class PropertyController extends GetxController {
PropertyRepo propertyRepo = PropertyRepo();
PropertyModel propertyModel = PropertyModel();
PropertyModel apartmentModel = PropertyModel();
final List<PropertyModel> _featuredPropertyList = [];
final List<PropertyModel> _popularPropertyList = [];
bool homeLoading = true;
List<PropertyModel> get featuredPropertyList => _featuredPropertyList;
List<PropertyModel> get popularPropertyList => _popularPropertyList;
//....//
Future<void> getFeaturedProperty() async {
homeLoading = true;
update(["home_page.dart", "explore_prop_page.dart"]);
ResponseModel response = await propertyRepo.getFeaturedProperties();
if (response.statusCode == 200) {
_featuredPropertyList.clear();
_featuredPropertyList.addAll((response.data as List)
.map((e) => PropertyModel.fromJson(e))
.toList());
}
await getPopularProperties();
homeLoading = false;
update(["home_page.dart", "explore_prop_page.dart"]);
}
Future<void> getPopularProperties() async {
ResponseModel response = await propertyRepo.getPopularProperties();
if (response.statusCode == 200) {
if (kDebugMode) {
print(response.data);
}
_popularPropertyList.clear();
_popularPropertyList.addAll((response.data['properties'] as List)
.map((e) => PropertyModel.fromJson(e))
.toList());
}
}
}
Please how can I solve this issue I have tried maintaining state in homescreen but it's still getting called every time. If you need more explanation, please let me know
CodePudding user response:
The problem is that:
- When you move between pages you change the built widget and this re-calls the initState
to solve this issues use PageView() widget with PageController
Your code will be something like this:
class IndexPage extends StatefulWidget {
const IndexPage({Key? key}) : super(key: key);
@override
State<IndexPage> createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> {
int _selectedIndex = 0;
@override
void initState() {
connectRequiredApi();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Pageview(
controller: pageController,
children:[
const HomeScreen(),
const ExploreScreen(),
const InvestScreen(),
const WalletScreen(),
const MoreScreen(),]
],),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: _selectedIndex == 0
? const Icon(IconlyBold.home, size: 22)
: const Icon(IconlyLight.home, size: 22),
label: "Home",
),
//.......//
BottomNavigationBarItem(
icon: _selectedIndex == 4
? const Icon(IconlyBold.category, size: 22)
: const Icon(IconlyLight.category, size: 22),
label: 'More',
),
],
currentIndex: _selectedIndex,
//...
onTap: itemTapped,
),
);
}
void itemTapped(int index) {
if (index == 2) {
showToast(context, "Coming Soon");
} else {
setState(() {
_selectedIndex = index;
});
}
}
void connectRequiredApi() async {
await Get.find<MapController>().checkLocationPermission();
//...//
}
}