#flutter #dart
Вопрос:
У меня есть два построителя представления списка, как показано на рисунке ниже, полученном из магазина fire:
Ошибка при попытке получить конкретный список элементов, и это ошибка ниже:
RangeError (index): Invalid value: Valid value range is empty: 4
When the exception was thrown, this was the stack:
#0 List.[] (dart:core-patch/growable_array.dart:254:60)
#1 AppCubit.changeCategoryModelState (package:ipet/shared/cubit/cubit.dart:116:35)
#2 CategoriesScreen.buildPetsCategoryItem.<anonymous closure>.<anonymous closure> (package:ipet/modules/categories/categories_screen.dart:97:43)
#3 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
#4 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:607:11)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#0916b
debugOwner: GestureDetector
state: ready
won arena
finalPosition: Offset(272.1, 219.8)
finalLocalPosition: Offset(51.1, 42.8)
button: 1
sent tap down
So I want to when click on item from buildPetsCategoryItem()
just Change the buildCategoriesListView()
So what is the best way to do this…
This is the below code:
return SingleChildScrollView(
controller: cubit.scrollController,
physics: BouncingScrollPhysics(),
child: Column(
children: [
SizedBox(
height: 30,
),
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: CustomText(
text: "Categories",
),
),
SizedBox(
height: 30,
),
// buildCategoryItem(context),
buildPetsCategoryItem(context),
buildCategoriesListView(cubit)
],
),
);
to be more clear I have this below categoriesBuilder:
Widget buildPetsCategoryItem(context) {
return Container(
height: 120,
child: ListView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: AppCubit.get(context).petsCategories.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
AppCubit.get(context).changePetsCategoryBorder(index);
AppCubit.get(context).changeCategoryModelState(index);
},
child: Container(
width: 60,
height: 60,
margin: EdgeInsets.symmetric(horizontal: 18),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: customShadow,
border:
AppCubit.get(context).selectedPetsCategory == index
? Border.all(
color: secondaryGreen,
width: 2,
)
: null,
borderRadius: BorderRadius.circular(20),
),
child: Image.network(
AppCubit.get(context).petsCategories[index].image,
scale: 1.8,
),
),
),
SizedBox(
height: 6,
),
Text(
AppCubit.get(context).petsCategories[index].name,
style: TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
);
},
),
);
}
and this is the CategoriesListView:
ListView buildCategoriesListView(AppCubit cubit) {
return ListView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
// scrollDirection: Axis.horizontal,
itemCount: cubit.currentCategoryPets.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
navigateTo(
context,
DetailsScreen(
pets: cubit.currentCategoryPets[index],
),
);
},
child: Container(
margin: EdgeInsets.symmetric(vertical: 5),
child: PetCard(
petId: cubit.currentCategoryPets[index].id,
petName: cubit.currentCategoryPets[index].name,
age: cubit.currentCategoryPets[index].age,
breed: cubit.currentCategoryPets[index].petType,
gender: cubit.currentCategoryPets[index].gender,
distance: cubit.currentCategoryPets[index].distance,
imagePath: cubit.currentCategoryPets[index].image,
),
),
);
},
);
}
as I have both methods which get the PetsModel
data for each category one gets all the pets, and the other get the Cats one:
List<PetsModel> pets = [];
List<PetsModel> cats = [];
void getPetsData() {
FirebaseFirestore.instance.collection('pets').get().then((value) {
value.docs.forEach((element) {
pets.add(PetsModel.fromJson(element.data()));
});
emit(AppGetPetsSuccessState());
}).catchError((error) {
emit(AppGetPetsErrorState(error.toString()));
});
}
void getCatsData() {
FirebaseFirestore.instance.collection('pets').where('type', isEqualTo: 'cat').get().then((value) {
value.docs.forEach((element) {
cats.add(PetsModel.fromJson(element.data()));
});
emit(AppGetPetsSuccessState());
}).catchError((error) {
emit(AppGetPetsErrorState(error.toString()));
});
}
I tried to create a method that changes the Category Model State
as the below one:
PetsModel petModel;
List<PetsModel> currentCategoryModel = [];
void changeCategoryModelState(int position) {
petModel = currentCategoryPets[position];
if (position == 4) getPetsData();
if (position == 5) getCatsData();
emit(AppChangeCategoryModelState());
}
this is the main class which contains the BlocProvider:
return BlocProvider(
create: (BuildContext context) => AppCubit()
..getUserData()
..getCategoriesData()
..getPetsData()
..getCatsData()
..handleScroll(),
child: BlocConsumer<AppCubit, AppStates>(...),);
for more infos this is the pet card widget:
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
// final randomColor = colors[_random.nextInt(colors.length)];
return Container(
margin: EdgeInsets.symmetric(horizontal: 20),
height: 240,
child: Stack(
children: [
Container(
// height: 200,
margin: EdgeInsets.only(
top: 70,
bottom: 20,
),
child: Row(
children: [
Container(
width: size.width * 0.48,
),
Expanded(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomText(
text: petName,
fontSize: 20,
fontWeight: FontWeight.bold,
maxLine: 1,
overflow: TextOverflow.ellipsis,
),
Icon(
gender == 'female'
? FontAwesomeIcons.venus
: FontAwesomeIcons.mars,
size: 18,
color: Colors.black54,
)
],
),
Text(
breed,
style: TextStyle(
fontSize: 12,
color: fadedBlack,
fontWeight: FontWeight.bold,
),
),
CustomText(
text: age ' years',
fontSize: 12,
color: fadedBlack,
),
Row(
children: [
Icon(
Icons.location_pin,
size: 16,
color: primaryGreen,
),
SizedBox(
width: 5,
),
CustomText(
text: 'Distance: ' distance ' Km',
fontSize: 12,
color: fadedBlack,
),
],
)
],
),
),
)
],
),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: customShadow,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
bottomRight: Radius.circular(20),
),
),
),
Container(
width: size.width * 0.48,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor,
boxShadow: customShadow,
borderRadius: BorderRadius.circular(22),
),
margin: EdgeInsets.only(top: 50),
),
Align(
child: Hero(
tag: petId,
child: Image.network(
imagePath,
loadingBuilder: loadingNetworkImage,
),
),
),
],
),
)
],
),
);
}
the below method is related for selectedPetsCategories()
:
int selectedPetsCategory = 0;
void changePetsCategoryBorder(int index) {
selectedPetsCategory = index;
emit(AppChangePetsCategoryBorderState());
}
Как я могу устранить эту ошибку?
Отредактированный
Итак, за предыдущую ошибку, потому что я должен добавить changeCategoryModelState()
метод init при запуске приложения в blocProvider, поэтому я сделал int position
аргумент необязательным и попытался добавить метод addAll
в качестве кода ниже:
void changeCategoryModelState({int position}) {
petModel = currentCategoryPets[position];
if (position == 4) getPetsData();
if (position == 5) getCatsData();
currentCategoryPets.addAll(pets);
emit(AppChangeCategoryModelState());
}
и назвал его в основном, как показано ниже, кодом:
return BlocProvider(
create: (BuildContext context) => AppCubit()
..getUserData()
..getCategoriesData()
..getPetsData()
..getCatsData()
..changeCategoryModelState()
..handleScroll(),
child: BlocConsumer<AppCubit, AppStates>(...),);
Я обнаружил следующую ошибку:
E/flutter ( 4506): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 2651 pos 20: '_debugCurrentBuildTarget == context': is not true.
E/flutter ( 4506): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
The following assertion was thrown attaching to the render tree:
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4191 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
When the exception was thrown, this was the stack:
#2 Element.rebuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4191:14)
#3 Element.rebuild (package:flutter/src/widgets/framework.dart:4194:6)
#4 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4474:5)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4469:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3541:14)
Комментарии:
1. Разве
currentCategoryPets
список не пуст при первомchangeCategoryModelState()
звонке?2. @mkobuolys нет, я еще не пытался вызвать его, пока не создам другие методы, я просто хочу увидеть результат, так как другие категории в firestore также являются emty, предполагается, что категория » Все » — это позиция 4, а кошка-одна позиция 5
3. И что происходит внутри
AppCubit.get(context).changePetsCategoryBorder(index);
илиAppCubit.get(context).changeCategoryModelState(index);
?4. @mkobuolys первый метод изменяет радиус границы при выборе элемента, а другой метод должен дать мне модель категории, которую я выбираю
5. Так, может быть, второй метод вызывает элемент с индексом, который находится вне диапазона?
Ответ №1:
Это правильный ответ, тогда просто удалите аргументы и обновите changeCategoryModelState
метод до:
void changeCategoryModelState() {
if (selectedPetsCategory == 5) {
currentCategoryPets.clear();
currentCategoryPets.addAll(cats);
print(selectedPetsCategory.toString());
}
else if (selectedPetsCategory == 4) {
currentCategoryPets.clear();
currentCategoryPets.addAll(pets);
print(selectedPetsCategory.toString());
}
emit(AppChangeCategoryModelState());
}