Переполнение родительских виджетов - PullRequest
0 голосов
/ 25 апреля 2018

Я пытаюсь создать виджет, в котором есть кнопка, и всякий раз, когда эта кнопка нажимается, под ней открывается список, заполняющий все пространство под кнопкой.Я реализовал это с помощью простого Column, примерно так:

class _MyCoolWidgetState extends State<MyCoolWidget> {
  ...
  @override
  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new MyButton(...),
        isPressed ? new Expanded(
          child: new SizedBox(
            width: MediaQuery.of(context).size.width,
            child: new MyList()
          )
        ) : new Container()
      ]
    )
  }
}

Это прекрасно работает во многих случаях, но не во всех.

Проблема , с которой я столкнулся при создании этого виджета, заключается в том, что если MyCoolWidget находится внутри Row, например, с другими виджетами, скажем, другие MyCoolWidget s,список ограничен шириной, которую подразумевает Row.
Я попытался исправить это с помощью OverflowBox, но, к сожалению, безуспешно.

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

Следующее изображение представляет собой то, что япытаюсь добиться, в котором "BUTTON1" и "BUTTON2" или оба MyCoolWidget s в Row: enter image description here

Редактировать: Фрагментфактического кода

class _MyCoolWidgetState extends State<MyCoolWidget> {

  bool isTapped = false;

  @override
  Widget build(BuildContext context) {
    return new Column(
      children: <Widget>[
        new SizedBox(
          height: 20.0,
          width: 55.0,
          child: new Material(
            color: Colors.red,
            child: new InkWell(
              onTap: () => setState(() => isTapped = !isTapped),
              child: new Text("Surprise"),
            ),
          ),
        ),
        bottomList()
      ],
    );
  }

  Widget comboList() {
    if (isTapped) {
      return new Expanded(
        child: new OverflowBox(
          child: new Container(
            color: Colors.orange,
            width: MediaQuery.of(context).size.width,
            child: new ListView( // Random list
              children: <Widget>[
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
                new Text("ok"),
              ],
            )
          )
        ),
      );
    } else {
      return new Container();
    }
  }
}

Я использую его следующим образом:

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Row(
      children: <Widget>[
        new Expanded(child: new MyCoolWidget()),
        new Expanded(child: new MyCoolWidget()),
      ]
    )
  }
}

Вот скриншот того, что код на самом деле делает: enter image description here

1 Ответ

0 голосов
/ 25 апреля 2018

Из комментариев выяснилось, что ОП хочет следующее:

Создание всплывающего окна, которое охватывает все и идет от того места, где кнопка находится на экране, до нижней части экрана, а также заполняет ее горизонтально, независимо от того, где находится кнопка на экране. Также будет открываться / закрываться при нажатии кнопки.

Есть несколько вариантов того, как это можно сделать; самым простым будет использование Dialog & showDialog, за исключением того, что у него есть некоторые проблемы вокруг SafeArea, которые затрудняют это. Кроме того, OP запрашивает, чтобы кнопка переключалась, а не нажимала в любом месте, а не на диалог (что и делает диалоговое окно - либо это, либо блокировка касается диалога).

Это рабочий пример того, как сделать что-то подобное. Полный отказ от ответственности - я не утверждаю, что это хорошая вещь, или даже хороший способ сделать это ... но это способ сделать это.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

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

// We're extending PopupRoute as it (and ModalRoute) do a lot of things
// that we don't want to have to re-create. Unfortunately ModalRoute also
// adds a modal barrier which we don't want, so we have to do a slightly messy
// workaround for that. And this has a few properties we don't really care about.
class NoBarrierPopupRoute<T> extends PopupRoute<T> {
  NoBarrierPopupRoute({@required this.builder});

  final WidgetBuilder builder;

  @override
  Color barrierColor;

  @override
  bool barrierDismissible = true;

  @override
  String barrierLabel;

  @override
  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
    return new Builder(builder: builder);
  }

  @override
  Duration get transitionDuration => const Duration(milliseconds: 100);

  @override
  Iterable<OverlayEntry> createOverlayEntries() sync* {
    // modalRoute creates two overlays - the modal barrier, then the
    // actual one we want that displays our page. We simply don't
    // return the modal barrier.
    // Note that if you want a tap anywhere that isn't the dialog (list)
    // to close it, then you could delete this override.
    yield super.createOverlayEntries().last;
  }

  @override
  Widget buildTransitions(
      BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
    // if you don't want a transition, remove this and set transitionDuration to 0.
    return new FadeTransition(opacity: new CurvedAnimation(parent: animation, curve: Curves.easeOut), child: child);
  }
}

class PopupButton extends StatefulWidget {
  final String text;
  final WidgetBuilder popupBuilder;

  PopupButton({@required this.text, @required this.popupBuilder});

  @override
  State<StatefulWidget> createState() => PopupButtonState();
}

class PopupButtonState extends State<PopupButton> {
  bool _active = false;

  @override
  Widget build(BuildContext context) {
    return new FlatButton(
      onPressed: () {
        if (_active) {
          Navigator.of(context).pop();
        } else {
          RenderBox renderbox = context.findRenderObject();
          Offset globalCoord = renderbox.localToGlobal(new Offset(0.0, context.size.height));
          setState(() => _active = true);
          Navigator
              .of(context, rootNavigator: true)
              .push(
                new NoBarrierPopupRoute(
                  builder: (context) => new Padding(
                        padding: new EdgeInsets.only(top: globalCoord.dy),
                        child: new Builder(builder: widget.popupBuilder),
                      ),
                ),
              )
              .then((val) => setState(() => _active = false));
        }
      },
      child: new Text(widget.text),
    );
  }
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new SafeArea(
        child: new Container(
          color: Colors.white,
          child: new Column(children: [
            new PopupButton(
              text: "one",
              popupBuilder: (context) => new Container(
                    color: Colors.blue,
                  ),
            ),
            new PopupButton(
              text: "two",
              popupBuilder: (context) => new Container(color: Colors.red),
            )
          ]),
        ),
      ),
    );
  }
}

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

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

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