I would like to implement like this pic on Flutter.
I'm trying to implement like this code using SliverStaggeredGrud.count.
However, When I enter long text, the add button was moved to next Column.
return SliverStaggeredGrid.count(
crossAxisCount: 3,
mainAxisSpacing: 16.0,
children: userItems,
staggeredTiles: userItems
.map<StaggeredTile>((_) => const StaggeredTile.fit(1))
.toList(),
);
Please help it.
V/r
Related
Woah! I've spent several hours refactoring nested ListViews to a parent CustomScrollView & child Slivers. The errors Slivers produced were opaque and frightening, with nothing illuminating in Logcat; sleuthing devoured much of the time.
Anyway, that's solved. I find I still have jank scrolling a 15-item list. OK, each item can involve further numerous widgets {Padding, Alignment, Elevated button, Row, Text, SizedBox, Icon}. So my 15-item list ends up being multiple more Widgets.
I've now swapped out my SliverChildListDelegate for SliverChildBuilderDelegates, so a Builder builds the Widget List lazily. Having done this, it seems quite inefficient because it's increased the Widgets in the Widget tree. Each of the builders' buildItem() calls needs an extra Column Widget to wrap that sub-chunk of the total list.
It may be a lot of Widgets scrolling but it's only a 15 item list. I wish I knew what to optimise. Any thoughts on how to best reduce jank on Lists for mobile web?
The Flutter team says Flutter works best for computational-centred apps rather than text heavy informational apps. In future would it be better just to use webView Widgets? I always thought embedding Webviews would be clunky and slow but Lists of native Flutter Widgets, even as SliverLists, give jank.
Here is the janky list complete with builder:
Widget buildLocationDescriptionWidgets(LocationDetails presentLocation) {
print(LOG + "buildLocationDescriptionWidgets");
if (presentLocation.descriptionLinkUrls.isEmpty)
return SliverToBoxAdapter(child:
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(presentLocation.description[0])));
int numDescriptionBlocks = presentLocation.description.length;
double paddingBottom = 16;
if (presentLocation.descriptionLinkUrls.length >= numDescriptionBlocks) {
paddingBottom = 0;
}
return SliverPadding(
padding: EdgeInsets.fromLTRB(16, 16, 16, paddingBottom), sliver:
SliverList(
key: Key("descriptionSliverList"),
delegate: SliverChildBuilderDelegate((context, index) =>
buildDescriptionBlock(context, index),
childCount: presentLocation.description.length
),
));
}
Column buildDescriptionBlock(BuildContext context, int index) {
List<Widget> colChildWidget = [];
colChildWidget.add(Text(
widget.presentLocation.description[index],
textAlign: TextAlign.left,
));
if (index < widget.presentLocation.descriptionLinkUrls.length) {
colChildWidget.add(Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Align(
alignment: Alignment.center,
child: index >=
widget.presentLocation.descriptionButtonIcons.length
? ElevatedButton(
child: Text(
widget.presentLocation.descriptionButtonText[index]),
onPressed: () {
_launchURL(
widget.presentLocation.descriptionLinkUrls[index]);
})
: ElevatedButton(
child:
Row(mainAxisSize: MainAxisSize.min, children: [
Text(
widget.presentLocation.descriptionButtonText[index]),
SizedBox(width: 8),
FaIcon(
buttonIconMap[widget.presentLocation
.descriptionButtonIcons[index]],
size: 16)
]),
onPressed: () {
_launchURL(
widget.presentLocation.descriptionLinkUrls[index]);
}))));
}
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: colChildWidget);
}
Should I regress from a builder to a conventional SliverList?
Other things I've tried: I eliminated jank in my app Drawer list by putting const everywhere possible, lots of Dividers were made Const. But when you style text using Theme.of(context).textTheme.bodyText2 etc. it doesn't allow you to set textboxes to const. If you want to use const you can't style the app globally, you'd have to hard code. Is it worth forsaking abstraction for hard coding Text widget styles?
Here is the web app: Love Edinburgh
For the clearest example of jank
Open the App Drawer
Scroll to WONDER
Tap Arthur's Seat
Open the panel to full screen - slide it up
Scroll down the panel.
It doesn't show on a desktop browser which is compiled using Skia / Webkit. It's a bit fiddly to get scroll working on a desktop browser, you need to click amongst the text, then attempt to scroll. It's meant for mobile use so I'm resigned to that.
Not sure how to help you out. Would rather put this on a comment rather than answer but I don't have the points to do a comment.
Anyway, I wish I could replicate your problem. On my personal experience, for a 15 item list with numerous child widgets, it shouldn't be janky unless it has probably big sized images or really too much extra widgets.
On my case, I made sure to "isolate" / "compute" my heavy computations and showed a loading screen while preparing the list.
You may read on:
Isolates : https://dart.dev/guides/language/concurrency
Compute:
https://api.flutter.dev/flutter/foundation/compute-constant.html
Hope that helped!
I try to make an apps using long GridView with complexe item. I use GridView.builder which is optimize and it creates visible items (and it do the job !).
But in my case, I need some widget before and I must add Column() and SingleChildScrollView.
When I do that I need to change GridView.builder with primary=false and shrinkWrap: true.
But now, all GridView items are generated.
EDIT: New demo
My wanted behavior is the mode "ColumnWithGrid".
Check this demo to understand issue.
Press top buttons to switch modes: open Console and check log
https://dartpad.dev/?id=4f60ffbf656767a6e5c5bccc280acd3a
I think "shrinkWrap" property must stay to false but I never success to keep it in this case.
My question:
How to use GridView.builder properly when I need to include it inside Column() or whatever ?
How to make the mode "ColumnWithGrid" without generate full list (using dev.pub, ...) ?
Thanks
After some search and experiment, I found some posts about this topic (which is true for GridView or ListView widget) and my conclusion is :
GridView doesn't work like I expect !
When I create just a single GridView, it's like I create a container of my full device area and I put GridView inside.
This "hidden container" just keep info visible inside this container area.
So if I include my GridView inside Column without any container, it doesn't create it for me and unroll all my data to compute properly size.
The feature that expected is : GridView computes only items at screen and unroll virtually data (so manage local/global slider position to create only item inside visible area).
I update my demo to show the effect about all cases.
Sources:
https://docs.flutter.dev/cookbook/lists/long-lists
https://medium.com/saugo360/flutter-creating-a-listview-that-loads-one-page-at-a-time-c5c91b6fabd3
A CustomScrollView in combination with SliverList and SliverGrid can be used to achieve lazy loading.
CustomScrollView(slivers: [
SliverList(
delegate: SliverChildListDelegate([
const Center(
child: Text(
"Header",
style: TextStyle(fontSize: 40),
),
),
]),
),
SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
print("generate the item $index");
return Container(color: Colors.blue);
},
childCount: 100,
),
),
]),
https://dartpad.dev/?id=9633305d9a2daa0905de852fa003aba1
Below I have attached an image of a layout of photos. I can't seem to get the name for this format of image layout. Is it flexbox? grid layout? Additionally, I wanted to know if it was possible to have this image layout format created through flutter with existing assets.
Use flutter_staggered_grid_view package.
In the pubspec.yaml , add the following dependency:
dependencies:
flutter_staggered_grid_view: any
In your library , add the following import:
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
Example:
StaggeredGridView.countBuilder(
crossAxisCount: 4,
itemCount: 8,
itemBuilder: (BuildContext context, int index) => new Container(
color: Colors.green,
child: new Center(
child: new CircleAvatar(
backgroundColor: Colors.white,
child: new Text('$index'),
),
)),
staggeredTileBuilder: (int index) =>
new StaggeredTile.count(2, index.isEven ? 2 : 1),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
),
Use it like GridView
Output:
Constructors :
The StaggeredGridView follow the same constructors convention than the GridView.
There are two more constructors: countBuilder and extentBuilder. These constructors allow you to define a builder for the layout and a builder for the children.
Tiles :
A StaggeredGridView needs to know how to display each tile, and what widget is associated with a tile.
A tile needs to have a fixed number of cell to occupy in the cross axis. For the extent in the main axis you have 03 options:
You want a fixed number of cells => use StaggeredTile.count.
You want a fixed extent => use StaggeredTile.extent.
You want a variable extent, defined by the content of the tile
itself => use StaggeredTile.fit.
In case you wouldn't want to use any package (sometimes this is a healthy solution), you could easily achieve what you want by combining Columns, Rows and Expanded Widgets using flex property to define what percentage of the Main Axis you would want your different Widgets to occupy (in your case, the images to be displayed).
I am trying to lay out images in a grid that is two columns wide. I was initially trying to use GridView.count() but I don't know the aspect ratio of these images in advance so they didn't always look good. I don't want to use a third-party library as has been suggested by answers of the few questions I came across similar to this one.
Hixie mentioned here that:
If you're using the constructor used by [GridView.count], you can set the aspect ratio (childAspectRatio argument to GridView.count), and each cell will honor it.
If you want more control, you can use the GridView.custom constructor to provide your own delegate, at which point you get to define the geometry of each child as you wish.
So I tried the following to test building a GridView where the child defines its height (in this case, 900):
return GridView.custom(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 4,
crossAxisSpacing: 4,
),
childrenDelegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
height: 900,
color: Colors.white,
);
},
childCount: 20,
),
);
I am still getting the squares the GridView ordinarily produces. I'm sure I'm misunderstanding something; how do I make sure the desired size of the children is respected?
I am making a screen when I need to show design like Screen Below, with tree views and connectors.
It will be a great help if someone can suggest me how to create a design like this, conceptually.
I have tried a Gridview and tree_view so far.
GridView.count(
// 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(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline,
),
);
}),
);
Use the public flutter package called GraphView
Flutter GraphView is used to display data in graph structures. It can
display Tree layout, Directed and Layered graph. Useful for Family
Tree, Hierarchy View.
The library is designed to support different graph layouts and currently works excellent with small graphs.
graphite is somewhat similar to the design,
DirectGraph(
list: list,
cellWidth: 136.0,
cellPadding: 24.0,
orientation: MatrixOrientation.Vertical,
)