Flutter: ListView: прокрутить родительский ListView, когда дочерний ListView достигнет дна - ClampingScrollPhysics не работает в размерном контейнере - PullRequest
0 голосов
/ 07 марта 2020

Я использую Flutter версии 1.12.13 + исправление.

Я ищу решение, чтобы иметь возможность прокручивать внутри ListView и когда достигну дна, автоматически дать отвод прокрутки к родительскому ListView .

enter image description here

Первое решение, которое должно быть достигнуто, - это использовать «физика: ClampingScrollPhysics ()» с «shrinkWrap: true». Поэтому я применяю это решение ко всем подпунктам Listview, кроме первого (красного), потому что мне нужно обернуть его внутри контейнера Container ().

Проблема возникает из-за первого ... ClampingScrollPhysics () не работал с размером Container ()!

Итак, когда я прокручиваю красный ListView и достигаю его дна, прокрутка останавливается ... Мне нужно положить палец за пределы этого ListView, чтобы иметь возможность снова прокручивать.

@override
  Widget build(BuildContext context) {
    super.build(context);

    print("build MySongs");

    return ListView(
      children: <Widget>[
        Container(
          height: 170,
          margin: EdgeInsets.all(16),
          child: ListView(
            children: <Widget>[
              Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.red, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
            ],
          ),
        ),
        Container(
          margin: EdgeInsets.all(16),
          child: ListView(
            physics: ClampingScrollPhysics(),
            shrinkWrap: true,
            children: <Widget>[
              Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.orange, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
            ],
          ),
        ),
        Container(
          margin: EdgeInsets.all(16),
          child: ListView(
            shrinkWrap: true,
            physics: ClampingScrollPhysics(),
            children: <Widget>[
              Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.blue, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
            ],
          ),
        ),
        Container(
          margin: EdgeInsets.all(16),
          child: ListView(
            physics: ClampingScrollPhysics(),
            shrinkWrap: true,
            children: <Widget>[
              Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
              Container(color: Colors.green, width: 100, height: 100, padding: EdgeInsets.all(8), margin: EdgeInsets.all(8)),
            ],
          ),
        ),
      ],
    );
  }

Возможно, вам понадобится опубликовать этот вопрос в выпуске Flutter github: /

Ответы [ 3 ]

2 голосов
/ 10 марта 2020

Спасибо за решение Hamed Hamedi :)! Я думаю, что я сделал лучшее решение на основе NotificationListener! (Я обнаружил эту функциональность благодаря ему).

@override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(8),
      color: Colors.yellow,
      child: ListView.builder(
        controller: controller,
        itemBuilder: (c, i) =>
        i == 10
          ? Container(
          height: 150,
          color: Colors.red,
          child: NotificationListener<OverscrollNotification>(
            onNotification: (OverscrollNotification value) {
              if (value.overscroll < 0 && controller.offset + value.overscroll <= 0) {
                if (controller.offset != 0) controller.jumpTo(0);
                return true;
              }
              if (controller.offset + value.overscroll >= controller.position.maxScrollExtent) {
                if (controller.offset != controller.position.maxScrollExtent) controller.jumpTo(controller.position.maxScrollExtent);
                return true;
              }
              controller.jumpTo(controller.offset + value.overscroll);
              return true;
            },
            child: ListView.builder(
              itemBuilder: (c, ii) => Text('-->' + ii.toString()),
              itemCount: 20,
            ),
          ),
        )
          : Text(i.toString()),
        itemCount: 45,
      ),
    );
  }

Решение, включенное в StatelessWidget:

import 'package:flutter/material.dart';

class ScrollParent extends StatelessWidget {
  final ScrollController controller;
  final Widget child;

  ScrollParent({this.controller, this.child});

  @override
  Widget build(BuildContext context) {
    return NotificationListener<OverscrollNotification>(
      onNotification: (OverscrollNotification value) {
        if (value.overscroll < 0 && controller.offset + value.overscroll <= 0) {
          if (controller.offset != 0) controller.jumpTo(0);
          return true;
        }
        if (controller.offset + value.overscroll >= controller.position.maxScrollExtent) {
          if (controller.offset != controller.position.maxScrollExtent) controller.jumpTo(controller.position.maxScrollExtent);
          return true;
        }
        controller.jumpTo(controller.offset + value.overscroll);
        return true;
      },
      child: child,
    );
  }
}
1 голос
/ 10 марта 2020

Сложно использовать NotificationListener. Поместите прослушиватель уведомлений о превышении прокрутки над своим дочерним виджетом прокрутки, а затем игнорируйте указатель в случае превышения прокрутки. Чтобы дочерний виджет снова мог прокручиваться в противоположном направлении, вы должны установить игнорирование false через короткое время. Пример подробного кода:

class _MyHomePageState extends State<MyHomePage> {

  var _scrollParent = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.yellow,
        child: ListView.builder(
          itemBuilder: (c, i) => i == 10
              ? Container(
                  height: 150,
                  color: Colors.red,
                  child: IgnorePointer(
                    ignoring: _scrollParent,
                    child: NotificationListener<OverscrollNotification>(
                      onNotification: (_) {

                        setState(() {
                          _scrollParent = true;
                        });

                        Timer(Duration(seconds: 1), () {
                          setState(() {
                            _scrollParent = false;
                          });
                        });

                        return false;
                      },
                      child: ListView.builder(
                        itemBuilder: (c, ii) => Text('-->' + ii.toString()),
                        itemCount: 100,
                      ),
                    ),
                  ),
                )
              : Text(i.toString()),
          itemCount: 100,
        ),
      ),
    );
  }
}

Было бы некоторое fl aws, например, требование двойной прокрутки пользователем для активации события родительской прокрутки (первое будет игнорировать указатель) или использование таймера для отключения игнорирования ведущих плохое поведение при быстрой прокрутке. Но простота реализации по отношению к другим решениям была бы огромна.

0 голосов
/ 08 марта 2020

Обычно, когда я сталкиваюсь с такой проблемой, я использую SingleChildScrollView с column в качестве дочернего элемента, а затем все, что я хочу в качестве дочернего элемента этого столбца. Вот некоторый демонстрационный код.

SingleChildScrollView
(
  child: Column
  (
    children:
    [
     /* Your content goes here. */
    ]
  )
)

Дайте мне знать, подходит ли это для вашего варианта использования

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...