admin管理员组文章数量:1401661
How is the search bar, shown in the two attached screenshots, implemented? There is a map on the page, but when I click on the search bar, it displays the search field along with the search results, without navigating to a new page. The BottomNavigationBar
remains visible, and the filter buttons (Pavilony, WC, etc.) disappear. I initially thought this was a SearchDelegate
, but that would load an entirely new page. How is this behavior achieved?
Screenshots:
How is the search bar, shown in the two attached screenshots, implemented? There is a map on the page, but when I click on the search bar, it displays the search field along with the search results, without navigating to a new page. The BottomNavigationBar
remains visible, and the filter buttons (Pavilony, WC, etc.) disappear. I initially thought this was a SearchDelegate
, but that would load an entirely new page. How is this behavior achieved?
Screenshots:
Share Improve this question asked Mar 25 at 1:30 RitchyCZERitchyCZE 1804 silver badges17 bronze badges 2- Do you want the implementation of the mechanism or just the UI ? – Mahmoud Al-shehyby Commented Mar 25 at 3:41
- Put your code to clarify – Dhruv Sakariya Commented Mar 25 at 5:05
1 Answer
Reset to default 1If you want to build a Custom searching by searching and get the result at the same screen you can implement this by building the UI and the management of the searching from search
=> Demo video for the provided Solution : CustomSearching
I had a solution for the mechanism you are want to achieve
1. Build CustomAppBarWidget
class CustomAppBarWidget extends StatelessWidget {
const CustomAppBarWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.sizeOf(context).height * .16,
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(20),
),
child: Consumer<ManageSearch>(
builder: (context, search, _) {
return Column(
children: <Widget>[
const SizedBox(height: 40),
Container(
margin: const EdgeInsets.all(10),
child: TextField(
controller: ManageSearch.searchController,
onChanged: (target) {
search.searchCity;
},
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Search",
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: const BorderSide(
color: Colors.grey,
width: 1.0,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
borderSide: const BorderSide(
color: Colors.grey,
width: 1.5,
),
),
),
),
),
],
);
},
),
);
}
}
2. Build the DemoNavigationWidget
just to simulate your UI
class NavigationModel {
final String label;
final IconData icon;
NavigationModel({
required this.icon,
required this.label,
});
}
List<NavigationModel> navigations = <NavigationModel>[
NavigationModel(icon: Icons.home, label: "Home"),
NavigationModel(icon: Icons.person, label: "Profile"),
NavigationModel(icon: Icons.settings, label: "Settings"),
NavigationModel(icon: Icons.map, label: "Map"),
];
class DemoNavigationBar extends StatelessWidget {
const DemoNavigationBar({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: Colors.white,
),
margin: const EdgeInsets.symmetric(horizontal: 20),
padding: const EdgeInsets.all(10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
for (int i = 0; i < navigations.length; i++) ...{
Column(
children: <Widget>[
Icon(navigations[i].icon),
Text(navigations[i].label)
],
),
}
],
),
);
}
}
3. Build DemoFilterWidget
also just to simulate your UI
// Demo Filter
List<ItemModel> filters = <ItemModel>[
ItemModel(icon: Icons.wc, label: "WC"),
ItemModel(icon: Icons.privacy_tip, label: "PR"),
ItemModel(icon: Icons.restaurant, label: "rest"),
ItemModel(icon: Icons.data_thresholding, label: "Data"),
];
class DemoFilter extends StatelessWidget {
const DemoFilter({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.sizeOf(context).height * .08,
child: ListView.builder(
itemCount: filters.length,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
width: MediaQuery.sizeOf(context).width * .25,
padding: const EdgeInsets.all(10),
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: const Color(0xFFE7FBE6),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(filters[index].icon),
Text(filters[index].label),
],
),
);
},
),
);
}
}
4. I used this demoList of cities to test
List<String> cities = <String>[
"Tokyo",
"Delhi",
"Shanghai",
"São Paulo",
"Mexico City",
"Cairo",
"Mumbai",
"Beijing",
"Dhaka",
"Osaka",
"New York",
"Karachi",
"Buenos Aires",
"Chongqing",
"Istanbul",
"Kolkata",
"Manila",
"Lagos",
"Rio de Janeiro",
"Tianjin",
"Kinshasa",
"Guangzhou",
"Los Angeles",
"Moscow",
"Shenzhen",
"Lahore",
"Bangalore",
"Paris",
"Bogotá",
"Jakarta"
];
5. Build a provider class to manage the search(SRP an clean) [IMPORTANT PART]
class ManageSearch with ChangeNotifier {
List<String> results = <String>[];
static TextEditingController? searchController;
void get searchCity {
String target = searchController!.text;
results = cities.where(
(city) {
bool isExist = city.toLowerCase().trim().contains(
target.toLowerCase().trim(),
);
return isExist;
},
).toList();
notifyListeners();
}
bool get startSearch {
bool isUserSearch = searchController!.text.isNotEmpty;
return isUserSearch;
}
bool get isEmptyResults {
bool isResultEmpty = results.isEmpty;
bool isEmpty = isResultEmpty && startSearch;
return isEmpty;
}
bool get hasResult {
bool hasResult = results.isNotEmpty && startSearch;
return hasResult;
}
}
6. Initialize the controller in the MainScreen
@override
void initState() {
ManageSearch.searchController = TextEditingController();
super.initState();
}
@override
void dispose() {
ManageSearch.searchController!.dispose();
super.dispose();
}
7. Build the MainScreen
and its components
class CustomSearchScreen extends StatefulWidget {
const CustomSearchScreen({super.key});
@override
State<CustomSearchScreen> createState() => _CustomSearchScreenState();
}
class _CustomSearchScreenState extends State<CustomSearchScreen> {
@override
void initState() {
ManageSearch.searchController = TextEditingController();
super.initState();
}
@override
void dispose() {
ManageSearch.searchController!.dispose();
super.dispose();
}
double get height => MediaQuery.sizeOf(context).height;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ManageSearch(),
child: Consumer<ManageSearch>(builder: (context, search, _) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
alignment: Alignment.center,
children: <Widget>[
if (search.isEmptyResults) ...{
Positioned.fill(
top: height * .17,
child: const Center(
child: Text(
"Empty Results",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
),
),
} else ...{
Positioned.fill(
top: height * .15,
child: search.startSearch
? ListView.builder(
padding: const EdgeInsets.only(top: 20),
itemCount: search.results.length,
itemBuilder: (context, index) {
return Container(
padding: const EdgeInsets.all(10),
margin: const EdgeInsets.all(15.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
search.results[index],
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
const Icon(Icons.location_on)
],
),
);
},
)
: InteractiveViewer(
child: Image.asset(
"assets/images/others/profile/test_map.jpg",
fit: BoxFit.cover,
),
),
),
},
const Positioned(
top: 0.0,
right: 0.0,
left: 0.0,
child: CustomAppBarWidget(),
),
if (!search.startSearch) ...{
Positioned(
top: height * .14,
right: 0.0,
left: 0.0,
child: const DemoFilter(),
),
},
Positioned(
right: 0.0,
left: 0.0,
bottom: 0.0,
child: Container(
height: height * .08,
decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular(25),
),
color: Colors.orange,
),
),
),
Positioned(
bottom: height * .03,
right: 0.0,
left: 0.0,
child: const DemoNavigationBar(),
),
],
),
);
}),
);
}
}
If you want you can use the
setState((){})
instead theProvider
but I used the Provider to build it cleanYou can control everything with the
bool
s as Searching Status
Hope that wan helpful for you
本文标签: mobile applicationHow to create this search bar in flutterStack Overflow
版权声明:本文标题:mobile application - How to create this search bar in flutter? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744221644a2595892.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论