英文:
Flutter how to put Pageview.builder inside GridView.count properly?
问题
我尝试使用扩展小部件和其他方法来解决这个问题,但我真的不知道如何解决这个错误...非常感谢大家的帮助👍;
这是我遇到的错误:
异常已发生。FlutterError(水平视口被赋予无限宽度。视口在滚动方向上扩展以填充其容器。在这种情况下,水平视口被赋予了无限量的水平空间来扩展。这种情况通常发生在可滚动小部件嵌套在另一个可滚动小部件内的情况下。如果此小部件始终嵌套在可滚动小部件内,就无需使用视口,因为子项始终有足够的水平空间。在这种情况下,考虑改用Row或Wrap。否则,考虑使用CustomScrollView将任意sliver连接成单个可滚动。)
网格代码:
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
padding: EdgeInsets.fromLTRB(0, 13, 0, 30),
childAspectRatio: size.width / (size.height * 0.59),
children: List.generate(allProducts.length, (index) {
return ChangeNotifierProvider.value(
value: allProducts[index],
child: Container(child: const FeedsWidget()));
}),
),
PageView.builder 代码:
PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: productModel.imageUrl!.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FancyShimmerImage(
height: size.width * 0.28,
width: size.width * 0.38,
imageUrl: productModel.imageUrl![index],
boxFit: BoxFit.fill,
),
);
}),
这是我的完整代码:
class FeedsScreen extends StatefulWidget {
static const routeName = "/FeedsScreenState";
const FeedsScreen({Key? key}) : super(key: key);
@override
State<FeedsScreen> createState() => _FeedsScreenState();
}
class _FeedsScreenState extends State<FeedsScreen> {
// 其他部分的代码...
}
class FeedsWidget extends StatefulWidget {
static const routeName = "/feedItemsSc";
const FeedsWidget({Key? key}) : super(key: key);
@override
State<FeedsWidget> createState() => _FeedsWidgetState();
}
class _FeedsWidgetState extends State<FeedsWidget> {
// 其他部分的代码...
}
希望这些信息对你有所帮助。
英文:
I tried using expanded widget and other ways to solve this but I really don't know how to solve this error.. Thank you very much for the help everyone 👍
This is the error i get :
> Exception has occurred. FlutterError (Horizontal viewport was given
> unbounded width. Viewports expand in the scrolling direction to fill
> their container. In this case, a horizontal viewport was given an
> unlimited amount of horizontal space in which to expand. This
> situation typically happens when a scrollable widget is nested inside
> another scrollable widget. If this widget is always nested in a
> scrollable widget there is no need to use a viewport because there
> will always be enough horizontal space for the children. In this case,
> consider using a Row or Wrap instead. Otherwise, consider using a
> CustomScrollView to concatenate arbitrary slivers into a single
> scrollable.)
grid code:
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
padding: EdgeInsets.fromLTRB(0, 13, 0, 30),
// crossAxisSpacing: 10,
childAspectRatio: size.width / (size.height * 0.59),
children: List.generate(allProducts.length, (index) {
return ChangeNotifierProvider.value(
value: allProducts[index],
child: Container(child: const FeedsWidget()));
}),
),
Pageview.builder code:
PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: productModel.imageUrl!.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FancyShimmerImage(
height: size.width * 0.28,
width: size.width * 0.38,
imageUrl: productModel.imageUrl![index],
boxFit: BoxFit.fill,
),
);
}),
This is my full code:
class FeedsScreen extends StatefulWidget {
static const routeName = "/FeedsScreenState";
const FeedsScreen({Key? key}) : super(key: key);
@override
State<FeedsScreen> createState() => _FeedsScreenState();
}
class _FeedsScreenState extends State<FeedsScreen> {
final TextEditingController? _searchTextController = TextEditingController();
final FocusNode _searchTextFocusNode = FocusNode();
@override
void dispose() {
_searchTextController!.dispose();
_searchTextFocusNode.dispose();
super.dispose();
}
@override
void initState() {
final productsProvider =
Provider.of<ProductsProvider>(context, listen: false);
productsProvider.fetchProducts();
super.initState();
}
@override
Widget build(BuildContext context) {
final productsProvider = Provider.of<ProductsProvider>(context);
List<ProductModel> allProducts = productsProvider.getProducts;
final Color color = Utils(context).color;
Size size = Utils(context).getScreenSize;
return Scaffold(
appBar: AppBar(
leading: const BackWidget(),
elevation: 0,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
centerTitle: true,
title: vTextWidget(
text: 'All Products',
color: color,
textSize: 20.0,
isTitle: true,
fontWeight: FontWeight.bold,
),
),
body: SingleChildScrollView(
child: Column(children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
height: kBottomNavigationBarHeight,
child: TextField(
focusNode: _searchTextFocusNode,
controller: _searchTextController,
onChanged: (valuee) {
setState(() {});
},
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide:
const BorderSide(color: Colors.greenAccent, width: 1),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide:
const BorderSide(color: Colors.greenAccent, width: 1),
),
hintText: "What's in your mind",
prefixIcon: const Icon(Icons.search),
suffix: IconButton(
onPressed: () {
_searchTextController!.clear();
_searchTextFocusNode.unfocus();
},
icon: Icon(
Icons.close,
color: _searchTextFocusNode.hasFocus ? Colors.red : color,
),
),
),
),
),
),
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
padding: EdgeInsets.fromLTRB(0, 13, 0, 30),
// crossAxisSpacing: 10,
childAspectRatio: size.width / (size.height * 0.59),
children: List.generate(allProducts.length, (index) {
return ChangeNotifierProvider.value(
value: allProducts[index],
child: Container(child: const FeedsWidget()));
}),
),
]),
),
);
}
}
and the widget page full code:
class FeedsWidget extends StatefulWidget {
static const routeName = "/feedItemsSc";
const FeedsWidget({Key? key}) : super(key: key);
@override
State<FeedsWidget> createState() => _FeedsWidgetState();
}
class _FeedsWidgetState extends State<FeedsWidget> {
final _quantityTextController = TextEditingController();
@override
void initState() {
_quantityTextController.text = '1';
super.initState();
}
@override
void dispose() {
_quantityTextController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final themeState = Provider.of<DarkThemeProvider>(context);
final productModel = Provider.of<ProductModel>(context);
final cartProvider = Provider.of<CartProvider>(context);
final wishlistProvider = Provider.of<WishlistProvider>(context);
bool? _isInCart = cartProvider.getCartItems.containsKey(productModel.id);
bool? _isInWishlist =
wishlistProvider.getWishlistItems.containsKey(productModel.id);
bool _isDark = themeState.getDarkTheme;
final Color color = Utils(context).color;
Size size = Utils(context).getScreenSize;
return Padding(
padding: const EdgeInsets.fromLTRB(5, 0, 8, 8),
child: Material(
borderRadius: BorderRadius.circular(12),
color: Theme.of(context).cardColor,
child: InkWell(
onTap: () {
Navigator.pushNamed(context, ProductDetails.routeName,
arguments: productModel.id);
//GlobalMethods.navigateTo(
// ctx: context, routeName: ProductDetails.routeName);
},
borderRadius: BorderRadius.circular(12),
child: Column(children: [
Flexible(
flex: 3,
child: SizedBox(
height: 300,
width: 400,
child: productModel.imageUrl == null
? Image(
height: size.width * 0.28,
width: size.width * 0.38,
fit: BoxFit.fill,
image:
AssetImage('lib/assets/images/error_image.png'),
)
: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: productModel.imageUrl!.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FancyShimmerImage(
height: size.width * 0.28,
width: size.width * 0.38,
imageUrl: productModel.imageUrl![index],
boxFit: BoxFit.fill,
),
);
}),
)),
//SizedBox(
// height: 8,
// ),
// FancyShimmerImage(
//imageUrl: productModel.imageUrl,
// height: size.width * 0.28,
// width: size.width * 0.38,
// boxFit: BoxFit.fill,
//),
SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: fTextWidget(
text: productModel.title,
maxLines: 1,
color: color,
textSize: 22,
isTitle: true,
),
),
Flexible(
flex: 1,
child: HeartBTN(
productId: productModel.id,
isInWishlist: _isInWishlist,
)),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(6, 8, 8, 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: priceWidget(
isDark: _isDark,
salePrice: productModel.discountPrice,
price: productModel.price,
textPrice: _quantityTextController.text,
isOneSale: productModel.isDiscounted ? true : false,
),
),
// const SizedBox(
// width: 10,
// ),
/* Flexible(
child: Row(
children: [
FittedBox(
child: fTextWidget(
text: 'Qty',
color: color,
textSize: 18,
isTitle: true,
),
),
const SizedBox(
width: 4,
),
Flexible(
flex: 2,
child: TextFormField(
controller: _quantityTextController,
key: const ValueKey('10'),
style: TextStyle(color: color, fontSize: 17),
keyboardType: TextInputType.number,
maxLines: 1,
decoration: InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide()),
),
textAlign: TextAlign.center,
cursorColor: Colors.green,
enabled: true,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp('[0-9.,]'),
),
],
onChanged: (value) {
setState(() {
if (value.isEmpty) {
_quantityTextController.text = '1';
} else {
// total = usedPrice *
// int.parse(_quantityTextController.text);
}
});
},
onSaved: (value) {},
),
),
],
),
),*/
],
),
),
const Spacer(),
SizedBox(
width: double.infinity,
child: TextButton(
onPressed: _isInCart
? null
: () {
final User? user = authInstance.currentUser;
if (user == null) {
GlobalMethods.errorDialog(
subtitle: 'Please Login',
vicon: Icon(Icons.error),
context: context);
return;
}
// if (_isInCart) {
// return;
// }
cartProvider.addProductsToCart(
productId: productModel.id,
quantity: int.parse(_quantityTextController.text),
);
},
child: fTextWidget(
text: _isInCart ? 'Added' : 'Add to cart',
maxLines: 1,
color: color,
textSize: 20,
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Theme.of(context).cardColor),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12.0),
bottomRight: Radius.circular(12.0),
),
),
)),
),
),
]),
),
),
);
}
}
答案1
得分: 0
我已经通过添加一个具有高度和宽度的尺寸框来解决了这个问题。因此,感谢大家的帮助,问题已经解决。
以下是我的更新后的PageView.builder代码:
child: SizedBox(
height: 120,
width: 400,
child: productModel.imageUrl == null
? Image(
height: size.width * 0.28,
width: size.width * 0.38,
fit: BoxFit.fill,
image: AssetImage('lib/assets/images/error_image.png'),
)
: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: productModel.imageUrl!.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FancyShimmerImage(
height: size.width * 0.28,
width: size.width * 0.38,
imageUrl: productModel.imageUrl![index],
boxFit: BoxFit.fill,
),
);
}),
)
请注意,我只翻译了代码部分,不包括代码中的注释。
英文:
I have fixed the problem by adding a sized box and giving it height and width. Thus, the problem was fixed thanks for your help everyone.
Here is my updated Pageview.builder code:
child: SizedBox(
height: 120,
width: 400,
child: productModel.imageUrl == null
? Image(
height: size.width * 0.28,
width: size.width * 0.38,
fit: BoxFit.fill,
image: AssetImage('lib/assets/images/error_image.png'),
)
: PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: productModel.imageUrl!.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: FancyShimmerImage(
height: size.width * 0.28,
width: size.width * 0.38,
imageUrl: productModel.imageUrl![index],
boxFit: BoxFit.fill,
),
);
}),
),
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论