flutter 仿QQ滑动删除

560 阅读1分钟

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

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

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ScrollController _preScrollController;
  bool _endPreScroll = false;
  List<String> _list = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 100; i++) _list.add("$i");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: NotificationListener<ScrollNotification>(
            onNotification: (scrollState) {
              if (_preScrollController != null && _preScrollController.offset == 160) {
                _preScrollController.animateTo(0.0,
                    duration: Duration(milliseconds: 100), curve: Curves.easeInOut);
                _preScrollController = null;
              }
              return null;
            },
            child: ListView.builder(
                itemCount: _list.length,
                itemBuilder: (context, index) {
                  return _buildContainer(index);
                })));
  }

  Widget _buildContainer(int index) {
    ScrollController scrollController = ScrollController();
    final item = _list[index];

    return NotificationListener<ScrollNotification>(
      onNotification: (scrollState) {
        if (scrollState is ScrollEndNotification) {
          _endScroll(scrollController);
        }
        return true;
      },
      child: Container(
        height: 60,
        margin: EdgeInsets.only(bottom: 1),
        child: ListView(
          shrinkWrap: true,
          scrollDirection: Axis.horizontal,
          controller: scrollController,
          children: <Widget>[
            Container(
              width: 360,
              height: 20,
              color: Colors.red,
              child: Text(item),
            ),
            GestureDetector(
              onTap: () {
                _preScrollController.animateTo(0.0,
                    duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
                scrollController = null;
                _preScrollController = null;
                setState(() {
                  _list.removeAt(index);
                });
              },
              child: Container(
                width: 160,
                height: 20,
                color: Colors.blue,
                child: Text("删除"),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _endScroll(ScrollController scrollController) {
    if (_curControllerInMiddle(scrollController)) {
      _endPreScroll = false;
      _autoOpenCurController(scrollController);
    }

    if (_preControllerNeedScroll()) {
      Future.delayed(const Duration(milliseconds: 10), () {}).then((s) {
        _preScrollController
            .animateTo(0.0, duration: Duration(milliseconds: 100), curve: Curves.easeInOut)
            .then((s) {
          _endPreScroll = true;
        });
      });
    }

    if (scrollController.offset == 160) {
      _closePreController();
      _preScrollController = scrollController;
    }
  }

  bool _preControllerNeedScroll() => _preScrollController != null && !_endPreScroll;

  bool _curControllerInMiddle(ScrollController scrollController) => scrollController.offset != 0 && scrollController.offset != 160;

  void _autoOpenCurController(ScrollController scrollController) {
    Future.delayed(const Duration(milliseconds: 10), () {}).then((s) {
      scrollController.animateTo(160,
          duration: Duration(milliseconds: 200), curve: Curves.easeInOut);
    });
  }

  void _closePreController() {
    if (_preScrollController != null && _preScrollController.offset != 0) {
      _preScrollController.animateTo(0.0,
          duration: Duration(milliseconds: 100), curve: Curves.easeInOut);
    }
  }
}