I am trying to run the Xcode Accessibility Inspector over my Flutter app and have issues when I have a vertical list that has a nested horizontal list. The screen reader gets stuck on the horizontal list and either never progresses or drops focus. I expected the reader to read off each square but observed the reader getting stuck on horizontal list. I have tried to create an example app to demo the issue.
Here is the build function of my stateless widget:
Widget _getVertList(double width) {
return ListView.builder(
shrinkWrap: true,
itemBuilder: (_, i) {
if (i != 0 && i % 3 == 0) {
return _getHorzList(width); // show horizontal list
}
return Semantics(
label: 'RED BOX $i',
child: Column(
children: [
Container(
color: Colors.red,
height: 100,
width: 100,
),
const SizedBox(
width: 10,
height: 10,
)
],
),
);
},
itemCount: 20,
);
}
Widget _getHorzList(double width) {
return SizedBox(
height: 101,
width: width,
child: Column(
children: [
Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemBuilder: (_, i) {
return Semantics(
label: 'Blue BOX $i',
child: Row(
children: [
Container(
color: Colors.blue,
height: 100,
width: 100,
),
const SizedBox(
width: 10,
height: 10,
)
],
),
);
},
itemCount: 10,
),
),
],
),
);
}
#override
Widget build(BuildContext context) {
final double width = MediaQuery.of(context).size.width;
return Scaffold(
body: _getVertList(width, height));
}
Related
Place an arrow at the end of the horizontal listview , i tried to warp horizontal listview and sizedbox for the arrow in Raw Widget but the arrow is always shown i wanna show when get the end of the list like this
Row(
children: [
const SizedBox(
width: 100,
height: 375,
child: Icon(
Icons.swipe_left_alt_rounded,
color: Colors.black,
size: 24,
)),
SizedBox(
height: 375,
width: SizeConfig.screenWidth * 0.8,
child: ListView.builder(
reverse: true,
scrollDirection: Axis.horizontal,
You can use itemBuilder to build items based on your need.
class AF extends StatelessWidget {
const AF({super.key});
#override
Widget build(BuildContext context) {
const itemLength = 4;
return Scaffold(
body: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: itemLength,
itemBuilder: (context, index) {
if (index == itemLength - 1) { // here will be the logic
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.arrow_back),
itemBuilder(index),
],
);
}
return itemBuilder(index);
},
),
);
}
Widget itemBuilder(int index) =>
Container(width: 200, child: Text("ItemNumber $index"));
}
Try use ListView swap outside Arrow Icon and ListView.builder:
This is demo code:
class TestScreen extends StatelessWidget {
const TestScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SizedBox(
height: 350,
child: ListView(
reverse: true,
scrollDirection: Axis.horizontal,
children: [
ListView.builder(
shrinkWrap: true,
reverse: true,
scrollDirection: Axis.horizontal,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(width: 2)),
child: Padding(
padding: const EdgeInsets.all(30),
child: Center(
child: Text(
index.toString(),
),
),
),
);
},
itemCount: 10,
),
const SizedBox(
width: 100,
child: Icon(
Icons.swipe_left_alt_rounded,
color: Colors.black,
size: 24,
)),
],
),
),
);
}
}
I have a gridView(3 items in a row) with dynamic number of items. I want gridView item should be at bottom means if there are 3 items then one row at bottom of screen, if there are 6 items then two row at bottom. So a dynamic padding at top depending on item count and screen size. My code structure is like below
class className extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
ImageFiltered(
//code here
),
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.black38,
),
GridView.builder(
primary: false,
reverse: false,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 30,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
//code
},
child: CustomWidget(
title: toolkitStore.getLabel(toolKit),
icon: ImageIcon(
AssetImage(
'assets/images/abcd.png'),
size: 48,
color: kWhiteColor,
),
),
);
},
itemCount: getCount().length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
),
],
),
),
);
}
}
Now I have this
but I want this
Thanks in advance.
**Try this one: **
import 'package:flutter/material.dart';
class ClassName extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Container(height: 100,width: 200,color: Colors.green,),//<----Your any widget
Align(
alignment: Alignment.bottomCenter,
child: GridView.builder(
primary: false,
reverse: true,
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 30,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () {
//code
},
child: const Icon(Icons.person,size: 50,color: Colors.green,),
);
},
itemCount: 5,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
),
),
Container(height: 100,width: 100,color: Colors.red,),//<----Your any widget
],
),
),
);
}
}
Wrap your GridView.builder with Align widget provide alignment: Alignment.bottomCenter,
Align(
alignment: Alignment.bottomCenter,
child: GridView.builder(
primary: false,
reverse: false,
While using Stack use positional widget(Positioned, Align,...) to place children on UI.
Thank you, everyone.
I solved my problem by using Positioned widget and setting shrinkWrap: true, my code structure is
new Positioned(
left: 0.0,
bottom: 0.0,
width: MediaQuery.of(context).size.width,
child: GridView.builder(
shrinkWrap: true, //this is most important
))
I want to create 2 list type data
first linear and other grid type list
now requirement is that both data list height will be dynamic means it should be expand when , new object is added.
and sorting scrollable along with all 4 widgets(sort, list, sort, grid).
like below image:
i have tried but height is static ,
i have used expanded but not giving result as i'm expecting.
code:
Container(
padding: EdgeInsets.all(10),
child: Container(
child: Column(
children: [
sort(context),//sort widget
createForlderView(context), //dynamic list widget
sort(context), //sort widget
_createGridView()// dynamic grid list widget
],
),
),
);
Widget sort(BuildContext context){
return Container(
// color: Colors.red,
height: 25,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Folder"),
Container(
// color:Colors.green,
width: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Sort"),
// SizedBox(width:5),
InkWell(onTap: () {}, child: Icon(Icons.sort))
],
),
),
],
),
);
}
// list view:
Widget createForlderView(BuildContext context) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
return Expanded(
child: Container(
height: _height / 1.2,
child: ListView.builder(
// padding: ,
itemCount: directoryItems.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Container(
height: 30,
width: 30,
child: Icon(Icons.folder, color: Colors.brown),
),
title: Text(directoryItems[index]),
subtitle: Text("15 items"),
trailing:
IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
));
}),
),
);
}
// grid view:
Widget _createGridView() {
var mSize = MediaQuery.of(context).size;
/*24 is for notification bar on Android*/
final double itemHeight = (mSize.height - kToolbarHeight) / 2;
final double itemWidth = mSize.width / 2;
int gridItemCount =
Provider.of<DocumentProvider>(context).allDocuments.length;
return Expanded(
child: Container(
height: 100,
child: GridView.count(
key: animatedListKey,
scrollDirection: Axis.vertical, //default
reverse: false,
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0,
childAspectRatio: (itemWidth / itemHeight),
children: List.generate(gridItemCount, (index) {
return Center(
child: SelectCard(
index: index,
itemHeight: itemHeight,
itemWidth: itemWidth,
deletefun: () {
Navigator.pop(context);
DeleteDialog(
index: index,
dateTime:
Provider.of<DocumentProvider>(context, listen: false)
.allDocuments[index]
.dateTime);
},
),
);
}),
),
),
);
}
output screen:
I have found my solution,
used CustomScrollView along with it's slivers: SliverToBoxAdapter (for single widget),SliverFixedExtentList (for linear list) , and SliverGrid (for Grid list).
import 'package:flutter/material.dart';
class ExpandableList extends StatefulWidget {
final List<FolderModel> listData;
final List<FilesModel> gridListData;
const ExpandableList({Key key, this.listData, this.gridListData}) : super(key: key);
#override
_ExpandableListState createState() => _ExpandableListState();
}
class _ExpandableListState extends State<ExpandableList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
buildAppBar(),
sorting(title: "folders", tralingTitle: "sort", onTap: (){}),
expandableListBuilder(),
sorting(title: "files", tralingTitle: "sort",onTap: (){}),
expandableGridList(),
],
)
);
}
buildAppBar(){
return SliverAppBar(
title: Text("Multi Expandable list example"),
centerTitle: true,
pinned: true,
);
}
expandableListBuilder(){
return SliverFixedExtentList(
itemExtent: 75.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
child: ListTile(
leading: Container(
height: 30,
width: 30,
child: Icon(Icons.folder, color: Colors.brown),
),
title: Text(widget.listData[index].title),
subtitle: Text(widget.listData[index].subtitle),
trailing:
IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
));
},
childCount: widget.listData.length
),
);
}
expandableGridList(){
return SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
elevation: 8,
child: Container(
alignment: Alignment.center,
height: 100,
width: 100,
child: Text("${widget.gridListData[index].title}${(index+1).toString()}"),
),
);
},
childCount: widget.gridListData.length,
),
);
}
sorting({String title,String tralingTitle, void Function() onTap}){
return SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.all(10),
height: 50,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
Container(
// color:Colors.green,
width: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(tralingTitle),
// SizedBox(width:5),
InkWell(
onTap:onTap,
child: Icon(Icons.sort))
],
),
),
],
),
),
);
}
}
result:
I have a widget that displays a 100x100 image and a blue container next to it which fills the rest of the Row.
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(title)));
},
child: Container(
padding: EdgeInsets.all(24),
child: Row(
children: [
SizedBox(
child: Image.asset("assets/img_small.png"),
width: 100,
height: 100),
Expanded(
child: Container(margin: EdgeInsets.only(left: 12), color: Colors.blue)
)
],
),
));
}
This works fine but as soon as I use it within a list view, the blue container is not visible:
#override
Widget build(BuildContext context) {
return ListView.separated(
itemCount: list.length,
separatorBuilder: (context, index) =>
Divider(color: Colors.grey, thickness: 2, height: 0, indent: 8),
itemBuilder: (context, position) {
return BlueBoxWidget(title: list[position]);
});
}
What am I doing wrong?
I am mostly interested why inside a listview the blue container doesn't try to expand its height as much as possible.
The blue Container is there, but with 0 height.
Try adding some height, like this, to get the container visible
Expanded(
Container(
height: 50,
margin: EdgeInsets.only(left: 12),
color: Colors.blue
),
)
try to remove the Expanded widget that wrapped the Container it maybe work.
I need to make a gridview in flutter to list card item in a horizontal direction with specific height and width, when I tried I always get a square cell in my gridview and no effect if I change my container height and width.
I tried like below
child: GridView.count(
scrollDirection: Axis.horizontal,
// Create a grid with 2 columns. If you change the scrollDirection to
// horizontal, this produces 2 rows.
crossAxisCount: 2,
// Generate 100 widgets that display their index in the List.
children: List.generate(cuisineListAll.length, (index) {
return Card(
child: Container(
width: 330,
height: 100,
child: Text(
myListAll[index].name,
style: TextStyle(fontSize: 15),
),
),
);
})),
is there a way to display my card with my own fixed size? I tried flutter_staggered_grid_view but when I changed to horizontal direction, no luck.
Another way maybe you can try SingleChildScrollView + Wrap:
class WrapScrollViewPage extends StatelessWidget {
const WrapScrollViewPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
final widgets = [
Container(width: 100, height: 30, color: Colors.red),
Text('111', style: TextStyle(fontSize: 20)),
Text('222', style: TextStyle(color: Colors.blue)),
Container(width: 60, height: 50, color: Colors.orange),
Container(width: 20, height: 30, color: Colors.green),
Text('333'),
Text('4444'),
Text('555555'),
Text('666666'),
];
return Scaffold(
appBar: AppBar(title: Text('SingleChildScrollView + Wrap')),
body: Column(
children: [
SizedBox(
width: ScreenUtil.screenWidth,
height: 50,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Wrap(
direction: Axis.horizontal,
spacing: 8,
crossAxisAlignment: WrapCrossAlignment.center,
children: widgets,
),
),
),
],
),
);
}
}
Result:
try to give childAspectRatio: YOUR_VALUE,
For ex,
...
GridView.count(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
crossAxisCount: 4,
childAspectRatio: 1 / 1.1,
...