如何在Flutter中监听放置在ScrollView中的ListView的滚动事件?

问题描述 投票:-1回答:1

我想在包含ListView内包含ScrollView(或很多)的Flutter应用中进行e查看,并成功完成。但是我在滚动侦听器加载我绑定到ListView的下一页数据时遇到问题。我应该将scrollController放在哪里?在ListView还是ScrollView中?或我如何解决这个问题?

class HomeChildState extends State<HomeChild> {
  HomeChildState() {
    _categoryBloc = CategoryBloc();
    _spotBloc = SpotBloc();
  }
  CategoryBloc _categoryBloc;
  SpotBloc _spotBloc;
  int page = 1;
  int perPage = 4;
  final ScrollController _scrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _categoryBloc.getCategories(1, 5);
    _checkLocationPermission();
    _scrollController.addListener(_onScroll);
  }

  void _onScroll() {
    if (_scrollController.position.pixels ==
        _scrollController.position.maxScrollExtent) {
      setState(() {
        page += 1;
      });
      _spotBloc.getNearestSpot(page, perPage, _position.latitude, _position.longitude);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: const Size(null, 40),
        child: Container(
          padding: const EdgeInsets.only(left: 16, bottom: 12),
          color: orangeGradient4,
          child: const Text(
            'Beranda',
            style: TextStyle(
                color: white1, fontWeight: FontWeight.bold, fontSize: 16),
          ),
        ),
      ),
      body: CustomScrollView(
        slivers: <Widget>[
          SliverList(
            delegate: SliverChildListDelegate(
              <Widget>[
                Column(
                  children: <Widget>[
                    Container(
                      height: 150,
                      width: MediaQuery.of(context).size.width,
                      alignment: Alignment.center,
                      decoration: BoxDecoration(
                          image: DecorationImage(
                              image: const AssetImage('assets/home_thumbnail.png'),
                              repeat: ImageRepeat.noRepeat,
                              alignment: FractionalOffset.center,
                              fit: BoxFit.cover)),
                    ),
                    Padding(
                      padding:
                      const EdgeInsets.only(top: 12, left: 16, right: 16, bottom: 8),
                      child: Stack(
                        children: <Widget>[
                          Align(
                            alignment: Alignment.centerLeft,
                            child: Text(
                              'Kategori',
                              style: TextStyle(color: gray2, fontWeight: FontWeight.bold),
                            ),
                          ),
                          Align(
                            alignment: Alignment.centerRight,
                            child: GestureDetector(
                                child: Padding(
                                  padding: const EdgeInsets.only(top: 8),
                                  child: Text(
                                    'See All',
                                    style: TextStyle(
                                        color: orange2, fontWeight: FontWeight.bold),
                                  ),
                                ),
                                onTap: () {
                                  Navigator.pushNamed(context, '/categories');
                                }),
                          )
                        ],
                      ),
                    ),
                    StreamBuilder<List<Category>>(
                      stream: _categoryBloc.categoriesStream,
                      initialData: PageStorage.of(context).readState(context,
                          identifier: const ValueKey<String>('categories')),
                      builder:
                          (BuildContext context, AsyncSnapshot<List<Category>> snapshot) {
                        if (snapshot.hasData) {
                          PageStorage.of(context).writeState(context, snapshot.data,
                              identifier: const ValueKey<String>('categories'));
                          if (snapshot.data.isNotEmpty) {
                            return Container(
                              padding: const EdgeInsets.only(left: 16, right: 16, top: 8),
                              height: 100,
                              child: ListView.builder(
                                itemBuilder: (BuildContext context, int position) {
                                  return Column(
                                    crossAxisAlignment: CrossAxisAlignment.center,
                                    children: <Widget>[
                                      Container(
                                        decoration: BoxDecoration(
                                            border: Border.all(
                                                width: 1,
                                                color: gray1,
                                                style: BorderStyle.solid),
                                            borderRadius: const BorderRadius.all(
                                                Radius.circular(8)),
                                            color: gray3),
                                        child: Padding(
                                          padding: const EdgeInsets.all(8),
                                          child: Image.network(
                                            snapshot.data[position].image.thumb.url,
                                            height: 40,
                                            width: 40,
                                          ),
                                        ),
                                      ),
                                      Padding(
                                        padding: const EdgeInsets.only(top: 6),
                                        child: Text(
                                          snapshot.data[position].name,
                                          style: TextStyle(fontSize: 11, color: black1),
                                        ),
                                      ),
                                    ],
                                  );
                                },
                                scrollDirection: Axis.horizontal,
                                itemCount: snapshot.data.length,
                              ),
                            );
                          } else {
                            return Text(
                              'Empty Data',
                              style: TextStyle(color: black1, fontSize: 11),
                            );
                          }
                        } else if (snapshot.hasError) {
                          WidgetsBinding.instance.addPostFrameCallback((_) {
                            ToastTool(
                                context: context,
                                message: 'Failed to load categories')
                                .show();
                          });
                        }
                        return Progressbar.getProgressBar();
                      },
                    ),
                    Container(
                      alignment: Alignment.centerLeft,
                      padding: const EdgeInsets.only(left: 16, top: 8, right: 16),
                      child: Text(
                        'Terdekat',
                        style: TextStyle(color: gray2, fontWeight: FontWeight.bold),
                      ),
                    ),
                    StreamBuilder<List<Spot>>(
                      stream: _spotBloc.nearestSpotStream,
                      builder: (BuildContext context, AsyncSnapshot<List<Spot>> snapshot) {
                        print('data ${snapshot.error}');
                        if (snapshot.hasData) {
                          if (snapshot.data.isNotEmpty) {
                            return ListView.builder(
                              itemBuilder: (BuildContext context, int position) {
                                if (position >= snapshot.data.length) {
                                  return Padding(
                                    padding: const EdgeInsets.only(top: 12, bottom: 12),
                                    child: Progressbar.getProgressBar(),
                                  );
                                } else {
                                  return GestureDetector(
                                    child: Container(
                                      padding: const EdgeInsets.all(12),
                                      margin: EdgeInsets.only(
                                          left: 16,
                                          right: 16,
                                          top: position != 0 ? 4 : 16,
                                          bottom:
                                          position != snapshot.data.length.toDouble()
                                              ? 4
                                              : 16),
                                      decoration: BoxDecoration(
                                          border: Border.all(
                                            color: gray1,
                                            width: 0.5,
                                          ),
                                          borderRadius:
                                          const BorderRadius.all(Radius.circular(8.0))),
                                      child: Column(
                                        children: <Widget>[
                                          Row(
                                            children: <Widget>[
                                              snapshot.data[position].image.thumb.url !=
                                                  null
                                                  ? Image.network(
                                                snapshot
                                                    .data[position].image.thumb.url,
                                                width: 48,
                                                height: 48,
                                              )
                                                  : Image.asset(
                                                'assets/antrian_icon.png',
                                                height: 48,
                                                width: 48,
                                              ),
                                              Padding(
                                                padding: const EdgeInsets.only(left: 12),
                                                child: Column(
                                                  children: <Widget>[
                                                    Column(
                                                      crossAxisAlignment:
                                                      CrossAxisAlignment.start,
                                                      children: <Widget>[
                                                        Text(
                                                          snapshot.data[position].name !=
                                                              null
                                                              ? '${snapshot.data[position].name}'
                                                              : 'Tidak Ada Nama',
                                                          style: const TextStyle(
                                                              fontWeight: FontWeight.bold),
                                                        ),
                                                        Padding(
                                                          padding:
                                                          const EdgeInsets.only(top: 4),
                                                          child: Text(
                                                            snapshot.data[position]
                                                                .address !=
                                                                null
                                                                ? '${snapshot.data[position].address}'
                                                                : 'Tidak Ada Alamat',
                                                            style: const TextStyle(
                                                                fontSize: 10, color: gray1),
                                                          ),
                                                        )
                                                      ],
                                                    )
                                                  ],
                                                ),
                                              )
                                            ],
                                          ),
                                          Row(
                                            mainAxisAlignment: MainAxisAlignment.end,
                                            crossAxisAlignment: CrossAxisAlignment.center,
                                            children: <Widget>[
                                              Row(
                                                children: <Widget>[
                                                  Image.asset(
                                                    'assets/category_icon.png',
                                                    width: 24,
                                                    height: 24,
                                                  ),
                                                  Text(
                                                    snapshot.data[position].queueCategory
                                                        .name !=
                                                        null
                                                        ? '${snapshot.data[position].queueCategory.name}'
                                                        : 'Tidak Ada Katergori',
                                                    style: const TextStyle(fontSize: 10),
                                                  )
                                                ],
                                              ),
                                              Padding(
                                                padding: const EdgeInsets.only(left: 12),
                                                child: Row(
                                                  children: <Widget>[
                                                    Icon(
                                                      Icons.access_time,
                                                      size: 18,
                                                    ),
                                                    Text(
                                                      (snapshot.data[position].startTime !=
                                                          null &&
                                                          snapshot.data[position]
                                                              .endTime !=
                                                              null)
                                                          ? '${snapshot.data[position].startTime} - ${snapshot.data[position].endTime}'
                                                          : 'Tidak Ada Jam',
                                                      style: const TextStyle(fontSize: 10),
                                                    )
                                                  ],
                                                ),
                                              )
                                            ],
                                          )
                                        ],
                                      ),
                                    ),
                                    onTap: () {
                                      Navigator.of(context).pushNamed('/spot_page',
                                          arguments: snapshot.data[position]);
                                    },
                                  );
                                }
                              },
                              shrinkWrap: true,
                              physics: const NeverScrollableScrollPhysics(),
                              itemCount: snapshot.data.length < perPage
                                  ? snapshot.data.length
                                  : snapshot.data.length + 1,
                              controller: _scrollController,
                            );
                          } else {
                            return Center(
                              child: const Text(
                                'Belum ada data',
                                style: TextStyle(fontSize: 12),
                              ),
                            );
                          }
                        } else if (snapshot.error != null) {
                          return Center(
                            child: const Text(
                              'Gagal memuat data',
                              style: TextStyle(fontSize: 12),
                            ),
                          );
                        }
                        return Padding(
                          padding: const EdgeInsets.only(top: 12, bottom: 12),
                          child: Progressbar.getProgressBar(),
                        );
                      },
                    )
                  ],
                )
              ]
            ),
          )
        ],
      ),
    );
  }
}

listview flutter dart scrollview onscrolllistener
1个回答
0
投票

这里是最好的原型,您将对滚动有更好的了解。

之前,您应该参考此链接https://api.flutter.dev/flutter/widgets/ScrollController-class.htmlhttps://api.flutter.dev/flutter/widgets/ScrollNotification-class.html

        import 'package:flutter/material.dart';

        main() {
        runApp(MyApp());
        }

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

        class ScrollNotificationPage extends StatefulWidget {
        @override
        _ScrollNotificationPageState createState() => _ScrollNotificationPageState();
        }

        class _ScrollNotificationPageState extends State<ScrollNotificationPage> {
        String _progress = "0%";
        ScrollController _controller = ScrollController();
        @override
        void initState() {
            super.initState();
            _controller.addListener(() {
            debugPrint("_controller offset ${_controller.offset}  position ${_controller.position}");
            });
        }

        @override
        Widget build(BuildContext context) {
            return Scaffold(
            appBar: AppBar(
                title: Text("ScrollNotification"),
            ),
            body: Scrollbar(
                child: NotificationListener<ScrollNotification>(
                // ignore: missing_return
                onNotification: (ScrollNotification notification) {
                    double progress = notification.metrics.pixels / notification.metrics.maxScrollExtent;
                    setState(() {
                    _progress = "${(progress * 100).toInt()}%";
                    });
                    print("BottomEdge: ${notification.metrics.extentAfter == 0}");
                },
                child: Stack(
                    alignment: Alignment.center,
                    children: <Widget>[
                    ListView.builder(
                        controller: _controller,
                        itemCount: 100,
                        itemExtent: 50.0,
                        itemBuilder: (context, index) {
                            return ListTile(title: Text("$index"));
                        }),
                    CircleAvatar(
                        radius: 30.0,
                        child: Text(_progress),
                        backgroundColor: Colors.black54,
                    ),
                    Positioned(
                        bottom: 20,
                        child: RaisedButton(
                        onPressed: () {
                            _controller.animateTo(0, duration: Duration(milliseconds: 500), curve: Curves.ease);
                        },
                        child: Text("Scroll Top"),
                        ),
                    )
                    ],
                ),
                ),
            ),
            );
        }
        }
© www.soinside.com 2019 - 2024. All rights reserved.