im new to Riverpod and Flutter
the problem i'm having is that when i use StateNotifier, the state is immutable so i have to create new state and add new value to the end of List
void add(Cart cart) {
state = [...state, cart];
}
void inQuan(int i) {
final tempCart = state[i];
tempCart.quantity++;
remove(state[i]);
add(tempCart);
}
and this makes my list pushes the item i'm editing to the end
is there any way to optimize my code?
This creates only one new array.
void inQuan(int i) {
state = [
for (int index = 0; i < state.length; index++)
if (i == index)
state[i].copyWith(quantity: state[i].quantity++)
else
state[i]
];
}
Related
I have a count variable like this:
class Count with ChangeNotifier {
int _count = 1;
int get count => _count;
void setCount(bool isIncrement) {
if (isIncrement) {
_count = checkCount(_count + 1);
} else {
_count = checkCount(_count - 1);
print("decrement" + _count.toString());
}
notifyListeners();
}
int checkCount(int count) {
if (count < 0) {
return 0;
} else if (count > 10) {
return 10;
} else {
return count;
}
}
}
I'm using the provider to use it on the food pages. But when I switch between the pages, the count variable continues from where it left off. I want it to restart as 1 every time the page changes.
class Hamburger extends StatefulWidget {
const Hamburger({super.key, required Count count});
#override
State<Hamburger> createState() => _HamburgerState();
}
class _HamburgerState extends State<Hamburger> {
#override
Widget build(BuildContext context) {
Color coloricon = Provider.of<iconcolor>(context).coloricon;
int count = Provider.of<Count>(context).count;
return Scaffold(
…
);
}
}
The idea of Provider is to have a consistent state across all your pages.
If you want to save only the number of hamburgers selected you need a variable similar to _hamburgerCount and control it there.
Or, for a more scalable solution, you can create a Map<String, int> or something similar to store the amount of each type. There is many ways to solve this, but with one global count variable you can not achieve storing a count for each type of food.
The List EleccionSinSeleccionClase is just a list of a class who has a String on it.
class EleccionSinSeleccionClase {
String Eleccion;
}
The state List is another class:
class EleccionConSleccionClase {
String Eleccion;
bool selec;
}
The problem is that I want to copy the first into the state of the StateNotifier, this line break the code.
This is the line: state[i].Eleccion = ListaElecciones[i].Eleccion;
class EleccionesConSeleccionNotifier
extends StateNotifier<List<EleccionConSleccionClase>> {
final List<EleccionSinSeleccionClase> ListaElecciones;
EleccionesConSeleccionNotifier({required this.ListaElecciones}) : super([]);
void init(){
print(ListaElecciones.length.toString());
if(ListaElecciones.length != 0){
for (int i = 0; i < ListaElecciones.length; i++) {
state[i].Eleccion = ListaElecciones[i].Eleccion; ////HERE////
}
}
}
}
final eleccionConSleccionStateNotifierProvider = StateNotifierProvider<
EleccionesConSeleccionNotifier, List<EleccionConSleccionClase>>((ref) {
final eleccioneswatch =
ref.watch(eleccionesSinSeleccionStateNotifierProvider);
return EleccionesConSeleccionNotifier(ListaElecciones: eleccioneswatch)..init();
});
Maybe the problem is that you initialize state as an empty list super([]) and then you're trying to change a value in an index that doesn't exist (state[i] where the list is obviously empty and cannot access that position)
void init(){
print(ListaElecciones.length.toString());
if(ListaElecciones.length != 0){
/// you will need to check if both lists are the same lenght if you actually want to do this
/// without failling
/*for (int i = 0; i < ListaElecciones.length; i++) {
state[i].Eleccion = ListaElecciones[i].Eleccion; ////HERE////
}*/
/// if you only want to copy Eleccion parameter in a new class this would be the easiest way
state = ListaElecciones.map((cb) => EleccionConSleccionClase(Eleccion: cb.Eleccion)).toList();
}
}
I was reading that flutter bloc pattern is best for managing state.
I can see the need to separate display and business logic into separate areas.
Trying to learn flutter/dart from ground up.
I building a listview and each row of individual items that acts as a shopping card. User can select # of items or flavors of bagels in each row.
first issue is how to display the count of variable _dozen on screen? I have cubit/bloc sample code working. Trying to add simple test logic to when use select intervals of 13 bagels it increment a count of 1 bakers = _dozen. I can see this in debugger works . But I cannot ( sorry being new ) cannot figure out how to pass the _dozen variable to my view_page. Is passing in Bloc on for state management correct? or do I fall back and try inheritabve widget?
at end of day just want to display at bottom of screen total dozen bagels order.
import 'package:bloc/bloc.dart';
/// {#template counter_cubit}
/// A [Cubit] which manages an [int] as its state.
/// {#endtemplate}
class CounterCubit extends Cubit<int> {
/// {#macro counter_cubit}
CounterCubit() : super(12);
int _dozen = 12;
/// Add 1 to the current state.
void increment() {
if (state >= 0) {
emit(state + 1);
_dozen = ( state ~/ 13);
print('dozen:' + '$_dozen');
}
}
/// Subtract 1 from the current state.
void decrement() {
if (state > 0) {
emit(state - 1);
_dozen = ( state ~/ 13);
print('dozen:' + '$_dozen');
}
}
}
It seems that you need to keep more than one int in your state; one for count and one for dozen. Make a separate class CounterState to represent your state and hold those values so you end up with this code:
import 'package:bloc/bloc.dart';
class CounterState {
int count;
int dozen;
CounterState(this.count, this.dozen);
}
/// {#template counter_cubit}
/// A [Cubit] which manages an [CounterState] as its state.
/// {#endtemplate}
class CounterCubit extends Cubit<CounterState> {
/// {#macro counter_cubit}
CounterCubit() : super(CounterState(12,1));
/// Add 1 to the current state.
void increment() {
if (state.count >= 0) {
final int count = state.count + 1;
emit(CounterState(count, count ~/ 12));
print('dozen:' + '${state.dozen}');
}
}
/// Subtract 1 from the current state.
void decrement() {
if (state.count > 0) {
final int count = state.count - 1;
emit(CounterState(count, count ~/ 12));
print('dozen:' + '${state.dozen}');
}
}
}
Then in your Widgets, access this as state.count and state.dozen instead of just state.
This solution can be improved, but it is sufficient to get you going.
I want to make a non scrollable grid that in it's whole expands to it's parent. I am trying to run a for loop in the build method to create the rows and columns. But I get the following errors
The element type 'Set<Row>' can't be assigned to the list type 'Widget'.
and
The element type 'Set<Text>' can't be assigned to the list type 'Widget'.
from the for loop. Why is this? And how can I fix this?
import 'package:flutter/material.dart';
class ExpandingGridArguments{
List<Widget> tiles;
int columns;
int rows;
ExpandingGridArguments(List<Widget> tiles, int columns)
{
this.tiles = tiles;
this.columns = columns;
this.rows = (tiles.length / columns).ceil();
}
}
class StaticGrid extends StatelessWidget {
#override
Widget build(BuildContext context) {
final ExpandingGridArguments arguments = ModalRoute.of(context).settings.arguments;
return Column(
children:
[
for(int c = 0; c < arguments.rows; c++ )
{
Row
(
children :
[
for(int r = 0; r < arguments.columns; r++)
{
Text('A row'),
}
]
),
}
]
);
}
}
The syntax of for inside lists is slightly different from what you did.
Instead of:
[
for (var i = 0; i < 42; i++) {
Text('$i')
}
]
it is used without the {}:
[
for (var i = 0; i < 42; i++)
Text('$i')
]
The reason for this being that {} is also used to create Set/Map:
Set<int> hashSet = {};
As such, using {} inside lists for readability is not supported, because Dart would confuse a "block" with the creation of a Set
You could create a function outside the build method to do the for loop and return the widgets
import 'package:flutter/material.dart';
class ExpandingGridArguments{
List<Widget> tiles;
int columns;
int rows;
ExpandingGridArguments(List<Widget> tiles, int columns)
{
this.tiles = tiles;
this.columns = columns;
this.rows = (tiles.length / columns).ceil();
}
}
class StaticGrid extends StatelessWidget {
buildRows(ExpandingGridArguments arguments) {
List<Widget> row = new List();
for(int c = 0; c < arguments.rows; c++ )
{
row.add(
Row
(
children :
[
for(int r = 0; r < arguments.columns; r++)
{
Text('A row'),
}
]
)
)
}
return row;
}
#override
Widget build(BuildContext context) {
final ExpandingGridArguments arguments = ModalRoute.of(context).settings.arguments;
return Column(
children: buildRows(arguments)
);
}
}
Personally, I find it a lot cleaner.
The reason for your errors is because for loops are done differently inside the build method. What you are doing is creating a Set
I used the sample candle stick chart code to draw chart. When I worked in the java7 ,the chart worked fine. But when I tried in the Java8. there is a problem.
I tracked the problem like this:this code is from the sample code of Ensemble :CandlStickChart.java
#Override protected void layoutPlotChildren() {
// we have nothing to layout if no data is present
if(getData() == null) return;
// update candle positions
for (int seriesIndex=0; seriesIndex < getData().size(); seriesIndex++) {
Series<Number,Number> series = getData().get(seriesIndex);
Iterator<Data<Number,Number>> iter = getDisplayedDataIterator(series);
Path seriesPath = null;
if (series.getNode() instanceof Path) {
seriesPath = (Path)series.getNode();
seriesPath.getElements().clear();
}
while(iter.hasNext()) {
System.out.println(i++); // the different place
Data<Number,Number> item = iter.next();
double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));
Node itemNode = item.getNode();
CandleStickExtraValues extra = (CandleStickExtraValues)item.getExtraValue();
if (itemNode instanceof Candle && extra != null) {
Candle candle = (Candle) itemNode;
this is part of the code.the problem is with the "the different palce"
for the iter.hasNext() will preserve the stale value.so, every time I set in new data。the list is further long .
the setdata code like :
ObservableList<XYChart.Data<Number, Number>> newData
= FXCollections.<XYChart.Data<Number, Number>>observableArrayList();
for (int j = 1; j <= leno; j++) {
newData.add(。。。。。。。);//
series.getData().clear();
series.setData(newData);
When I remove the stale data by Iter.remove the exception is:we don't support removeing items from the diplayed data list.
You have to add two calls to removeDataItemFromDisplay to the dataItemRemoved method.
Note: I made series and item final in the example code.
#Override
protected void dataItemRemoved(final Data<Number, Number> item,
final Series<Number, Number> series) {
final Node candle = item.getNode();
if (shouldAnimate()) {
// fade out old candle
FadeTransition ft = new FadeTransition(Duration.millis(500), candle);
ft.setToValue(0);
ft.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
});
ft.play();
} else {
getPlotChildren().remove(candle);
removeDataItemFromDisplay(series, item);
}
}