【问题标题】:Filtering out Movies in Flutter在 Flutter 中过滤掉电影
【发布时间】:2021-08-25 11:30:23
【问题描述】:

我正在用 Flutter 开发一个电影应用程序。 TMDB API 链接https://developers.themoviedb.org/3/getting-started/introduction。我想知道如何按流派过滤电影列表。这是我的应用程序的屏幕截图。

流派 UI 是一个水平列表,我们可以选择任何流派。这是它的屏幕截图。

我想根据流派选择过滤我的电影列表 UI,是否选择了相应的流派显示列表,如果未选择则显示原始列表。如果可能,还提供一些关于多类型过滤的见解。

这是我的流派 UI 代码。

import 'package:flutter/material.dart';
import 'package:flutter_movies_app/utility/Size_Config.dart';

import '../../../constants.dart';

class Genres extends StatefulWidget {
  const Genres({Key? key}) : super(key: key);

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

class _GenresState extends State<Genres> {
  var genres = [
    [28, "Action"],
    [12, "Adventure"],
    [16, "Animation"],
    [35, "Comedy"],
    [80, "Crime"],
    [99, "Documentary"],
    [18, "Drama"],
    [10751, "Family"],
    [14, "Fantasy"],
    [36, "History"],
    [27, "Horror"],
    [10402, "Music"],
    [9648, "Mystery"],
    [10749, "Romance"],
    [878, "Science Fiction"],
    [10770, "TV Movie"],
    [53, "Thriller"],
    [10752, "War"],
    [37, "Western"]
  ];
  List<bool> temp = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < genres.length; i++) temp.add(false);
  }

  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);

    return Container(
      margin: const EdgeInsets.symmetric(vertical: kDefaultPadding / 2),
      height: SizeConfig.screenHeight * 0.05,
      //color: Colors.red,
      child: ListView.builder(
          scrollDirection: Axis.horizontal,
          itemCount: genres.length,
          itemBuilder: (ctx, index) => InkWell(
                onTap: () {
                  if (temp[index]) {
                    setState(() {
                      temp[index] = false;
                    });
                  } else {
                    setState(() {
                      temp[index] = true;
                    });
                  }
                },
                child: Container(
                  alignment: Alignment.center,
                  margin: const EdgeInsets.only(left: kDefaultPadding / 2),
                  padding: const EdgeInsets.symmetric(
                      horizontal: kDefaultPadding,
                      vertical: kDefaultPadding / 4),
                  decoration: BoxDecoration(
                      color: temp[index] ? Colors.amber : Colors.transparent,
                      border: Border.all(
                          color: temp[index]
                              ? Colors.transparent
                              : Colors.black26),
                      borderRadius: BorderRadius.circular(20.0)),
                  child: Text(
                    genres[index].last.toString(),
                    style: TextStyle(
                        color: temp[index]
                            ? Colors.white
                            : kTextColor.withOpacity(0.8),
                        fontSize: SizeConfig.safeBlockHorizontal * 4),
                  ),
                ),
              )),
    );
  }
}

我正在使用提供程序包进行状态管理和 API(TMDB 电影 API)集成。这是我的提供程序 dart 文件中的一些代码。

List<nowPlaying.Result> _nowPlayingMovies = [];
List<nowPlaying.Result> get getNowPlaying => [..._nowPlayingMovies];

Future<void> getNowPlayingMovies({required String type}) async {
    try {
      nowPlaying.NowPlayingModel? nowPlayingModel =
          await GetMoviesTvShows.nowPlayingMovies(type: type, page: 1);
      if (nowPlayingModel != null) {
        List<nowPlaying.Result> temp = [];
        nowPlayingModel.results.forEach((result) {
          if (result.title.isNotEmpty && result.overview.isNotEmpty) {
            temp.add(result);
          }
        });
        _nowPlayingMovies = temp;
        notifyListeners();
      }
    } catch (e, s) {
      print(e);
      print(s);
    }
  }

这是我提出的过滤代码。但我不想更改原始列表,因为在未选择流派时我将需要它。

Future<void> filterByGenre({required int genreId}) async {
    try {
      List<nowPlaying.Result> nowPlayingTemp = [];
      _nowPlayingMovies.forEach((element) {
        if (element.genreIds.contains(genreId)) nowPlayingTemp.add(element);
      });
      List<moviesModel.Result> popularTemp = [];
      _popularLS.forEach((element) {
        if (element.genreIds.contains(genreId)) popularTemp.add(element);
      });
      List<moviesModel.Result> topRatedTemp = [];
      _topRatedLS.forEach((element) {
        if (element.genreIds.contains(genreId)) topRatedTemp.add(element);
      });
      List<moviesModel.Result> upcomingTemp = [];
      _upComingLS.forEach((element) {
        if (element.genreIds.contains(genreId)) upcomingTemp.add(element);
      });
      _nowPlayingMovies = nowPlayingTemp;
      _popularLS = popularTemp;
      _topRatedLS = topRatedTemp;
      _upComingLS = upcomingTemp;
      notifyListeners();
    } catch (e, s) {
      print(e);
      print(s);
    }
  }

你能帮助你的开发伙伴吗?

【问题讨论】:

    标签: flutter dart provider


    【解决方案1】:

    您对激活和停用类型的操作是危险的。

    相反,您可以为流派创建一个对象 Like:

    class Genre {
      int id;
      String title;
      bool active;
    
      Genre(this.id, this.title, {this.active = false});
    
      void toggleActive() {
        active = !active;
      }
    }
    

    有了这个,您将有一个更简单的界面来激活和停用流派。

    现在,让我们看看如何过滤电影。

    考虑某种方式将所有电影放在一起。

    class Movie {
      List<int> genreIds;
      String name;
    
      Movie(this.name,this.genreIds);
    }
    
    class MovieGenerator {
      static Future<List<Movie>> getMovies() async{
        return [
          Movie("Dairy kid", [1,2]),
          Movie("Dairy Man", [1]),
        ];
      }
    }
    

    过滤可以通过以下方式完成:

             FutureBuilder<List<Movie>>(
              future: MovieGenerator.getMovies(),
              builder: (c, snapshot) {
                if(snapshot.hasData) {
                  var movies = snapshot.data;
                  var selectedGenres = genres.where((e) => e.active).map((e) => e.id);
                  var filteredMovies = movies.where((a) {
                    bool shouldAdd = false;                
                    for(int i = 0; i<a.genreIds.length; i++) {
                      if(selectedGenres.contains(a.genreIds[i])) {
                        shouldAdd = true;
                        break;
                      }
                    }
                    
                    return shouldAdd;
                  }).toList();
                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: List.generate(
                     filteredMovies.length,
                      (i) => Text(filteredMovies[i].name) 
                    ),
                  );
                }else {
                  return Container();
                }
              }
            ),
    

    所以,整个代码可能看起来像:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Home(),
        );
      }
    }
    
    class Genre {
      int id;
      String title;
      bool active;
    
      Genre(this.id, this.title, {this.active = false});
    
      void toggleActive() {
        active = !active;
      }
    }
    
    class Movie {
      List<int> genreIds;
      String name;
      
      Movie(this.name,this.genreIds);
    }
    
    class MovieGenerator {
      static Future<List<Movie>> getMovies() async{
        return [
          Movie("Dairy kid", [1,2]),
          Movie("Dairy Man", [1]),
        ];
      }
    }
    
    class Home extends StatefulWidget {
      @override
      State<Home> createState() => HomeState();
    }
    
    class HomeState extends State<Home> {
      List<Genre> genres;
    
      @override
      void initState() {
        super.initState();
        genres = [
          Genre(1, "Action", active: true),
          Genre(2, "Comedy"),
        ];
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ListView(children: [
            SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                children: List.generate(genres.length, (i) {
                  var cur = genres[i];
                  return Chip(
                      title: cur.title,
                      active: cur.active,
                      onTap: () {
                        setState(() {
                          genres[i].toggleActive();
                        });
                      });
                }),
              ),
            ),
            FutureBuilder<List<Movie>>(
              future: MovieGenerator.getMovies(),
              builder: (c, snapshot) {
                if(snapshot.hasData) {
                  var movies = snapshot.data;
                  var selectedGenres = genres.where((e) => e.active).map((e) => e.id);
                  var filteredMovies = movies.where((a) {
                    bool shouldAdd = false;                
                    for(int i = 0; i<a.genreIds.length; i++) {
                      if(selectedGenres.contains(a.genreIds[i])) {
                        shouldAdd = true;
                        break;
                      }
                    }
                    
                    return shouldAdd;
                  }).toList();
                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: List.generate(
                     filteredMovies.length,
                      (i) => Text(filteredMovies[i].name) 
                    ),
                  );
                }else {
                  return Container();
                }
              }
            ),
          ]),
        );
      }
    }
    
    class Chip extends StatelessWidget {
      final String title;
      final bool active;
      final Function onTap;
    
      const Chip({Key key, this.title, this.active, this.onTap}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
          onTap: onTap,
          child: Container(
              padding: const EdgeInsets.all(10.0),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(999.0),
                color: active ? Colors.red : Colors.grey,
              ),
              child: Text(title,
                  style: TextStyle(
                    color: active ? Colors.white : Colors.black,
                  ))),
        );
      }
    }
    

    您可以在 dartpad.dev 中运行此代码进行检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-21
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多