skip to Main Content

i am very new in flutter…

So, i tried to follow tutorial that sometimes i change it litle bit so it could run like i want it to. so, i am making an infinitescroll to get the data from API which has pagination in it (laravel pagination).

Here is the code that i am working on

class searchBerita extends StatefulWidget {
  const searchBerita({super.key});

  @override
  State<searchBerita> createState() => _searchBeritaState();
}

class _searchBeritaState extends State<searchBerita> {
  int page = 1;
  List<ArticleList>? articleList;
  ScrollController _listController = ScrollController();

  @override
  void initState() {
    super.initState();
    _listController.addListener(() {
      print('scroll: ' + _listController.position.maxScrollExtent.toString());
      if (_listController.position.maxScrollExtent ==
          _listController.position.pixels) {
        page++;
        print('page : ' + page.toString());
        setState(() {});
      }
    });
  }

  @override
  void dispose() {
    _listController.dispose();
    super.dispose();
  }

  Future<List<ArticleList>> getListArtikel() async {
    List<ArticleList> articleData = [];
    try {
      var response = await http.post(
        Uri.parse(apiUrl + '/guest/search-article?page=${page}'),
      );

      if (response.statusCode == 200) {
        var data = jsonDecode(response.body.toString());

        for (Map<String, dynamic> item in data['data']['data_article']) {
          articleData.add(ArticleList.fromJson(item));
        }

        return articleList = articleData;
      } else {
        print('failed');
        throw Exception('failed');
      }
    } catch (e) {
      print(e.toString());
      throw Exception('failed');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        padding: EdgeInsets.all(20.0),
        children: [
          const _TemukanBerita(),
          FutureBuilder(
              future: getListArtikel(),
              builder: (context, AsyncSnapshot<List<ArticleList>> snapshot) {
                if (snapshot.connectionState == ConnectionState.done) {
                  if (snapshot.data == null) {
                    return const Center(child: Text('Something went wrong'));
                  }

                  return Container(
                    height: MediaQuery.of(context).size.height,
                    child: ListView.builder(
                      controller: _listController,
                      itemCount: snapshot.data!.length ?? 0,
                      scrollDirection: Axis.vertical,
                      shrinkWrap: true,
                      itemBuilder: (context, index) {
                        return InkWell(
                          onTap: () {
                            try {
                              Provider.of<Article>(context, listen: false)
                                  .getDetailArtikel(
                                      context, snapshot.data![index].slug!);
                            } catch (err) {
                              print(err);
                            }
                          },
                          child: Padding(
                            padding: const EdgeInsets.only(top: 10.0),
                            child: Material(
                              child: Material(
                                child: Container(
                                  width: MediaQuery.of(context).size.width,
                                  decoration: BoxDecoration(
                                      color: Colors.white,
                                      border: Border.all(
                                          color: Colors.grey[300]!, width: 1.0),
                                      borderRadius: BorderRadius.all(
                                          Radius.circular(10))),
                                  child: Row(
                                    children: <Widget>[
                                      CachedNetworkImage(
                                        imageUrl: snapshot.data![index]!.image!,
                                        imageBuilder: (context, imageProvider) {
                                          return Container(
                                            height: 100,
                                            width: 100,
                                            decoration: BoxDecoration(
                                              borderRadius: BorderRadius.all(
                                                  Radius.circular(8.0)),
                                              image: DecorationImage(
                                                  image: imageProvider,
                                                  fit: BoxFit.cover),
                                            ),
                                          );
                                        },
                                        progressIndicatorBuilder: (context, url,
                                                downloadProgress) =>
                                            CircularProgressIndicator(
                                                value:
                                                    downloadProgress.progress),
                                        errorWidget: (context, url, error) =>
                                            Icon(Icons.error),
                                      ),
                                      Row(
                                        mainAxisAlignment:
                                            MainAxisAlignment.spaceBetween,
                                        children: <Widget>[
                                          Container(
                                            padding:
                                                EdgeInsets.only(left: 10.0),
                                            width: MediaQuery.of(context)
                                                    .size
                                                    .width -
                                                200,
                                            child: Column(
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.start,
                                              children: <Widget>[
                                                Row(
                                                  crossAxisAlignment:
                                                      CrossAxisAlignment.center,
                                                  children: <Widget>[
                                                    Row(
                                                      crossAxisAlignment:
                                                          CrossAxisAlignment
                                                              .center,
                                                      children: <Widget>[
                                                        Container(
                                                          width: MediaQuery.of(
                                                                      context)
                                                                  .size
                                                                  .width *
                                                              0.5,
                                                          child: Text(
                                                            snapshot
                                                                .data![index]
                                                                .title!,
                                                            style: TextStyle(
                                                                fontSize: 14.0,
                                                                fontFamily:
                                                                    "Sofia",
                                                                fontWeight:
                                                                    FontWeight
                                                                        .bold,
                                                                color: Colors
                                                                    .black),
                                                            overflow:
                                                                TextOverflow
                                                                    .clip,
                                                            maxLines: 2,
                                                          ),
                                                        ),
                                                      ],
                                                    ),
                                                  ],
                                                ),
                                                const SizedBox(
                                                  height: 10,
                                                ),
                                                Row(
                                                  children: [
                                                    const Icon(
                                                      Icons.schedule,
                                                      size: 18,
                                                    ),
                                                    const SizedBox(
                                                      width: 5,
                                                    ),
                                                    Text(
                                                      '${DateTime.now().difference(DateTime.parse(snapshot.data![index].tanggal_publish!)).inHours} hours ago',
                                                    ),
                                                    const SizedBox(
                                                      width: 20,
                                                    ),
                                                    const Icon(
                                                      Icons.visibility,
                                                      size: 18,
                                                    ),
                                                    const SizedBox(
                                                      width: 5,
                                                    ),
                                                    Text(
                                                      '${snapshot.data![index].jumlahView!} views',
                                                      style: const TextStyle(
                                                          fontSize: 12),
                                                    )
                                                  ],
                                                )
                                              ],
                                            ),
                                          ),
                                        ],
                                      )
                                    ],
                                  ),
                                ),
                              ),
                            ),
                          ),
                        );
                      },
                    ),
                  );
                }
                return Center(child: CircularProgressIndicator());
              })
        ],
      ),
    );
  }
}

I am sorry, it is very long, i am still working on how to make it simple. i think the infinite scroll is working. but there are some issues here i dont know how to resolve.

1. the scroll is very weird, it looks like that the scroll working only on the listview.builder not the whole page. it made the the state triggered even before i reach the bottom of the list.

2. the data seems not added to the early list but it looks like its overwrite the list. so the list is changing but i lost the earlier list. i want it to still add the earlier list as well

i’ve been tring to look for a lot of solution but it seems like i dont fully understand whats wrong.

This is the article model that might responsible for this frustating problem:

class ArticleList {
  ArticleList({
    this.id,
    this.slug,
    this.image,
    this.title,
    this.category,
    this.jumlahView,
    this.tanggal_publish,
    this.author,
  });

  final int? id;
  final String? slug;
  final String? image;
  final String? title;
  final String? category;
  final int? jumlahView;
  final String? tanggal_publish;
  final String? author;

  factory ArticleList.fromJson(Map<String, dynamic> json) => ArticleList(
      id: json["id"] == null ? null : json["id"],
      slug: json["slug"] == null ? null : json["slug"],
      title: json["title"] == null ? null : json["title"],
      image: json["image"] == null ? null : json["image"],
      category: json["category"] == null ? null : json["category"],
      jumlahView: json["jumlahView"] == null ? null : json["jumlahView"],
      author: json["author"] == null ? null : json["author"],
      tanggal_publish:
          json["tanggal_publish"] == null ? null : json['tanggal_publish']);

  static List<ArticleList> fromJsonList(dynamic jsonList) {
    final articles = <ArticleList>[];
    if (jsonList == null) return articles;

    if (jsonList is List<dynamic>) {
      for (final json in jsonList) {
        articles.add(
          ArticleList.fromJson(json),
        );
      }
    }

    return articles;
  }
}

i dont know what is wrong, it seems like i am following the tutorial very carefully. please help me.

2

Answers


  1. Chosen as BEST ANSWER

    i have an update for my problem, because i cant really remove the null check operator and also put late in articleList variable and i dont understand why it couldnt read the initialization on my futureBuilder. so i change how i initialize articleList on the state class into this:

      List<ArticleList> articleList = <ArticleList>[];
    

    and it just work like magic. just added <ArticleList>[], the problem i've been trying to solve for two days is gone.

    i dont know whats the explanation to this, cause i am still new here. i apreciate your help though... thank you...


  2. There’s a simple issue here,

    See you have two lists os type List<ArticleList>, one is a class variable with name articleList and another is in the function getListArtikel() with name articleData. Now you are fetching list of article from the api with pagination and it will be saved in the list articleData so it will have list for that page only and after you’re returning like return articleList = articleData which means you’re replacing the new data with old one.

    You can do two things you can have only one list articleList you just fetch new data and add them in this list below:

    for (Map<String, dynamic> item in data['data']['data_article']) {
       articleList.add(ArticleList.fromJson(item));
    }
    

    Or you can have both the list just at the return statement you can add the new data which is now in articleData and at to the articleList like below:

    return articleList.addAll(articleData);
    

    so the articleList will have the all the data and articleData will have data for that page only.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search