admin管理员组文章数量:1277304
I'm developing a Flutter screen where i use a GridView (used in page_editor_screen.dart) to display a grid of widgets. Each widget (PageElementWidget) contains an image, a description field, and some details (product code, quantity, unit price).
The issue is that the internal content of PageElementWidget does not respect the constraints imposed by the grid cell (for example, the width and height defined by the GridView), causing an overflow – as indicated by the yellow-black overflow bar at the bottom. For instance, I noticed that each cell receives well-defined constraints (e.g., BoxConstraints(w=254.0, h=360.1)), but the inner widgets, such as TextFields and images, do not dynamically resize according to the available space. As you can see in image, overflow "disappear" when i stretch application windows, so i suppose some widget not follow parent constraint, but i don't figure out which one.
Additional Context:
The goal of the screen is to create a facsimile of an A4 page, were user choose rows and columns count, which will later be used to generate a PDF. This means that the layout must be responsive and correctly adhere to the A4 format constraints, as any overflow or misalignment would affect the quality of the generated PDF.
I have tried several solutions, including:
- Using a LayoutBuilder to inspect the constraints and divide the available space in fixed percentages.
- Employing Flexible and Expanded widgets inside a Column to proportionally distribute the space.
- Adjusting the childAspectRatio of the GridView and attempting to adapt the widgets to changes in screen size.
- Correct the font size according to the available space, even if it starts at the first rendering of the elements and then remains fixed even if i stretch screen size.
However, the problem persists: the content renders incorrectly and continues to overflow, regardless of the adjustments made.
Snippets:
Tile content (PageElementWidget):
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/page_element_model.dart';
import 'package:image_picker/image_picker.dart';
class PageElementWidget extends StatefulWidget {
final int index;
const PageElementWidget({
super.key,
required this.index,
});
@override
_PageElementWidgetState createState() => _PageElementWidgetState();
}
class _PageElementWidgetState extends State<PageElementWidget>
with AutomaticKeepAliveClientMixin {
final ImagePicker _picker = ImagePicker();
XFile? _image;
String description = "";
String code = "";
int quantity = 0;
double unitPrice = 0.0;
@override
void initState() {
super.initState();
// Otteniamo il modello relativo a questo widget
final element = Provider.of<PageElementModel>(context, listen: false);
if (element.imagePath.isNotEmpty) {
_image = XFile(element.imagePath);
}
description = element.description;
code = element.code;
quantity = element.quantity;
unitPrice = element.unitPrice;
}
Future<void> _selectImageFromGallery() async {
final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_image = pickedFile;
});
_updateProvider();
}
}
@override
Widget build(BuildContext context) {
super.build(context);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Sezione immagine
Expanded(
flex: 3,
child: GestureDetector(
onTap: _selectImageFromGallery,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: _image != null
? Image.file(File(_image!.path), fit: BoxFit.contain)
: Center(
child: Text(
"Click to select an image",
textAlign: TextAlign.center,
),
),
),
),
),
// Sezione descrizione
Expanded(
flex: 1,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 4.0),
alignment: Alignment.center,
child: TextField(
decoration: InputDecoration(
hintText: 'Enter description here',
border: const OutlineInputBorder(),
),
textAlign: TextAlign.center,
maxLines: 2,
onChanged: (value) {
setState(() {
description = value;
});
_updateProvider();
},
),
),
),
// Sezione dettagli (codice, quantità, prezzo)
Expanded(
flex: 2,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
// RIGA 1: Codice
Row(
children: [
Text(
'Code: ',
),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter product code',
border: InputBorder.none,
),
textAlign: TextAlign.center,
maxLines: 2,
onChanged: (value) {
setState(() {
code = value;
});
_updateProvider();
},
),
),
],
),
// RIGA 2: Quantità
Row(
children: [
Text(
'QNT: ',
),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter quantity',
border: InputBorder.none,
),
textAlign: TextAlign.center,
maxLines: 2,
onChanged: (value) {
setState(() {
quantity = int.tryParse(value) ?? 0;
});
_updateProvider();
},
),
),
],
),
// RIGA 3: Prezzo unitario
Row(
children: [
Text(
'Unit Price: ',
),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter unit price',
border: InputBorder.none,
),
textAlign: TextAlign.center,
maxLines: 2,
onChanged: (value) {
setState(() {
unitPrice = double.tryParse(value) ?? 0.0;
});
_updateProvider();
},
),
),
],
),
],
),
),
),
],
);
}
// Aggiorna il modello associato
void _updateProvider() {
final element = Provider.of<PageElementModel>(context, listen: false);
element.setImagePath(_image?.path ?? '');
element.setDescription(description);
element.setCode(code);
element.setQuantity(quantity);
element.setUnitPrice(unitPrice);
}
@override
bool get wantKeepAlive => true;
}
The screen with gridVew widget:
import 'package:flutter/material.dart';
import 'package:flutter_application_1/widgets/page_element_widget.dart';
import 'package:flutter_application_1/widgets/side_bar.dart';
import 'package:provider/provider.dart';
import 'package:flutter_application_1/models/page_model.dart';
class PageEditorScreen extends StatelessWidget {
final int columns = 5;
final int rows = 7;
/*const PageEditorScreen({
super.key,
required this.columns,
required this.rows,
});*/
@override
Widget build(BuildContext context) {
double aspectRatio = 1;
return ChangeNotifierProvider(
create: (context) => PageModel(),
child: Consumer<PageModel>(
builder: (context, pageModel, child) {
// Se la lista dei modelli non è già inizializzata, creala
if (pageModel.pages.length != columns * rows) {
pageModel.initPages(columns * rows);
}
return Scaffold(
appBar: AppBar(
title: Text('Pagina di lavoro'),
actions: [
IconButton(
icon: Icon(Icons.save),
onPressed: () => _savePageElements(context),
),
],
),
drawer: SideBar(),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: LayoutBuilder(
builder: (context, constraints) {
print('Height: ${constraints.maxHeight} Width: ${constraints.maxWidth}');
aspectRatio = CheckAspectRatio(constraints.maxWidth);
print('AspectRatio: $aspectRatio');
return GridView.builder(
padding: const EdgeInsets.all(0.0),
shrinkWrap: false,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
childAspectRatio: 1,
),
itemCount: columns * rows,
itemBuilder: (context, index) => ChangeNotifierProvider.value(
value: pageModel.pages[index],
child:
PageElementWidget(key: ValueKey(index), index: index),
),
);
},
),
);
},
),
);
}
double CheckAspectRatio(double width) {
return width / 2520;
}
void _savePageElements(BuildContext context) {
final pageList = context.read<PageModel>();
List<Map<String, dynamic>> savedData = [];
for (var element in pageList.pages) {
savedData.add(element.toMap());
}
print("Dati Salvati: $savedData");
}
}
Screen
native application size
window stretched
Update 02/03/25
I found an workaround, so not a solution, for my code: In GridView.builder there is the childAspectRatio parameter that forces, for page_editor_screen, the height constraint to be equal to the width constraint (default value = 1.0). Wrapping the GridView in LayoutBuilder I do an method to define the ratio, dividing the width of the screen by a number I derived during testing. While the workaround effectively prevents the overflow from being visible, it does so by altering the final appearance of the box. Essentially, I'm modifying the grid's aspect ratio to hide the overflow, but this adjustment changes the intended design of the page_editor_screen. So the main question remains: why do the widgets inside page_editor_screen not respect the height of the columns?
There the snippet:
body: LayoutBuilder(
builder: (context, constraints) {
print('Height: ${constraints.maxHeight} Width: ${constraints.maxWidth}');
aspectRatio = CheckAspectRatio(constraints.maxWidth);
print('AspectRatio: $aspectRatio');
return GridView.builder(
padding: const EdgeInsets.all(0.0),
shrinkWrap: false,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: columns,
childAspectRatio: aspectRatio,
),
itemCount: columns * rows,
itemBuilder: (context, index) => ChangeNotifierProvider.value(
value: pageModel.pages[index],
child:
PageElementWidget(key: ValueKey(index), index: index),
),
); //GridView.builder
},
), //LayoutBuilder
本文标签:
版权声明:本文标题:flutter - Overflow in widgets inside a GridView – How do I force the internal content to respect constraints? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741263822a2368092.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论