从另一个小部件传递到重新渲染UI的参数中更新一个小部件

发布于 2025-01-22 15:20:14 字数 7654 浏览 1 评论 0原文

我有两个小部件是一个ListView Builder,它从REST API水平显示按钮列表,而另一个未来的构建器则根据按钮的类别名称显示了来自另一个REST API的图像。

按类别按钮确实将值传递给了我创建的Fetchphotos未来,我可以看到类别名称出现在调试控制台中。但是,尽管更改了变量值并在类别按钮上打开setState内部的fetchphoto,但UI永远不会重新呈现。

我在下面的类别清单中发表了评论,我认为我已经解决了,但无济于事 //设置状态以更新fetchphotos和重新渲染UI不起作用,

我该如何使用UI从Fetchphotos Future中使用新近获取的JSON数据刷新并添加了更新的QueryString参数?

Future<List<Category>> fetchCategories(http.Client client) async {
  final response = await client
      .get(Uri.parse('./categories'));
  return compute(parseCategories, response.body);
}

List<Category> parseCategories(String responseBody) {
  final parsed1 = jsonDecode(responseBody);
  parsed1.insert(0, {"id": "0", "name": "All");
  final parsed = parsed1.cast<Map<String, dynamic>>();
  return parsed.map<Category>((json) => Category.fromJson(json)).toList();
}

class Category {
  final String id;
  final String name;
  final int useCount;
  const Category(
      {required this.id, required this.name, required this.useCount});

  factory Category.fromJson(Map<String, dynamic> json) {
    return Category(
      id: json['id'] as String,
      name: json['name'] as String
    );
  }
}

class CategoryList extends StatefulWidget {
  const CategoryList({Key? key, required this.categories}) : super(key: key);

  final List<Category> categories;

  @override
  State<CategoryList> createState() => _CategoryListState();
}

var chosenCategory = "all";

class _CategoryListState extends State<CategoryList> {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: widget.categories.length,
      itemBuilder: (context, index) {
        return Padding(
            padding: EdgeInsets.only(left: 2, right: 2),
            child: ElevatedButton(
              onPressed: () {
                setState(() {
                // SET STATE TO UPDATE fetchPhotos AND RE-RENDER UI NOT WORKING
                chosenCategory = widget.categories[index].name;
                fetchPhotos(http.Client(), chosenCategory);
                });
              },
              child: Text(widget.categories[index].name),
              
            ));
      },
    );
  }
}

Future<List<Photo>> fetchPhotos(http.Client client, chosenCategory) async {
  print("---- CHOSEN CATEGORY ------ $chosenCategory");
  print(chosenCategory);

  final response = await client.get(Uri.parse(
      ' 'https://localhost/photoapp/getPhotos?searchString=$chosenCategory'));
  '));
  return compute(parsePhotos, response.body);
}

List<Photo> parsePhotos(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}

class Photo {
  final String id;
  final String name;
  final String imageUrl;

  const Photo({
    required this.id,
    required this.name,
    required this.imageUrl,
  });

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as String,
      name: json['name'] as String,
      imageUrl: json['imageUrl'] as String,
    );
  }
}



class PhotosList extends StatefulWidget {
  const PhotosList({Key? key, required this.photos}) : super(key: key);

  final List<Photo> photos;

  @override
  State<PhotosList> createState() => _PhotosListState();
}

class _PhotosListState extends State<PhotosList> {
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: widget.photos.length,
      itemBuilder: (context, index) {
        return Stack(
          alignment: Alignment.topCenter,
          children: <Widget>[
            InkWell(
                onTap: () { },
                child: Container(
                  height: 300.0,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      fit: BoxFit.cover,
                      alignment: FractionalOffset.center,
                      image: widget.photos[index].imageUrl,
                  ),
                    ),
                  ),
                )), // Container Image
            Container(
              margin: const EdgeInsets.only(top: 150),
              width: MediaQuery.of(context).size.width * 0.92,
              child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(widget.photos[index].name,
                      style: TextStyle(fontSize: 12, color: Colors.white),
                      maxLines: 1,
                      textAlign: TextAlign.center)),
              decoration: BoxDecoration(
                color: Colors.black,
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.withOpacity(0.8),
                    spreadRadius: 1,
                    blurRadius: 3,
                    offset: const Offset(1, 1),
                  ),
                ],
              ),
            ),
          ],
        );
      },
    );
  }
}

class AlbumPage extends StatefulWidget {
 AlbumPage({Key, key, this.title}) : super(key: key);

  final String? title;

  @override
  _AlbumState createState() => _ClbumState();
}

class _AlbumState extends State<AlbumPage> {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => AlbumCubit(AlbumState.initial),
      child: AlbumWidget(),
    );
  }
}

class AlbumWidget extends StatefulWidget {
  @override
  _AlbumWidgetState createState() => _AlbumWidgetState();
}

class _AlbumWidgetState extends State<AlbumWidget> {
  @override
  void initState() {
    super.initState();


  }

  appBar() {
    return AppBar(
        title: const Text("Photo Album"),
        leading: GestureDetector(
          child: const Icon(
            Icons.arrow_back_ios,
            color: Colors.white,
          ),
        ));
  }

  getCategories() {
    return Container(
      padding: const EdgeInsets.all(14.0),
      color: Colors.grey,
      width: double.infinity,
      height: 60,
      child: FutureBuilder<List<Category>>(
        future: fetchCategories(http.Client()),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred.'),
            );
          } else if (snapshot.hasData) {
            return CategoryList(categories: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }

  getPhotos() {
    return Flexible(
      child: FutureBuilder<List<Photo>>(
        future: fetchPhotos(http.Client(), chosenCategory),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred.'),
            );
          } else if (snapshot.hasData) {
            return PhotosList(photos: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: appBar(),
        body: Column(
          children: <Widget>[
            getCategories(),
            getPhotos(),
          ],
        ));
  }
}
 

I have two widgets one is a listview builder that displays a list of buttons horizontally from a rest API and the other a future builder that displays images from another rest API based on the category name of the button.

Pressing a category button does pass the value to the fetchPhotos future I have created and I can see the category name appear in the debug console. However, the UI never re-renders, despite changing the variable value and calling fetchPhoto inside setState onPressed on a category button.

I've made a comment in the categoryList below where I thought I had it solved but to no avail
// SET STATE TO UPDATE fetchPhotos AND RE-RENDER UI NOT WORKING

How can I go about getting the ui to refresh with the newly fetched JSON data from the fetchPhotos future with the updated querystring parameter added?

Future<List<Category>> fetchCategories(http.Client client) async {
  final response = await client
      .get(Uri.parse('./categories'));
  return compute(parseCategories, response.body);
}

List<Category> parseCategories(String responseBody) {
  final parsed1 = jsonDecode(responseBody);
  parsed1.insert(0, {"id": "0", "name": "All");
  final parsed = parsed1.cast<Map<String, dynamic>>();
  return parsed.map<Category>((json) => Category.fromJson(json)).toList();
}

class Category {
  final String id;
  final String name;
  final int useCount;
  const Category(
      {required this.id, required this.name, required this.useCount});

  factory Category.fromJson(Map<String, dynamic> json) {
    return Category(
      id: json['id'] as String,
      name: json['name'] as String
    );
  }
}

class CategoryList extends StatefulWidget {
  const CategoryList({Key? key, required this.categories}) : super(key: key);

  final List<Category> categories;

  @override
  State<CategoryList> createState() => _CategoryListState();
}

var chosenCategory = "all";

class _CategoryListState extends State<CategoryList> {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: widget.categories.length,
      itemBuilder: (context, index) {
        return Padding(
            padding: EdgeInsets.only(left: 2, right: 2),
            child: ElevatedButton(
              onPressed: () {
                setState(() {
                // SET STATE TO UPDATE fetchPhotos AND RE-RENDER UI NOT WORKING
                chosenCategory = widget.categories[index].name;
                fetchPhotos(http.Client(), chosenCategory);
                });
              },
              child: Text(widget.categories[index].name),
              
            ));
      },
    );
  }
}

Future<List<Photo>> fetchPhotos(http.Client client, chosenCategory) async {
  print("---- CHOSEN CATEGORY ------ $chosenCategory");
  print(chosenCategory);

  final response = await client.get(Uri.parse(
      ' 'https://localhost/photoapp/getPhotos?searchString=$chosenCategory'));
  '));
  return compute(parsePhotos, response.body);
}

List<Photo> parsePhotos(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
  return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}

class Photo {
  final String id;
  final String name;
  final String imageUrl;

  const Photo({
    required this.id,
    required this.name,
    required this.imageUrl,
  });

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as String,
      name: json['name'] as String,
      imageUrl: json['imageUrl'] as String,
    );
  }
}



class PhotosList extends StatefulWidget {
  const PhotosList({Key? key, required this.photos}) : super(key: key);

  final List<Photo> photos;

  @override
  State<PhotosList> createState() => _PhotosListState();
}

class _PhotosListState extends State<PhotosList> {
  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: widget.photos.length,
      itemBuilder: (context, index) {
        return Stack(
          alignment: Alignment.topCenter,
          children: <Widget>[
            InkWell(
                onTap: () { },
                child: Container(
                  height: 300.0,
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      fit: BoxFit.cover,
                      alignment: FractionalOffset.center,
                      image: widget.photos[index].imageUrl,
                  ),
                    ),
                  ),
                )), // Container Image
            Container(
              margin: const EdgeInsets.only(top: 150),
              width: MediaQuery.of(context).size.width * 0.92,
              child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(widget.photos[index].name,
                      style: TextStyle(fontSize: 12, color: Colors.white),
                      maxLines: 1,
                      textAlign: TextAlign.center)),
              decoration: BoxDecoration(
                color: Colors.black,
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.withOpacity(0.8),
                    spreadRadius: 1,
                    blurRadius: 3,
                    offset: const Offset(1, 1),
                  ),
                ],
              ),
            ),
          ],
        );
      },
    );
  }
}

class AlbumPage extends StatefulWidget {
 AlbumPage({Key, key, this.title}) : super(key: key);

  final String? title;

  @override
  _AlbumState createState() => _ClbumState();
}

class _AlbumState extends State<AlbumPage> {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => AlbumCubit(AlbumState.initial),
      child: AlbumWidget(),
    );
  }
}

class AlbumWidget extends StatefulWidget {
  @override
  _AlbumWidgetState createState() => _AlbumWidgetState();
}

class _AlbumWidgetState extends State<AlbumWidget> {
  @override
  void initState() {
    super.initState();


  }

  appBar() {
    return AppBar(
        title: const Text("Photo Album"),
        leading: GestureDetector(
          child: const Icon(
            Icons.arrow_back_ios,
            color: Colors.white,
          ),
        ));
  }

  getCategories() {
    return Container(
      padding: const EdgeInsets.all(14.0),
      color: Colors.grey,
      width: double.infinity,
      height: 60,
      child: FutureBuilder<List<Category>>(
        future: fetchCategories(http.Client()),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred.'),
            );
          } else if (snapshot.hasData) {
            return CategoryList(categories: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }

  getPhotos() {
    return Flexible(
      child: FutureBuilder<List<Photo>>(
        future: fetchPhotos(http.Client(), chosenCategory),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred.'),
            );
          } else if (snapshot.hasData) {
            return PhotosList(photos: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: appBar(),
        body: Column(
          children: <Widget>[
            getCategories(),
            getPhotos(),
          ],
        ));
  }
}
 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文