如何在AppBar中使用定位小部件

时间:2018-07-09 03:46:25

标签: dart flutter flutter-positioned

从我阅读的内容来看,这应该是可能的,但我无法完全实现它。我在Stack的{​​{1}}里面有一个bottom,在appBar里面有一个Positioned列表。一切似乎都按预期放置,但是Stack正在裁剪列表,因此如果appBarappBar的内容在列表的顶部不显示。

我是Flutter的新手,但是在HTML的世界中,我将拥有一个绝对定位的列表,并且appBar将使用高于主体的z-index进行固定,以实现分层效果。

我尝试了很多变体,但似乎appBar想要种植它的孩子。任何帮助将不胜感激。

这是我要模仿的照片: expected overlay behavior

这是一段代码:

body

更新#1

return new Scaffold(
  appBar: new AppBar(
    title: new Row(
      children: <Widget>[
        new Padding(
          padding: new EdgeInsets.only(
            right: 10.0,
          ),
          child: new Icon(Icons.shopping_basket),
        ),
        new Text(appTitle)
      ],
    ),
    bottom: new PreferredSize(
      preferredSize: const Size.fromHeight(30.0),
      child: new Padding(
        padding: new EdgeInsets.only(
          bottom: 10.0,
          left: 10.0,
          right: 10.0,
        ),
        child: new AutoCompleteInput(
          key: new ObjectKey('$completionList'),
          completionList: completionList,
          hintText: 'Add Item',
          onSubmit: _addListItem,
        ),
      ),
    ),
  ),

4 个答案:

答案 0 :(得分:1)

我从未测试过,但是AppBar具有flexibleSpace属性,该属性将小部件作为参数。该小部件放置在AppBar顶部(标题所在的位置)和AppBar底部之间的空间中。如果将窗口小部件放置在此空间中而不是AppBar的底部(应仅用于TabBars之类的窗口小部件)的底部,则您的应用程序可能会正常运行。

另一种可能的解决方案是将列表元素放在DropdownButton中,而不是放在堆栈中。

您可以在AppBar here上找到更多信息。

编辑:您还可以考虑在使用搜索时使用脚手架主体显示建议。

此外,您可能会发现PopupMenuButton的源代码对于解决您的问题很有用(因为它的工作方式与建议框相似)。这是一个片段:

  void showButtonMenu() {
    final RenderBox button = context.findRenderObject();
    final RenderBox overlay = Overlay.of(context).context.findRenderObject();
    final RelativeRect position = new RelativeRect.fromRect(
      new Rect.fromPoints(
        button.localToGlobal(Offset.zero, ancestor: overlay),
        button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
      ),
      Offset.zero & overlay.size,
    );
    showMenu<T>(
      context: context,
      elevation: widget.elevation,
      items: widget.itemBuilder(context),
      initialValue: widget.initialValue,
      position: position,
    )
    .then<void>((T newValue) {
      if (!mounted)
        return null;
      if (newValue == null) {
        if (widget.onCanceled != null)
          widget.onCanceled();
        return null;
      }
      if (widget.onSelected != null)
        widget.onSelected(newValue);
    });
  }

答案 1 :(得分:1)

您将无法使用Positioned小部件将某些内容绝对定位在剪辑之外。 (AppBar要求此剪辑遵循材料规范,因此它可能不会更改)。

如果您需要将某些东西放置在其所构建的窗口小部件的边界之外,那么您需要一个Overlay。叠加层本身是由MaterialApp中的导航器创建的,因此您可以将新元素放入其中。使用Overlay的其他一些小部件是工具提示和弹出菜单,因此您可以根据需要查看它们的实现以获取更多启发。

final OverlayEntry entry = new OverlayEntry(builder: (BuildContext context) => /* ... */)
Overlay.of(context, debugRequiredFor: widget).insert(_entry);

答案 2 :(得分:0)

我认为AppBar的空间有限。并在AppBar中放置列表是一个坏习惯。

答案 3 :(得分:0)

创建了一个示例文件,演示了我的想法(至少与此问题相关)。希望它可以使其他人免于不必要的麻烦。

enter image description here

  using System;
  namespace ConsoleApp2
  {
  class Program
  {
    static void Main(string[] args)
    {
        IStuff IStuff = new DerivedClass1("data1 here");
        IStuff.DoStuff(); // prints "1: data here"

        IStuff = new DerivedClass2("data2 here");
        IStuff.DoStuff(); // prints "1: data here"

        Console.ReadKey();
    }

    public class BaseClass
    {
        public BaseClass(string data)
        {
            Data = data;
        }

        public string Data { get; set; }
    }

    // Interface for derived Classes:

    public interface IStuff
    {
        void DoStuff();
    }

    // Derived Classes: 
    // (Don't have own Properties besides the ones they get from BaseClass and 
    // no other Methods than they have to implement from IStuff)

    public class DerivedClass1 : BaseClass, IStuff
    {
        public DerivedClass1(string data) : base(data)
        {

        }
        public void DoStuff()
        {
            Console.WriteLine($"1: {Data}");
        }
    }

    public class DerivedClass2 : BaseClass, IStuff
    {
        public DerivedClass2(string data) : base(data)
        {

        }
        public void DoStuff()
        {
            Console.WriteLine($"2: {Data}");
        }
    }


    //UnknownType GetDerivedClass(BaseClass baseClass, int value)
    //{
    //    switch (value)
    //    {
    //        case 1:
    //            return baseClass as DerivedClass1;
    //        case 2:
    //            return baseClass as DerivedClass2;
    //        default:
    //            return null;
    //    }
    //}

    //var value = 1;

}
}