I’ve to implement search performance in Flutter throughout a number of backside navigation pages and inside every navigation web page we have now a number of tabs.
One search bar needs to be used and has to show completely different outcomes throughout a number of pages.
I’ve 4 pages on the underside navbar,
- OrdersScreen
- ProductScreen
- Favorite
- Profile
I am utilizing the search performance on OrdersScreen and ProductScreen.
With a customScaffold throughout all of the pages (the scaffold features a menuDrawer button, brand of the App and searchButton upon which a person clicks to open the searchBar and an expandable widget which is the precise content material of every web page).
ProductScreen has 2 tabs,
- Record of Merchandise
- Stock of Merchandise
Equally OrdersScreen has 5-6 tabs,
- All Orders
- Unfulfilled Orders
- … so on
After I write any factor within the search bar even a letter, it should name the fetchData methodology of the respective tab.
And if the person faucets anyplace on the display screen the searchbar and the info that is been up to date ought to reset.
I’m utilizing GetX for State Administration.
Now my query is,
Ought to I deal with Search Bar like this ? (as I’ve defined) OR Ought to I deal with it in a different way like making a separate web page for Search Performance? (On this case how would I deal with the info as a result of every web page has completely different playing cards, completely different formatted knowledge).
I can share the code I’ve written to this point if somebody must look into it.
ORDERS SCREEN
import 'bundle:flutter/materials.dart';
import 'bundle:flutter_screenutil/flutter_screenutil.dart';
import 'bundle:get/get.dart';
import '../../Controllers/search_controller.dart';
import '../../Widgets/custom_search_scaffold.dart';
import '../../Widgets/search_button.dart';
class OrdersScreen extends StatefulWidget {
OrdersScreen({Key? key}) : tremendous(key: key);
@override
State<OrdersScreen> createState() => _OrdersScreenState();
}
class _OrdersScreenState extends State<OrdersScreen>
{
ultimate GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
ultimate orderController = Get.put(OrderController());
ultimate searchController = Get.discover<SearchController>();
Future<void> handleTabSelection() async {
searchController.searchBoxWidth.worth = 0.sw;
if (searchController.searchText.worth.textual content.isNotEmpty) {
print("searchText is just not empty right here");
searchController.searchText.worth.clear();
searchController.handleTabSelectionOrders(
closeSearch: true,
standing: orderController.tabController.index == 0
? null
: orderController.tabController.index == 1
? 0
: orderController.tabController.index == 2
? 1
: orderController.tabController.index == 3
? 4
: orderController.tabController.index == 4
? 3
: orderController.tabController.index == 5
? 9
: null);
}
}
@override
void initState() {
searchController.operation?.cancel();
orderController.tabController.addListener(handleTabSelection);
tremendous.initState();
}
@override
Widget construct(BuildContext context) {
return GestureDetector(
onTap: () {
searchController.closeOrdersSearchBar(
tabIndex: orderController.tabController.index == 0
? null
: orderController.tabController.index == 1
? 0
: orderController.tabController.index == 2
? 1
: orderController.tabController.index == 3
? 4
: orderController.tabController.index == 4
? 3
: orderController.tabController.index == 5
? 9
: null);
},
little one: CustomSearchScaffold(
scaffoldKey: _scaffoldKey,
searchable: true,
expandedChild: Expanded(
little one: Column(
kids: [
SizedBox(
height: 6.h,
),
CustomSearchWidget(
onSearch: () async {
if (searchController.searchBoxWidth.value == 0.sw) {
searchController.increaseWidthOfSearchBox();
} else if (searchController.searchText.value.text.isEmpty) {
print("ORDER SEARCH TEXT IS NULL");
} else {
await searchController.getSearchResult(first: true, pageName: 'ORDER_SCREEN');
}
},
onChange: (value) async {
await searchController.cancelWaiting();
await searchController.startWaiting(textValue: value, pageName: "ORDER_SCREEN");
},
onClose: () async {
Get.find<SearchController>().searchBoxWidth.value != 0.sw ?
await searchController.closeOrdersSearchBar() : null;
},
hint: "Search Order...",
),
Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: TabBar(
controller: orderController.tabController,
onTap: (index) {
searchController.searchText.value.clear();
},
isScrollable: true,
labelPadding: EdgeInsets.symmetric(horizontal: 8.w),
indicatorSize: TabBarIndicatorSize.tab,
labelColor: Constants.TextBlack,
unselectedLabelColor: Constants.TextBlack,
indicatorWeight: 3.h,
indicatorColor: Constants.BackgroundBlue,
labelStyle: ThemeStyles.NormalBold,
tabs: [
Tab(
child: Text('All', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Unfulfilled', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Fulfilled', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Partially Refunded', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Refunded', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Hold', style: ThemeStyles.NormalBold),
),
],
),
),
SizedBox(peak: 4.h),
Expanded(
little one: TabBarView(
controller: orderController.tabController,
kids: const [
AllOrdersView(),
AllOrdersView(status: 0),
AllOrdersView(status: 1),
AllOrdersView(status: 4),
AllOrdersView(status: 3),
AllOrdersView(status: 9),
],
),
),
],
),
),
),
);
}
}
PRODUCTS SCREEN
import 'bundle:flutter/materials.dart';
import 'bundle:flutter_screenutil/flutter_screenutil.dart';
import 'bundle:flutter_svg/svg.dart';
import 'bundle:get/get.dart';
import 'bundle:async/async.dart';
import '../../Controllers/inventory_controller.dart';
import '../../Controllers/product_controller.dart';
import '../../Controllers/search_controller.dart';
import '../../Widgets/custom_search_scaffold.dart';
class ProductsScreen extends StatefulWidget {
const ProductsScreen({Key? key}) : tremendous(key: key);
@override
State<ProductsScreen> createState() => _ProductsScreenState();
}
class _ProductsScreenState extends State<ProductsScreen> with SingleTickerProviderStateMixin {
ultimate GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
ultimate productController = Get.put(ProductScreenController());
ultimate prodController = Get.put(ProductController());
ultimate inventoryController = Get.put(InventoryScreenController());
ultimate searchController = Get.discover<SearchController>();
Future<void> handleTabSelection() async {
searchController.searchBoxWidth.worth = 0.sw;
if (searchController.searchText.worth.textual content.isNotEmpty) {
print("searchText is just not empty right here");
searchController.searchText.worth.clear();
searchController.handleTabSelectionProducts(closeSearch: true, tabIndex: productController.tabController.index == 0 ? 1 : 0);
}
}
@override
void initState() {
productController.clicked.worth = false;
productController.tabController = TabController(size: 2, vsync: this, initialIndex: 0);
productController.tabController.addListener(handleTabSelection);
tremendous.initState();
}
@override
Widget construct(BuildContext context) {
return GestureDetector(
onTap: () {
Get.discover<SearchController>().searchBoxWidth.worth != 0.sw ?
searchController.closeProductsSearchBar() : null;
},
little one: CustomSearchScaffold(
scaffoldKey: _scaffoldKey,
searchable: true,
expandedChild: Expanded(
little one: Column(
kids: [
SizedBox(
height: 6.h,
),
CustomSearchWidget(
onSearch: () async {
if (searchController.searchBoxWidth.value == 0.sw) {
searchController.increaseWidthOfSearchBox();
} else if (searchController.searchText.value.text.isEmpty) {
print("PRODUCT SEARCH TEXT IS NULL");
} else {
await searchController.getSearchResult(first: true, pageName: 'PRODUCT_SCREEN');
}
},
onChange: (value) {
searchController.cancelWaiting();
searchController.startWaiting(textValue: value, pageName: "PRODUCT_SCREEN");
},
onClose: () {
Get.find<SearchController>().searchBoxWidth.value != 0.sw ?
searchController.closeProductsSearchBar() : null;
},
hint: "Search Products...",
),
Theme(
data: ThemeData(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: TabBar(
controller: productController.tabController,
isScrollable: false,
labelPadding: EdgeInsets.symmetric(horizontal: 4.w),
indicatorSize: TabBarIndicatorSize.tab,
labelColor: Constants.TextBlack,
unselectedLabelColor: Constants.TextBlack,
indicatorWeight: 3.h,
indicatorColor: Constants.BackgroundBlue,
labelStyle: ThemeStyles.NormalBold,
tabs: [
Tab(
child: Text('List', style: ThemeStyles.NormalBold),
),
Tab(
child: Text('Inventory', style: ThemeStyles.NormalBold),
),
],
),
),
Expanded(
little one: TabBarView(
controller: productController.tabController,
kids: [
ListScreen(),
InventoryScreen(),
],
),
),
],
),
),
),
);
}
}
CUSTOM SEARCH SCAFFOLD
import 'bundle:flutter/materials.dart';
import 'bundle:flutter_screenutil/flutter_screenutil.dart';
import 'bundle:flutter_svg/svg.dart';
import 'bundle:get/get.dart';
import '../Controllers/search_controller.dart';
import 'menu_drawer.dart';
typedef SearchCallback = Operate()?;
class CustomSearchScaffold extends StatefulWidget {
ultimate Widget? expandedChild;
ultimate Widget? mainLogo;
GlobalKey<ScaffoldState>? scaffoldKey;
ultimate bool? searchable;
ultimate SearchCallback onSearch;
CustomSearchScaffold({Key? key, this.scaffoldKey, this.expandedChild, this.mainLogo, this.searchable, this.onSearch}) : tremendous(key: key);
@override
State<CustomSearchScaffold> createState() => _CustomSearchScaffoldState();
}
class _CustomSearchScaffoldState extends State<CustomSearchScaffold> {
ultimate searchController = Get.put(SearchController());
ultimate orderController = Get.discover<OrderController>();
@override
void initState() {
tremendous.initState();
}
@override
Widget construct(BuildContext context) {
return Scaffold(
key: widget.scaffoldKey,
backgroundColor: Constants.BackgroundPrimary,
drawer: MenuDrawer(),
drawerScrimColor: Colours.black.withOpacity(0.2),
physique: Container(
padding: EdgeInsets.fromLTRB(16.w, Get.width > 600 ? 8.h : 4.h, 16.w, 0),
little one: Column(
crossAxisAlignment: CrossAxisAlignment.begin,
kids: [
const SafeArea(child: SizedBox()),
Expanded(
child: Stack(
fit: StackFit.loose,
children: [
SizedBox(
width: 0.4.sw,
child: Row(
children: [
/// ******* menu drawer *******
GestureDetector(
onTap: () async {
if (Get.find<SearchController>().searchBoxWidth.value != 0.sw) {
await Get.find<SearchController>().closeProductsSearchBar();
await Get.find<SearchController>().closeOrdersSearchBar(
tabIndex: orderController.tabController.index == 0
? null
: orderController.tabController.index == 1
? 0
: orderController.tabController.index == 2
? 1
: orderController.tabController.index == 3
? 4
: orderController.tabController.index == 4
? 3
: orderController.tabController.index == 5
? 9
: null);
}
widget.scaffoldKey!.currentState!.openDrawer();
},
child: SizedBox(
width: Get.width > 600 ? 20.w : 26.w,
height: Get.width > 600 ? 30.h : 26.h,
child: SvgPicture.asset(
Constants.drawer,
color: Colors.black,
// size: 30.w,
),
),
),
SizedBox(width: Get.width > 600 ? 14.w : 20.w),
],
),
),
Column(
kids: [
widget.expandedChild!,
],
),
],
),
),
],
),
),
);
}
}
SEARCH BUTTON
import 'bundle:flutter/materials.dart';
import 'bundle:flutter_screenutil/flutter_screenutil.dart';
import 'bundle:flutter_svg/svg.dart';
import 'bundle:get/get.dart';
import '../Constants/constants.dart';
import '../Constants/theme_styles.dart';
import '../Controllers/search_controller.dart';
typedef SearchCallback = Operate()?;
typedef ValueChangedCallBack = void Operate(String)?;
class CustomSearchWidget extends StatefulWidget {
ultimate String? trace;
ultimate SearchCallback onSearch;
ultimate SearchCallback onClose;
ultimate ValueChangedCallBack onChange;
const CustomSearchWidget({Key? key, this.onSearch, this.onClose, this.onChange, this.trace}) : tremendous(key: key);
@override
_CustomSearchWidgetState createState() => _CustomSearchWidgetState();
}
class _CustomSearchWidgetState extends State<CustomSearchWidget> {
ultimate searchController = Get.discover<SearchController>();
@override
Widget construct(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).dimension.width,
little one: Obx(
() => Row(
mainAxisAlignment: MainAxisAlignment.finish,
kids: [
AnimatedContainer(
alignment: Alignment.center,
width: searchController.searchBoxWidth.value,
height: 33.h,
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
color: Constants.backgroundColor,
borderRadius: BorderRadius.circular(0),
),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// ********** Close Button *********
GestureDetector(
onTap: widget.onClose,
child: Padding(
padding: const EdgeInsets.only(left: 6.0),
child: Container(
width: 0.075.sw,
height: 33.h,
alignment: Alignment.center,
child: Icon(
Icons.close,
color: Colors.grey,
size: 20.h,
),
),
),
),
// ********* Search Text Field *********
SizedBox(
width: 0.63.sw,
child: Theme(
data: Theme.of(context).copyWith(
primaryColor: Colors.black,
),
child: TextFormField(
focusNode: searchController.focusNodeSearch.value,
controller: searchController.searchText.value,
decoration: ThemeStyles.inputDecorationNoBorder.copyWith(
hintText: widget.hint ?? 'Search...',
contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 7),
),
onChanged: widget.onChange,
),
),
),
],
),
),
),
GestureDetector(
onTap: widget.onSearch,
little one: Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w),
little one: SizedBox(
width: 20.w,
peak: 20.w,
little one: SvgPicture.asset(
Constants.search,
colour: Colours.black,
),
),
),
),
],
),
),
);
}
}
SEARCH CONTROLLER
import 'bundle:flutter/cupertino.dart';
import 'bundle:flutter_screenutil/flutter_screenutil.dart';
import 'bundle:get/get.dart';
import 'bundle:async/async.dart';
import '../Fashions/search_query_model.dart';
import 'inventory_controller.dart';
import 'orders_controller.dart';
class SearchController extends GetxController {
var searchText = TextEditingController().obs;
var productController = Get.put(ProductController());
var productScreenController = Get.put(ProductScreenController());
var orderScreenController = Get.put(OrderController());
var inventoryController = Get.put(InventoryScreenController());
var searchPhrase="".obs;
var isLoading = false.obs;
var isLoadingFirst = false.obs;
var web page = 1.obs;
var totalPage = 0.obs;
var searchModel = SearchQueryModel().obs;
var searchList = [].obs;
var searchProductString = ''.obs;
var searchBoxWidth = 0.sw.obs;
var tabIndex = 0.obs;
var focusNodeSearch = FocusNode().obs;
CancelableOperation? operation;
Future<void> getSearchResult({bool? first, String? pageName}) async {
if (pageName == 'PRODUCT_SCREEN'){
await handleTabSelectionProducts();
} else if (pageName == 'ORDER_SCREEN'){
await handleTabSelectionOrders();
}
}
void increaseWidthOfSearchBox() {
searchBoxWidth.worth == 0.7.sw ? searchBoxWidth.worth = 0.sw : searchBoxWidth.worth = 0.7.sw;
}
@override
void onInit() {
tremendous.onInit();
}
Future<void> handleTabSelectionProducts({bool? closeSearch, int? tabIndex}) async {
if (tabIndex == null){
if (productScreenController.tabController.index == 0) {
print("index is 0 in product");
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
if (productController.filterIndex.worth <= 6) {
await productController.fetchProductsList(
isFirst: true,
standing: productController.filterIndex.worth,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 7) {
await productController.fetchProductsList(
isFirst: true,
standing: 10,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 8) {
await productController.fetchProductsList(
isFirst: true,
standing: 11,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 9) {
await productController.fetchProductsList(
isFirst: true,
standing: 12,
searchTerm: searchText.worth.textual content,
);
}
}
} else {
await inventoryController.fetchInventoryList(isFirst: true, searchTerm: searchText.worth.textual content);
}
} else {
if (tabIndex == 0) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
if (productController.filterIndex.worth <= 6) {
await productController.fetchProductsList(
isFirst: true,
standing: productController.filterIndex.worth,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 7) {
await productController.fetchProductsList(
isFirst: true,
standing: 10,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 8) {
await productController.fetchProductsList(
isFirst: true,
standing: 11,
searchTerm: searchText.worth.textual content,
);
} else if (productController.filterIndex.worth == 9) {
await productController.fetchProductsList(
isFirst: true,
standing: 12,
searchTerm: searchText.worth.textual content,
);
}
}
} else {
await inventoryController.fetchInventoryList(isFirst: true, searchTerm: searchText.worth.textual content);
}
}
}
Future<void> handleTabSelectionOrders({bool? closeSearch, int? standing}) async {
if (standing == null && closeSearch == null){
if (orderScreenController.tabController.index == 0) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchAllOrdersList(isFirst: true, searchTerm: searchText.worth.textual content);
}
} else if (orderScreenController.tabController.index == 1) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 0);
}
} else if (orderScreenController.tabController.index == 2) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 1);
}
} else if (orderScreenController.tabController.index == 3) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 4);
}
} else if (orderScreenController.tabController.index == 4) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 3);
}
} else if (orderScreenController.tabController.index == 5) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 9);
}
}
} else {
if (standing == null && closeSearch == true) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchAllOrdersList(isFirst: true, searchTerm: searchText.worth.textual content);
}
} else if (standing == 0) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 0);
}
} else if (standing == 1) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 1);
}
} else if (standing == 4) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 4);
}
} else if (standing == 3) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 3);
}
} else if (standing == 9) {
if (searchBoxWidth.worth != 0.sw || closeSearch != null) {
await Get.discover<OrderController>().fetchOrdersList(isFirst: true, searchTerm: searchText.worth.textual content, standing: 9);
}
}
}
}
Future<void> startWaiting({String? textValue, String? pageName}) async {
await operation?.cancel();
operation = CancelableOperation.fromFuture(
Future.delayed(const Period(seconds: 2)).then((worth) async {
await getSearchResult(first: true, pageName: pageName);
}),
);
await operation?.worth.then((worth) {
print("Waited 1 seconds");
}).catchError((error) {
});
}
Future<void> cancelWaiting() async {
await operation?.cancel();
}
Future<void> closeProductsSearchBar() async {
focusNodeSearch.worth.unfocus();
searchBoxWidth.worth = 0.sw;
if (searchText.worth.textual content.isNotEmpty) {
print("searchText is just not empty");
searchText.worth.clear();
await handleTabSelectionProducts(closeSearch: true);
}
}
Future<void> closeOrdersSearchBar({int? tabIndex}) async {
focusNodeSearch.worth.unfocus();
searchBoxWidth.worth = 0.sw;
if (searchText.worth.textual content.isNotEmpty) {
print("searchText is just not empty");
searchText.worth.clear();
await handleTabSelectionOrders(closeSearch: true, standing: tabIndex);
}
}
@override
void onClose() {
searchBoxWidth.worth = 0.1.sw;
tremendous.onClose();
}
}
Thus far this code appears to work on Product Display screen however after I apply it to Orders Display screen it nonetheless masses the onChange methodology of the Product Display screen.
Please information me.