繁体   English   中英

如何在 Flutter 中自动滚动 Listview.seperated 中的所有 ListTiles?

[英]How to automatically scroll through all the ListTiles in the Listview.seperated in Flutter?

使用 flutter 中的计时器自动滚动(无需任何用户交互)通过 Listview 中的所有 ListTiles。 下面的方法只制作一个 ListTile 动画,但我想将所有 ListTiles 从上到下一个一个地动画,然后从下到上一个一个地动画。

下面是列表视图:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: FutureBuilder(
          future: fetchNews(),
          builder: (context, snap) {
            if (snap.hasData) {
              news = snap.data;
              return ListView.separated(
                //controller: _controller,
                scrollDirection: scrollDirection,
                controller: controller,
                itemBuilder: (context, i) {
                  final NewsModel _item = news[i];
                  return AutoScrollTag(
                    key: ValueKey(i),
                    controller: controller,
                    index: i,
                    child: ListTile(
                      title: Text('${_item.title}'),
                      subtitle: Text(
                        '${_item.description}',
                        // maxLines: 1,
                        //overflow: TextOverflow.ellipsis,
                      ),
                    ),
                  );
                },
                separatorBuilder: (context, i) => Divider(),
                itemCount: news.length,
              );
            } else if (snap.hasError) {
              return Center(
                child: Text(snap.error.toString()),
              );
            } else {
              return Center(
                child: CircularProgressIndicator(),
              );
            }
          },
        ),
      ),
    );
  }
}

这是我尝试过的自动滚动:

@override
  void initState() {
    super.initState();
    timer = Timer.periodic(Duration(seconds: 2), (Timer t) async {
        await controller.scrollToIndex(1,
            preferPosition: AutoScrollPosition.begin);
    });

这是一个解决方案,假设ListView中的所有项目都具有相同的itemExtent

在此处输入图像描述

在此解决方案中,我将当前项目突出显示为选中状态。 您还可能希望在到达列表底部后立即停止自动滚动。

完整的源代码

import 'dart:async';

import 'package:faker/faker.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part '66455867.auto_scroll.freezed.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class HomePage extends StatelessWidget {
  Future<List<News>> _fetchNews() async => dummyData;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('News')),
      body: FutureBuilder(
        future: _fetchNews(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return NewsList(newsList: snapshot.data);
          } else if (snapshot.hasError) {
            return Center(child: Text(snapshot.error.toString()));
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

class NewsList extends StatefulWidget {
  final List<News> newsList;

  const NewsList({
    Key key,
    this.newsList,
  }) : super(key: key);

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

class _NewsListState extends State<NewsList> {
  ScrollController _scrollController = ScrollController();
  Timer _timer;

  double _itemExtent = 100.0;
  Duration _scrollDuration = Duration(milliseconds: 300);
  Curve _scrollCurve = Curves.easeInOut;

  int _autoScrollIncrement = 1;
  int _currentScrollIndex = 0;

  @override
  void initState() {
    super.initState();
    _timer = Timer.periodic(Duration(seconds: 2), (_) async {
      _autoScrollIncrement = _currentScrollIndex == 0
          ? 1
          : _currentScrollIndex == widget.newsList.length - 1
              ? -1
              : _autoScrollIncrement;
      _currentScrollIndex += _autoScrollIncrement;
      _animateToIndex(_currentScrollIndex);
      setState(() {});
    });
  }

  void _animateToIndex(int index) {
    _scrollController.animateTo(
      index * _itemExtent,
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
      controller: _scrollController,
      itemExtent: _itemExtent,
      children: widget.newsList
          .map((news) => ListTile(
                title: Text(news.title),
                subtitle: Text(
                  news.description,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                ),
                selected: widget.newsList[_currentScrollIndex].id == news.id,
                selectedTileColor: Colors.amber.shade100,
              ))
          .toList(),
    );
  }
}

@freezed
abstract class News with _$News {
  const factory News({int id, String title, String description}) = _News;
}

final faker = Faker();
final dummyData = List.generate(
  10,
  (index) => News(
    id: faker.randomGenerator.integer(99999999),
    title: faker.sport.name(),
    description: faker.lorem.sentence(),
  ),
);

解决方案中使用的软件包:


更新:只滚动一次

要停止列表视图底部的自动滚动,您只需要修改initState方法:

int _currentScrollIndex;
News _selectedNews;

@override
void initState() {
  super.initState();
  _currentScrollIndex = -1;
  _timer = Timer.periodic(Duration(seconds: 2), (_) async {
    setState(() {
      if (_currentScrollIndex == widget.newsList.length - 1) {
        _timer.cancel();
        _selectedNews = null;
      } else {
        _selectedNews = widget.newsList[++_currentScrollIndex];
        _animateToIndex(_currentScrollIndex);
      }
    });
  });
}

我们不需要定义为_autoScrollIncrement的滚动方向。 但是,当我们到达列表底部时,我会引入一个新的_selectedNews以轻松取消选择最后一个新闻项目。 我们的ListTileselected标志将变为:

@override
Widget build(BuildContext context) {
  return ListView(
    [...]
    children: widget.newsList
      .map((news) => ListTile(
        [...]
        selected: _selectedNews?.id == news.id,
        [...]
      ))
      .toList(),
  );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM