Flutter-解决滑动冲突-1

315 阅读1分钟

关键逻辑在于使用 NotificationListener 监听到 OverscrollNotification ,将子组件不滑动的部分传递给父组件去滑动。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Scroll(),
        ),
      ),
    );
  }
}

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

  @override
  State<Scroll> createState() => _ScrollState();
}

class _ScrollState extends State<Scroll> {
  final _controller = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: NotificationListener(
        onNotification: (notification) {
          if (notification is OverscrollNotification) {
            final d = notification.dragDetails?.delta.dy ?? 0;
            final offset = _controller.offset - d;
            _controller.jumpTo(offset);
          }
          return true;
        },
        child: SingleChildScrollView(
          controller: _controller,
          child: Column(
            children: [
              Container(
                height: 200,
                color: Colors.redAccent,
              ),
              SizedBox(
                height: 300,
                child: ListView.separated(
                  shrinkWrap: true,
                  padding: const EdgeInsets.only(bottom: 50),
                  itemBuilder: (context, index) {
                    return SizedBox(
                      width: 360,
                      height: 50,
                      child: Text('index $index'),
                    );
                  },
                  separatorBuilder: (context, index) {
                    return const Divider();
                  },
                  itemCount: 20,
                ),
              ),
              Container(
                height: 200,
                color: Colors.yellowAccent,
              ),
              SizedBox(
                height: 300,
                child: ListView.separated(
                  shrinkWrap: true,
                  padding: const EdgeInsets.only(bottom: 50),
                  itemBuilder: (context, index) {
                    return SizedBox(
                      width: 360,
                      height: 50,
                      child: Text('index $index'),
                    );
                  },
                  separatorBuilder: (context, index) {
                    return const Divider();
                  },
                  itemCount: 20,
                ),
              ),
              Container(
                height: 200,
                color: Colors.blueAccent,
              ),
            ],
          ),
        ),
      ),
    );
  }
}