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,
)
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
cv template and I want to edit it with flutter
Everything in Flutter is widgets, this image would be an Image widget in your Flutter app.
You can use Stack widget to put things over each other. so You can put image over an image by using Stack widget.
Unfortunately you can't edit text of an image in Flutter, Instead I would rather to edit this image (for putting image and editing text) by Photoshop for example and then implementing it as one piece widget in my Flutter app.
What I assess from your question is you want to have a layout like the one given in your link, right? For a circular image, you could use CircleAvatar. As for the text you could use the Text widget. Now put these widgets inside a Column or Row. You seem to be new to Flutter and I'd suggest you to get a good grip on the basics first. Anyhow, here's a little dummy code snippet you could extend to achieve what you're looking for
Column(
crossAxisAlignment: CrossAxisAlignment
.start, //if you want your widgets to align on left in your col
children: [
CircleAvatar(
radius: 70,
foregroundImage: AssetImage("pathToYourAssetImg"),
),
SizedBox(
height: 20, //set this to your intended value
),
Text( //you could also create a custom text widget and pass the arguments if you don't want to hardcode text widgets over & over again for all of your text
"yourText",
style: TextStyle(
color: Colors.black87,
fontSize: 20, //set this to your value
fontWeight: FontWeight.bold //if you want to have a bold text
),
),
],
);
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).
My Requirements is to arrange items like this in listview:
item 1 item2
item 3 item4
item 5 item6
I'm currently using ListView and its children as Wrap widget(to arrange item in next line)
My Output is like this
item 1 item 4
item 2 item 5
item 3 item 6
How to achieve my requirement in the flutter
The best way to do this is by using GridView. It is really meant for that kind of layout that you needed.
Here is an example of how to use a GridView:
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.headline5,
),
);
}),
);
Here is a picture showing the layout difference between GridView and ListView:
#Uni answerd to use Grid-view, and that's 100% correct, but if you need a setup like this:
--Widget1-- --Widget2--
--------Widget3--------
--Widget4-- --Widget5--
You could use Listview, but then have the Widget1 and Widget2 in a Row(), And that way there will only be 1 widget(Row) on each line, but that widget(Row) will have 2 child-widgets, or more, on the inside.
This gives a lot more flexibility than Gridview, but to be honest if you need the function of gridview, then use that, I even use it, but Listview with rows can be helpfull for a more dynamic design :)