The app has a BottomNavigationBar (always visible) and when I added the search tab this error apears (Search page was writed following a tutorial from youtube). I'm not sure about how can manage the state when I leave the search page or how to restart it.
I realice error apears when no search has been performed
Can someone help to solve this error?
Here is my code
home
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static final List<Widget> _widgetOptions = <Widget>[
const Text(
'Index 1: Home',
style: optionStyle,
),
const Text(
'Index 1: Events',
style: optionStyle,
),
SearchScreen(),
const Text(
'Index 3: Messages',
style: optionStyle,
),
ProfilePage(uid: FirebaseAuth.instance.currentUser!.uid)
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: mobileBackgroundColor,
),
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
label: 'Events',
backgroundColor: mobileBackgroundColor,
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
backgroundColor: mobileBackgroundColor,
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.chat_bubble_2),
label: 'Messages',
backgroundColor: mobileBackgroundColor,
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
backgroundColor: mobileBackgroundColor,
),
],
unselectedItemColor: Colors.black12,
selectedItemColor: Colors.deepOrangeAccent,
currentIndex: _selectedIndex,
onTap: _onItemTapped,
));
}
}
search
class Search extends StatefulWidget {
@override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
static const historyLenght = 5;
final List<String> _searchHistory = ['pink', 'blue'];
late List<String> filteredSearchHistory;
String selectedTerm = "Search";
List<String> filterSearchTerms({
@required String? filter,
}) {
if (filter != null && filter.isNotEmpty) {
return _searchHistory.reversed
.where((term) => term.startsWith(filter))
.toList();
} else {
return _searchHistory.reversed.toList();
}
}
void addSearchTerm(String term) {
if (_searchHistory.contains(term)) {
putSearchTermFirst(term);
return;
}
_searchHistory.add(term);
if (_searchHistory.length > historyLenght) {
_searchHistory.removeRange(0, _searchHistory.length - historyLenght);
}
filteredSearchHistory = filterSearchTerms(filter: null);
}
void deleteSearchTerm(String term) {
_searchHistory.removeWhere((element) => element == term);
filteredSearchHistory = filterSearchTerms(filter: null);
}
void putSearchTermFirst(String term) {
deleteSearchTerm(term);
addSearchTerm(term);
}
late FloatingSearchBarController controller;
@override
void initState() {
super.initState();
controller = FloatingSearchBarController();
filteredSearchHistory = filterSearchTerms(filter: null);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FloatingSearchBar(
controller: controller,
body: FloatingSearchBarScrollNotifier(
child: SearchResultListView(
searchTerm: selectedTerm,
),
),
transition: CircularFloatingSearchBarTransition(),
physics: const BouncingScrollPhysics(),
title: Text(selectedTerm),
hint: 'Search ... ',
actions: [
FloatingSearchBarAction.searchToClear(),
],
onQueryChanged: (query) {
setState(() {
filteredSearchHistory = filterSearchTerms(filter: query);
});
},
onSubmitted: (query) {
setState(() {
addSearchTerm(query);
selectedTerm = query;
});
controller.close();
},
builder: (context, transition) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Material(
color: Colors.white,
elevation: 4,
child: Builder(builder: ((context) {
if (filteredSearchHistory.isEmpty &&
controller.query.isEmpty) {
return Container(
height: 56,
width: double.infinity,
alignment: Alignment.center,
child: const Text(
'Start searching',
maxLines: 1,
overflow: TextOverflow.ellipsis,
));
} else if (filteredSearchHistory.isEmpty) {
return ListTile(
title: Text(controller.query),
leading: const Icon(Icons.search),
onTap: () {
setState(() {
addSearchTerm(controller.query);
selectedTerm = controller.query;
});
controller.close();
},
);
} else {
return Column(
mainAxisSize: MainAxisSize.min,
children: filteredSearchHistory
.map(
(e) => ListTile(
title: Text(e,
maxLines: 1,
overflow: TextOverflow.ellipsis),
leading: const Icon(Icons.history),
trailing: IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
setState(() {
deleteSearchTerm(e);
});
},
),
onTap: () {
setState(() {
putSearchTermFirst(e);
selectedTerm = e;
});
controller.close();
},
),
)
.toList());
}
}))),
);
},
),
);
}
}
class SearchResultListView extends StatelessWidget {
final String searchTerm;
const SearchResultListView({
Key? key,
required this.searchTerm,
}) : super(key: key);
@override
Widget build(BuildContext context) {
if (searchTerm == null) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [Icon(Icons.search), Text('data')],
),
);
}
final sBar = FloatingSearchBar.of(context);
return ListView(
padding: EdgeInsets.only(
top: sBar!.style.height + sBar.style.margins.vertical),
children: List.generate(
50,
(index) => ListTile(
title: Text('Hola $searchTerm'),
subtitle: Text(index.toString()),
)));
}
}