Dart/Flutter: horizontally scrollable week view - how to display particular items from the ListView? - flutter

I've been trying to make horizontal weekly calendar without using third party packages. I've created a horizontally scrollable Listview, containing three weeks : previous, current and next. Obviously, Listview displays from the first item in the list, which is the first day of the previuos week. Is there any way to control the items displayed and to display the current week with previous and next weeks being accessed through horizontal scrolling?
Here is the code for the ListView.builder:
Container(
height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 20),
itemCount: threeWeeks2.length,
itemBuilder: (BuildContext context, int index) {
var date = DateFormat('d').format(threeWeeks2[index]);
return DayCardBig(date);
}
),
),
Also, I can't keep but wondering whether the logic behind this implementation of week view is sound. I tried a more complex widget using carousel slider and pageview, but it just got messy. Is there any other widget that I'm not familiar with that I could use for a scrollable week view ?

Related

Dynamic ListView of stateful widgets not working

Dears,
it could be just a mistake of mine but ...it's driving me crazy ;)
I have a ListView inside my statefulwidget:
Expanded(
child: ListView.builder(
padding: EdgeInsets.all(10.0),
itemCount: searchableFoodList.length,
itemBuilder: (BuildContext context, int index) {
print('4 - SFL - ${searchableFoodList[index].id} - ${searchableFoodList[index].name}');
return
FoodItem(
id: searchableFoodList[index].id,
baseUnit: searchableFoodList[index].baseUnit,
baseUnitS: searchableFoodList[index].baseUnitS,
baseVal: searchableFoodList[index].baseVal,
baseValCal: searchableFoodList[index].baseValCal,
mediumVal: searchableFoodList[index].mediumVal,
mediumValCal: searchableFoodList[index].mediumValCal,
name: searchableFoodList[index].name,
note: searchableFoodList[index].note
);
},
),
searchableFoodList is modified (according user selection) inside a setState().
Let say that we have a 3 FoodItem(s), so my searchableFoodList is [FoodItem-1, FoodItem-2, FoodItem-3] and everything is working fine.
If I select a single item in my list, let say "FoodItem-2", the searchableFoodList becomes [FoodItem-2] and the list displayed contains (correctly) just one item but it is FoodItem-1.
Note that I inserted a print ...and it prints "FoodItem-2"
I guess that the problem is that it is considered the "original list" and it is changed only the length of the list but the list itself is not re-generated.
I have no more ideas ...any suggestions to solve this problem?
P.S.
FoodItem is stateful widget as well (an animated one). I did something similar with using stateless widget and I didn't have any problem

Idea in order to address lack of scrollbar in Flutter web

I am new to flutter and using it for web. I see that there is no built in scrollbar when the page overflows the viewport
Would it be possible to somehow have a javascript script in the html that would check the height of the content periodically and add/remove scroll bar as necessary?
Does this make any sense?
Thank you
I'm not sure if its what you want but if you wrap your Listview with Scrollbar then you get the result you want:
Scrollbar(
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) => ListTile(title: Text("Item= ${index + 1}"),),),
)
You can find more here

Flutter - SliverAppBar with snapping toolbar and nested scroll view

I'm trying to reproduce a UX design in which we have the following components:
A top bar which contains the text "Desmos"
A main post content, which is composed of
A header (user icon, user name, post date, options button)
The post message
Any post image that might be present
A tab bar, which allows the user to show either the Comments list or the Reactions list.
The peculiarity of this UX is that when the user scrools the list of Comments or Reactions (based on which he is currently viewing), the vertical scroll list snaps to the tab bar.
From there, the user will be able to either scroll down the list of comments or, with an additional scroll, showing again the post. Please note that the original post should be placed so that for the user to show it again, a higher amount of scroll force is required.
I have put together a video that you can see here to better understand how this should work:
I've already realized a widget called PostContent that contains all the above mentioned main content of a post. I've also already tried coding something for the wanted UX that looks like the following:
Scaffold(
body: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (context, _) {
return [
SliverAppBar(
backgroundColor: Colors.white,
expandedHeight: 310,
pinned: true,
primary: true,
flexibleSpace: PostContent(post: post),
)
];
},
body: ListView.builder(
itemBuilder: (context, index) {
return Text(index.toString());
},
),
),
),
);
The result can be seen by clicking on the following preview:
The problems with this implementation are the following:
As the PostContent is a Column, how can I get its height so that I don't have to specify a fixed value inside SliverAppBar's expandedHeight attribute?
How can I avoid that when scrolling up the ListView, the scrolling stops when it reaches the AppBar without scrolling further up?

How to use detect changes in elements of an array using provider?

I started developing my first app with flutter and I have some questions.
I have a screen that contains a Horizontal ListView where each item represents a month and occupy the entire screen. Each item is another list of itens. It's basically a list showing expenses for every month. I'm controlling state using Provider, and I'm having trouble to detect changes in a month. For example, I'm in january, but I added an expense in february, so the february item must detect the change and rewrite. I haven't been able to do it so far. Here is the screenshots of the app:
I have a provider that has an array of "Periods". And a "Period" is a class that represents a month, and contains an array of expenses.
I guess I'm not organising my data the right away, I'd appreciate if someone could point me in the right direction.
EDIT:
So, I watched this video here: https://www.youtube.com/watch?v=d_m5csmrf7I, and that helped me a little at least on how to detect changes in nested providers. I basically did this:
Widget build(BuildContext context) {
...
final size = MediaQuery.of(context).size;
final financeiro = Provider.of<Financeiro>(context);
return ImprovedListView.builder(
controller: _listController,
scrollDirection: Axis.horizontal,
itemCount: financeiro.periodos.length,
itemSize: size.width,
physics: const NeverScrollableScrollPhysics(),
initialScrollOffset: financeiro.indexMesAtual * size.width,
itemBuilder: (ctx, index) {
final periodo = financeiro.periodos[index]; //get a piece of the list and pass to another change notifier provider
return ChangeNotifierProvider<Periodo>.value(
value: periodo,
child: PeriodoFinanceiro(
key: ValueKey('${periodo.ano}${periodo.mes}'),
index: index,
scrollTo: scrollTo,
carregarDadosIniciais: carregarDadosIniciais,
excluirLancamento: excluirLancamento,
),
);
};
}
Now I just have to figure out how to better control the scrolloffset of the list when its re-rendered.
Thanks

flutter - SliverList / SliverChildBuilderDelegate supply initial index or allow negative indices

I'm currently building a calendar view in Flutter using a SliverList and a SliverChildBuilderDelegate such that I don't have to render every single item in the calendar at once.
The first date is epoch time, Jan 1, 1970, and the last date is some odd amount of time computed after today's date.
My issue is is that when I first render the view, I want it to render the view starting today, not on Jan 1, 1970. However, if I have today as the 0 indexes, negative indices are not allowed (or supplied) to the builder delegate so you can't scroll up from that date. You also can't supply an initial index, as far as I can tell, to the builder or the list, so I can't make epoch time as the 0 indexes either since the list will just start there, making for quite the terrible experience! I'm not entirely sure how to proceed.
Does anyone have any suggestions?
I'm not aware of an easy way to do this, there's no initialPositition parameter in ListView nor in SliverList. The reason I can think of is that lists are a series of widgets embedded on a ScrollView, such that in order for you to set an initial item, you would need to know the exact scroll offset of that item.
By default the two list widgets make no assumption about the height of its items, so in general finding that offset would require you to compute the heights of all widgets before it one by one, which is inefficient.
However, you can make things easier if you know beforehand the height of all your list items, or if you can force them a fixed height through either the ListView.itemExtent field or the SliverFixedExtentList.
In case you do know (or forced) the height of your list items beforehand, you can set an initial item through an initialScrollOffset in your ScrollController. Here's an example with a ListView.
#override
Widget build(BuildContext context) {
final _itemExtent = 56.0; // I know item heights beforehand
final generatedList = List.generate(500, (index) => 'Item $index');
return ListView(
controller: ScrollController(initialScrollOffset: _itemExtent * 401),
children: generatedList
.map((index) =>
ListTile(title: Text(index, style: TextStyle(fontSize: 20.0))))
.toList(),
);
}
Or in a SliverList.
#override
Widget build(BuildContext context) {
final _itemExtent = 56.0;
final generatedList = List.generate(500, (index) => 'Item $index');
return CustomScrollView(
controller: ScrollController(initialScrollOffset: _itemExtent * 401),
slivers: [
SliverFixedExtentList(
itemExtent: _itemExtent, // I'm forcing item heights
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text(
generatedList[index],
style: TextStyle(fontSize: 20.0),
),
),
childCount: generatedList.length,
),
),
],
);
}
In both cases this is the result when you first open the app.