4

I have this array/list in Flutter which contains some simple widgets:

final List<Widget> steps = [
      _step0(),
      _step1(),
      _step2(),
    ];

I can display all of them like this:

itemBuilder: (BuildContext context, int index) {
   return steps[index];
}

But how can I pass a value to one of the widget from the itemBuilder?

Widget step0 build(String something) {}
4
  • Can you elaborate more, about what you want to achieve? Do you want multiple methods as your code step1(), step2() or using single method and pass argument if have. Commented Dec 29, 2019 at 13:27
  • pass some arguments if needed as commented on comment on the other answer Commented Dec 29, 2019 at 15:53
  • You should specify any issue..... Commented Dec 29, 2019 at 16:06
  • @dadumohapatra I already specified the issue: I don't know how to pass values to a widget that it has been initiated into a List already Commented Dec 29, 2019 at 16:25

3 Answers 3

4

If I got you, this is what you are trying to achieve you need to have a list of Function not Widget:

class _MyHomePageState extends State<MyHomePage> {
  List<Function> steps;

  @override
  void initState() {
    steps = [
      _step0,
      _step1,
      _step2,
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: ListView.builder(
          itemCount: steps.length,
          itemBuilder: (BuildContext context, int index) {
            return steps[index](somethinng: "something");
          },
        ),
      ),
    );
  }

  Widget _step0({String somethinng}) {
    return Container(child: Text(somethinng ?? "anything"));
  }

  Widget _step1({String somethinng}) {
    return Container(child: Text(somethinng ?? "anything"));
  }

  Widget _step2({String somethinng}) {
    return Container(child: Text(somethinng ?? "anything"));
  }
}

If you can adjust your scenario to match with one method(without step0, step1, ...), you can try something like below or get an idea and do some changes to your scenario:

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: ListView(
          children: List.generate(10, (int index) {
            return ParentWidget(
              data: index,
              function: () => print("whooo! $index"),
              child: Text(index.toString(), style: TextStyle(fontSize: 20)),
            );
          }),
        ),
      ),
    );
  }
}

class ParentWidget extends StatefulWidget {
  final Widget child;
  final int data;
  final Function function;

  ParentWidget({this.child, this.data, this.function});

  @override
  _ParentWidgetState createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State<ParentWidget> {
  @override
  void initState() {
    print(widget.data);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: widget.function,
      child: Container(
        child: (widget.child != null) ? widget.child : SizedBox(),
      ),
    );
  }
}

If you have large collection of data, please dont use, List.generate() use ListView.builder like you are doing right now.

If this not what you are looking for please let me know to delete this answer.

Sign up to request clarification or add additional context in comments.

3 Comments

That's perfect! Thanks mate
Unfortunately this just works for Stateles widgets. When you try to change the state on one of those widgets it doesn't work
@Dani That was not in your question right? so, according to what you have I provided an answer, if I correct.
1

I solved it just changing to List of Functions returning Widgets. In your case you would need to:

final List<Function> steps = [
  (input) => _step0(input),
  (input) => _step1(input),
  (input) => _step2(input),
];

Then when you loop over it you just pass the argument to the constructor as:

itemBuilder: (BuildContext context, int index) {
   return steps[index](input);
}

Comments

0

You mean something like this?:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return _myListView(context);
  }
}

Widget _myListView(BuildContext context) {
  final List<Widget> steps = [
    _step0(1),
    _step1(2),
    _step2(3),
  ];

  return ListView.builder(
    itemCount: steps.length,
    itemBuilder: (BuildContext context, int index) {
      return steps[index];
    },
  );
}

_step0(int number) {
  print(number);
}

_step1(int number) {
  print(number);
}

_step2(int number) {
  print(number);
}

9 Comments

but you have already the value you're passing on the List. Let's say that you need to do some calculation inside your itemBuilder and pass some dynamic value, how would you send that?
In this case maybe I would use a Provider, or a variable with a stateful widget, and update accordingly. Lets say with a (if index == 2 -> variable == whatever logic you want).
Got you. I have a provider already but that information inside it is being shared through my pages. In this case, I don't want this information outside this widget. Is there no other possible way then?
I dont see the problem in share the Provider. But you could use some logic to send diffent info withouth need of any Provider. To help with implementation would need more of your code and know more, and why.
I mean, there is no problem using the provider but imo I think it should be used just to share info, right?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.