رونمایی از پخته‌ترین و کاربردی‌ترین محصولات آموزشی سون‌لرن با کلی آفرهای ویژه🔥
۰ ثانیه
۰ دقیقه
۰ ساعت
۴ عليرضا سیریزی
SearchScreen
جامعه فلاتر ایجاد شده در ۳۰ خرداد ۱۴۰۲

سلام وقت بخیر

من میخوام یک صفحه سرچ بزنم که با تغیر مقدار داخل یک تکس فیلد درخواستی یه سرور بفرسته و لیست کتاب هارو بگیره با ارگومنت onChanged استفاده میکنم مشکلی که هست وقتی متن داخل تکس فیلد رو پاک میکنم باید EmptyStateنشون بده ولی یک لیست نشون میده چون موقع پاک کردن بازم درخواست میفرسته و یکم طول میکشه تا جواب درخواست‌ها بیاد وزمانی که جواب درخواست میا یک SuccessStateمیفرسته

اگه راه حلی بهم بدین ممنون میشم

class SearchScreen extends StatefulWidget {
  const SearchScreen({super.key});
  @override
  State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
  final TextEditingController _searchControler = TextEditingController();
   SearchBloc? searchBloc;
   @override
  void dispose() {
    // TODO: implement dispose
    searchBloc?.close();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: BlocProvider<SearchBloc>(
        create: (context) {
          final bloc = SearchBloc(bookRepo)..add(SearchStarted());
          searchBloc=bloc;
          return bloc;
        },
        child: Scaffold(
          body: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              Container(
                decoration: BoxDecoration(
                  color: Theme.of(context).dividerColor,
                ),
                width: MediaQuery.of(context).size.width,
                height: 75,
                child: Row(
                  children: [
                    Expanded(
                      child: Container(
                        decoration: BoxDecoration(
                          color: LiightThemeColors.secondaryTextColor
                              .withOpacity(0.4),
                          borderRadius: BorderRadius.circular(5),
                        ),
                        height: 56,
                        margin: const EdgeInsets.fromLTRB(12, 0, 12, 0),
                        child: TextField(
                          controller: _searchControler,
                          onChanged: (value) {
                            searchBloc!.add(SearchChangeSearchTerm(value));
                          },
                          // textInputAction: TextInputAction.search,
                          decoration: InputDecoration(
                            labelText: 'جستجو',
                            enabledBorder: const OutlineInputBorder(
                                borderSide: BorderSide.none),
                            focusedBorder: const OutlineInputBorder(
                                borderSide: BorderSide.none),
                            prefixIcon: IconButton(
                                onPressed: () {},
                                icon: const Padding(
                                  padding: EdgeInsets.only(right: 8.0),
                                  child: Icon(CupertinoIcons.search),
                                )),
                            floatingLabelBehavior: FloatingLabelBehavior.never,
                          ),
                        ),
                      ),
                    ),
                    Container(
                        margin: const EdgeInsets.only(left: 12),
                        child: GestureDetector(
                          child:
                              SvgPicture.asset('assets/icons/library_icon.svg'),
                          onTap: () {},
                        ))
                  ],
                ),
              ),
              BlocBuilder<SearchBloc, SearchState>(
                builder: (context, state) {
                  return Expanded(
                      child: state is SerchSuccessState
                          ? _BookList(bookList: state.bookList)
                          : state is SearchEmptyState
                              ? Center(child: Text(state.text))
                              : state is SearchErrorState
                                  ? const Center(
                                      child: Text("error"),
                                    )
                                  : state is SearchLoadingState
                                      ? const Center(
                                          child: CupertinoActivityIndicator(),
                                        )
                                      : throw Exception('not supported'));
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}
class _BookList extends StatelessWidget {
  const _BookList({super.key, required this.bookList});
  final List<BookEntity2> bookList;
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: bookList.length,
        itemBuilder: (context, index) {
          return Container(
            width: MediaQuery.of(context).size.width,
            height: 80,
            child: Text(bookList[index].name),
          );
        });
  }
}

کد‌های bloc

class SearchBloc extends Bloc<SearchEvent, SearchState> {
  final IBookRepository bookRepository;
  SearchBloc(this.bookRepository) : super(SearchLoadingState()) {
    on<SearchEvent>((event, emit) async {
      if (event is SearchStarted) {
        emit(SearchLoadingState());
        emit(SearchEmptyState('کتاب مورد نظر را جستجو کنید'));
      } else if (event is SearchChangeSearchTerm) {
        if(event.searchTerm.isNotEmpty){
          emit(SearchLoadingState());
        try {
          final bookList =
              await bookRepository.searchForDownload(event.searchTerm);
          emit(SerchSuccessState(bookList));
        } catch (e) {
          emit(SearchErrorState());
        }
        }else{
          emit(SearchEmptyState('کتاب مورد نظر را سرچ کنید'));
        }
        
      }
    });
  }
}

سلام. خالی بودن پاسخ که بررسی نشده؛ باید چک بشه و به اون صورت هندلش کنید.

یلدا محصلی ۰۲ تیر ۱۴۰۲، ۲۱:۰۵

سلام بله این مورد هم باید اضافه بشه

ولی مشکلی که من میگم اینه که با هر بار تغییر کردن value داخل onchenged یک درخواست میره سمت سرور به همین ترتیب موقع پاک کردن هم پشت سر هم درخواست میره که عمل پسندیده ای نیست :)

تو کلاس بلاک من شرط emptystateرو گزاشتم رویsearchterm ورودی,اگر خالی بود دیگه درخواست به سرور رو نفرسته و empty stateرو نشون بده

حالا بعد اینکه emptystate نشون داده شده, جواب درخواست‌های قبلی از سرور میاد این باعث میشه state succes نشون کاربر بده


عليرضا سیریزی ۰۳ تیر ۱۴۰۲، ۰۹:۲۶

میتونید تغییرات رو به ازای هر چندتا کاراکتر انجام بدید. مثلا اگه باقیمانده طول رشته بر ۳ صفر بود درخواست بده. (یا هر عددی)

یه روش دیگه این هست که از تابع onSubmitted استفاده کنید. البته با کلیک دکمه کیبورد تابع فراخوانی میشه.

یلدا محصلی ۰۳ تیر ۱۴۰۲، ۱۱:۰۸

در روش اول که فرمودید یعنی اینکه به ازای هر سه تا تغییر درخواست بده بازم اگه طول رشته زیاد باشه همین اتفاق میوفته یعنی اینکه کاربر دکمه دیلیت رو نگه تا را تمام متن پاک بشه بازم سه تا تغییر یک درخواست میره

این فیچر Real Time Search در اپ هایی مثل طاقچه(صفحه جستجو) چطور پیاده سازی شدن ؟

عليرضا سیریزی ۰۳ تیر ۱۴۰۲، ۱۱:۴۷