0

I'm currently learning to write Mobile Applications in Flutter using Dart and recently I wanted to try to build an App where you can keep which movies you want to still watch and get some basic info about them. Now this is just for me, to train to understand the basic concepts of flutter and I wanted to ask how to make multiple widgets from one list. Ill show you my code and then elaborate more on it.

import 'package:flutter/material.dart';

class MovieList {
  String name;
  String url;
  String description;
  String actors;
  int id;

  MovieList(this.name, this.url, this.description, this.actors, this.id);

  var movies = [
    {
      "21",
      "assets/images/21_movie.jpeg",
      "randomDescriptionfor21",
      "idkwhichactors.1",
      1
    },
    {
      "Dirty Dancing",
      "assets/images/dirty_dancing_movie.jpeg",
      "randomDescriptionforDirtyDancing",
      "idkwhichactors.2",
      2
    },
    {
      "Endless love",
      "assets/images/endless_love_movie.jpeg",
      "randomDescriptionforEndlesslove",
      "idkwhichactors.3",
      3
    },
    {
      "Gut gegen Nordwind",
      "assets/images/gut_gegen_nordwind_movie.jpeg",
      "randomDescriptionforNordwind",
      "idkwhichactors.4",
      4
    },
    {
      "Illuminati",
      "assets/images/illuminati_movie.jpeg",
      "randomDescriptionforIlluminati",
      "idkwhichactors.5",
      5
    },
    {
      "Bridget Jones",
      "assets/images/jones_movie.jpeg",
      "randomDescriptionforBridgetJones",
      "idkwhichactors.6",
      6
    },
    {
      "Kevin allein Zuhaus",
      "assets/images/kevin_allein_zuhaus_movie.jpeg",
      "randomDescriptionforKevin",
      "idkwhichactors.7",
      7
    },
    {
      "Little Woman",
      "assets/images/little_woman_movie.jpeg",
      "randomDescriptionforLittleWoman",
      "idkwhichactors.8",
      8
    },
    {
      "Liebe braucht keine Ferien",
      "assets/images/love_movie.jpeg",
      "randomDescriptionforLiebeundFerien",
      "idkwhichactors.9",
      9
    },
    {
      "Marvel-Filme",
      "assets/images/marvel_movie.jpeg",
      "randomDescriptionforMarvel",
      "idkwhichactors.10",
      10
    },
    {
      "Oceans 12",
      "assets/images/oceans_12_movie.jpeg",
      "randomDescriptionforOceans12",
      "idkwhichactors.11",
      11
    },
    {
      "Pirates of the Carribean",
      "assets/images/pirates_carribean_movie.jpeg",
      "randomDescriptionforPiraten",
      "idkwhichactors.12",
      12
    },
    {
      "Romeo und Julia",
      "assets/images/romeo_and_julia_movie.jpeg",
      "randomDescriptionforRomeoxJulia",
      "idkwhichactors.13",
      13
    },
    {
      "A star is born",
      "assets/images/star_movie.jpeg",
      "randomDescriptionforStar",
      "idkwhichactors.14",
      14
    },
    {
      "Die Entdeckung der Unendlichkeit",
      "assets/images/stephen_hawking_movie.jpeg",
      "randomDescriptionforStephen",
      "idkwhichactors.15",
      15
    },
    {
      "Frühstück bei Tiffany",
      "assets/images/tiffany_movie.jpeg",
      "randomDescriptionforTIffany",
      "idkwhichactors.16",
      16
    }
  ];
}

So as you see I define a class, MovieList, where I define certain variables (name, url, description, actors, id). Now under the initialisation of those Im defining a list with multiple movies, that have all of those attributes.

  1. Question: How can use the list to create multiple Objects of MovieList and how could I implement a loop (or sth else idk how it would be done) to display multiple widgets, matching the movies I defined in the "movies" list?

  2. Question: Is this even the right approach and would that even work? Like I said I'm pretty much starting with dart and flutter so Id really use your help.

Thanks in advance :)

So thanks a lot you already really helped me a lot. Now I wanted to do my Card Widget and that's basically how I changed up the code: 1:

``
import 'package:flutter/material.dart';
import './header.dart';
import './image_widget.dart';
import './movies_to_watch.dart';

var movies = [
  {
    'title': '21',
    'bannerPath': 'assets/images/21_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Dirty Dancing',
    'bannerPath': 'assets/images/dirty_dancing_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Endless Love',
    'bannerPath': 'assets/images/endless_love_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Gut gegen Nordwind',
    'bannerPath': 'assets/images/gut_gegen_nordwind_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Illuminati',
    'bannerPath': 'assets/images/illuminati_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Bridget Jones',
    'bannerPath': 'assets/images/jones_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ]
  },
  {
    'title': 'Kevin allein zuhaus',
    'bannerPath': 'assets/images/kevin_allein_zuhaus_movie.jpeg',
    'description': 'randomDescriptionforPirates',
    'actors': [
      'some actor',
    ],
  },
];

class Body extends StatelessWidget {
  const Body({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: EdgeInsets.only(bottom: 20.0),
            child: HeaderWidget(),
          ),
          Padding(
            padding: EdgeInsets.only(right: 20.0, left: 20.0),
            child: FilmstoWatch(),
          ),
          Padding(
            padding: EdgeInsets.only(right: 20.0, left: 20.0),
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                children: [
                  for (var movie in movies)
                    MovieWidget(model: MovieModel.fromJson(movie)),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
``

and 2:

``
import 'package:flutter/material.dart';

class MyClass {
  // here I am generating fake movies but you should use the data that you already have
  List<Map<String, dynamic>> movies = List.generate(
      15,
      (index) => {
            'title': 'fake title $index',
            'actors': ['fake actor $index'],
            'bannerPath': 'some/fake/path/$index',
            'description': 'some fake description $index',
          });

  List<MovieModel> get models =>
      movies.map((movie) => MovieModel.fromJson(movie)).toList();

  List<Widget> get widgets =>
      models.map((model) => MovieWidget(model: model)).toList();
}

class MovieModel {
  MovieModel({
    required this.title,
    required this.actors,
    required this.bannerPath,
    required this.description,
  });

  factory MovieModel.fromJson(Map<String, dynamic> json) {
    return MovieModel(
      title: json['title'],
      actors: json['actors'],
      bannerPath: json['bannerPath'],
      description: json['description'],
    );
  }

  String title;
  String bannerPath;
  String description;
  List<String> actors;
}

class MovieWidget extends StatelessWidget {
  const MovieWidget(
      {required this.model}); // if you decide to not make a model class, you would pass each value individually

  final MovieModel model;

  @override
  Widget build(BuildContext context) {
    // obviously this can be any widget you want
    return SingleChildScrollView(
      child: Card(
        shape:
            RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
        elevation: 10.0,
        margin: const EdgeInsets.all(10.0),
        child: Column(
          children: [
            Text(model.title),
            Container(
              height: 200,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(10.0),
                image: DecorationImage(
                  image: AssetImage(model.bannerPath),
                ),
              ),
            ),
            Text(model.description),
            if (model.actors.isNotEmpty) Text(model.actors.first),
          ],
        ),
      ),
    );
  }
}
``

If I run this I get this error thrown:

https://drive.google.com/file/d/1zbmsOq3lQIPUIZ92mvrg4sCcT21W8cc4/view?usp=sharing

when I replace the model.bannerPath with the actual string that should be inserted there it works. Thanks a lot for your help again!

1 Answers1

2

I will be honest with you, I am not a huge fan of sets and have no idea why you've decided to use them, so I changed your sets into maps, I also removed the integer they had cause I can't tell why it would be useful. As I said, that is just how I code and I hope you can decide if you want to keep the sets or not

var movies = [
  ...
  {
    'title': 'Pirates of the Carribean',
    'banner': 'assets/images/pirates_carribean_movie.jpeg',
    'description': 'randomDescriptionforPiraten',
    'actors': ['some actor'],
  },
  ...
];

I would also recommend you make a MovieModel class that can store those values in a type safe way

class MovieModel {
  String title;
  String bannerPath;
  String description;
  List<String> actors;
}

Then you should make some widget that can display the information that you want

class MovieWidget extends StatelessWidget {
  MovieWidget({required this.model}); // if you decide to not make a model class, you would pass each value individually

  final MovieModel model;

  @override
  Widget build(BuildContext context) {
    // obviously this can be any widget you want
    return Column(
      children: [
        Text(model.title),
        Text(model.banner),
        Text(model.description),
        Text(model.actors.first),
      ],
    );
  }
}

Finally to make your list of movies into a list of widgets, first you need to turn it into a list of models

final List<MovieModel> models = movies.map((movie) => MovieModel(title: movie['title'], banner: movie['banner'], description: movie['description'], actors: movie['actors']));

Then you can do the same with the widgets:

List<Widget> widgets = models.map((model) => MovieWidget(model: model));

EDIT:

Regarding your comment about using the old movies variable.

If you want to add all of those widgets to a Column for example:

return Column(
  children: [
    for (var movie in movies)
      MovieWidget(model: MovieModel.fromJson(movie)),
  ],
);

Obviously in the example above, if you want to add padding you just have to surround MovieWidget with padding.

h8moss
  • 4,626
  • 2
  • 9
  • 25
  • Hi, thanks a lot for the help. Ive been using sets more than maps, which led to me not being really secure about using the maps but Im seeing the advantages they bring. Basically I still have a question. Maybe Im adding the two List variables (last two lines you told me to add) or Im doing something else wrong but so far it always was underlined red with this message: ``The instance member 'movies' can't be accessed in an initializer. Try replacing the reference to the instance member with a different expression`` Thanks a lot for the help again and I hope you have a good day :) – Jonas Jacob Biermann Nov 01 '21 at 22:01
  • Are you trying to make widgets and models class variables? If you are, the error comes from there, a possible solution is to make them getter functions, from `type variableName = value;` to `type get variableName => value`, so `List get models => movies.map((movie) => MovieModel(...));` and `List get widgets => models.map((model) => MovieWidget(model: model));`, but I'm not sure this will solve the issue. – h8moss Nov 02 '21 at 00:38
  • So I get multiple arrows. Just to make sure that I dont get those arrows because I did sth wrong... Could you show how the code would look in a file? Im not sure I put everything where I should have. This would be a great help. Thanks in advance:) – Jonas Jacob Biermann Nov 04 '21 at 17:16
  • I did end up making some slight changes to the code, in order for it to work, bu here is the whole thing: https://pastebin.com/MzMq6fKR – h8moss Nov 04 '21 at 18:17
  • Thanks a lot what do I pass to the widget if I want to use it in a different place? – Jonas Jacob Biermann Nov 04 '21 at 18:45
  • Oh and since I would like to actually understand and learn from this experience... Do you have any like documentation concerning this? Would be great to get some recommendations – Jonas Jacob Biermann Nov 04 '21 at 18:46
  • to use the widget, you just go: `MovieWidget(model: )`. Which specific parts of my code would you like documentation for? [here is the documentation for the .map method I used](https://api.dart.dev/stable/2.14.4/dart-core/Iterable/map.html), I also used [short hand functions](https://dart.dev/guides/language/language-tour#functions), [anonymous functions](https://dart.dev/guides/language/language-tour#anonymous-functions) and [the get keyword](https://dart.dev/guides/language/language-tour#getters-and-setters) – h8moss Nov 04 '21 at 19:36
  • Thanks Ive never used short hand functions and I dont have a lot of experience in general. What do I ultimately insert in the part? – Jonas Jacob Biermann Nov 04 '21 at 20:47
  • You would insert an instance of the class `MovieModel`, for example: `MovieWidget(model: MovieModel(title: 'some title', actors: ['some actors'], ...));` like that. – h8moss Nov 05 '21 at 00:41
  • So when I add this I get this error: https://drive.google.com/file/d/18IIBgtbBSKAwUPqYx4CR6fp-5vdrJ_d_/view?usp=sharing – Jonas Jacob Biermann Nov 05 '21 at 15:47
  • That is weird, when I run my code, I don't get that error, here is a list of things you could try in order to fix it: 1. run `flutter clean` and `flutter pub get` on your project. 2. make movie model class const by making every field final and adding `const` before the constructor, this will probably cause some build error, so make sure you fix those. 3. Add `const` before the actors list `actors: const ['some actor']`. This is a weird error because I can't reproduce it, if none of what I said works, you could send me your code so I can make sure they are the same. – h8moss Nov 05 '21 at 18:31
  • I added the code above in the original question – Jonas Jacob Biermann Nov 05 '21 at 18:58
  • Ok, I believe the problem stems from making the children of Column const, so change `children: const [...]` to `children: [...]` – h8moss Nov 05 '21 at 19:12
  • Thanks a lot this worked, now do I just provide each movie one by one or can I use the "old" movies variable and pass that? – Jonas Jacob Biermann Nov 05 '21 at 19:19
  • Not sure about using the "old" movies variable, because it is a list of sets, and as we discussed I don't really use them that much. I edited my question to show how to use the new movies variable in a column. Does that help? – h8moss Nov 05 '21 at 20:13
  • Oh yeah I actually mean the new movie variable with the maps but Ill try that – Jonas Jacob Biermann Nov 05 '21 at 20:18
  • Hi I edited it a bit again and there seems to be a problem with bannerPath... I put the code in the question – Jonas Jacob Biermann Nov 05 '21 at 20:58
  • That is a weird error, sadly I don't know how to fix it, I can give you some suggestions, like before, you should run flutter clean to clean the project, second, you could try printing model.bannerPath and comparing it to the actual string: `print(model.bannerParh); print(model.bannerPath == 'assets/images/jones_movie.jpeg');`, if that prints `false`, please let me know so we can see why. – h8moss Nov 05 '21 at 21:31
  • I also found some other treads with similar problems, please take a look: [1](https://github.com/flutter/flutter/issues/17870), [2](https://stackoverflow.com/questions/53659809/fluttererror-unable-to-load-asset), [3](https://stackoverflow.com/questions/64158543/flutter-unable-to-load-image-asset) – h8moss Nov 05 '21 at 21:32
  • So by now I dont get the error thrown anymore but still the Images dont pop up... I dont get any errors there is just white space idk why... https://drive.google.com/file/d/1INxJuZfjifJPbR-1zy-2KBMwd0T6UoNC/view?usp=sharing There you see all the relevant code and the output – Jonas Jacob Biermann Nov 08 '21 at 14:41
  • I am very sorry, I don't know why this error is happening, I also failed at reproducing the same error on my machine. I recommend you ask a new question here at SO to try and get more community members onvolved. – h8moss Nov 08 '21 at 18:15