ListView Flutter上方的浮动操作按钮

时间:2019-11-01 19:20:54

标签: flutter dart flutter-layout

我想在当前右下角的当前ListView上方有一个浮动操作按钮,但由于所有尝试都给我带来了错误,因此我不知道该怎么做。该按钮的功能是将项目添加到当前项目列表中。该页面的屏幕快照可以找到here

以下代码段都是从此处开始的首页)。从那里,它引用 HomePageBody ,然后引用 PlanetRow 。很抱歉会造成混乱。

void main() {
  runApp(MaterialApp(
    theme:
    ThemeData(accentColor: Colors.black87),
    home: HomePage(),
  ));
}

class HomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          AppBar(
            title: Text('Overview'),
            backgroundColor: Color.fromRGBO(53, 73, 94, 0.9),
            elevation: 0.0,
            leading: Container(),
            ),
          new HomePageBody()
        ],
      ),
    );
  }
}

HomePageBody:

class HomePageBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Expanded(
      child: new Container(
        color: Color.fromRGBO(53, 73, 94, 0.9),
        child: new CustomScrollView(
          scrollDirection: Axis.vertical,
          slivers: <Widget>[
            new SliverPadding(
              padding: const EdgeInsets.symmetric(vertical: 0.0),
              sliver: new SliverFixedExtentList(
                itemExtent: 152.0,
                delegate: new SliverChildBuilderDelegate(
                      (context, index) => new PlanetRow(planets[index]),
                  childCount: planets.length,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

PlanetRow:

class PlanetRow extends StatelessWidget {

  final Planet planet;

  PlanetRow(this.planet);

  Widget _planetValue({String value, String image}) {
    return new Row(
        children: <Widget>[
          new Image.asset(image, height: 12.0),
          new Container(width: 8.0),
          new Text(planet.gravity, style: Style.smallTextStyle),
        ]
    );
  }

  @override
  Widget build(BuildContext context) {

    final planetThumbnail = new Container(
      margin: new EdgeInsets.symmetric(
        vertical: 16.0,
      ),
      alignment: FractionalOffset.centerLeft,
      child: new Image(
        image: new AssetImage(planet.image),
        height: 92.0,
        width: 92.0,
      ),
    );

    final planetCardContent = new Container(
      margin: new EdgeInsets.fromLTRB(76.0, 16.0, 16.0, 16.0), // left, top, right, bottom
      constraints: new BoxConstraints.expand(),
      child: new Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          new Container(height: 4.0),
          new Text(planet.name,
            style: Style.titleTextStyle,
          ),
          new Container(height: 5.0),
          new Text(planet.location,
              style: Style.commonTextStyle

          ),
          new Container(
              margin: new EdgeInsets.symmetric(vertical: 8.0),
              height: 2.0,
              width: 18.0,
              color: new Color(0xff00c6ff)
          ),
          new Row(
            children: <Widget>[
              new Expanded(
                  child: _planetValue(
                      value: planet.distance,
                      image: 'assets/img/ic_distance.png')

              ),
              new Expanded(
                  child: _planetValue(
                      value: planet.gravity,
                      image: 'assets/img/ic_gravity.png')
              )
            ],
          )
        ],
      ),
    );

    final planetCard = new Container(
      child: planetCardContent,
      height: 124.0,
      margin: EdgeInsets.only(
        left: 46.0,
      ),
      decoration: new BoxDecoration(
        color: new Color(0xFF333366),
        shape: BoxShape.rectangle,
        borderRadius: new BorderRadius.circular(8.0),
        boxShadow: <BoxShadow> [
          new BoxShadow(
            color: Colors.black12,
            blurRadius: 10.0,
            offset: new Offset(0.0, 10.0),
          ),
        ],
      ),
    );

    return new Container(
      height: 120.0,
      margin: const EdgeInsets.symmetric(
        vertical: 12.0,
        horizontal: 24.0,
      ),
      child: new Stack(
        children: <Widget>[
          planetCard,
          planetThumbnail,
        ],
      ),
    );
  }
}

此代码段来自本教程:https://github.com/sergiandreplace/flutter_planets_tutorial。任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:3)

已更新

这似乎对我在Android设备上正常工作。 Here是它的图片。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    theme: ThemeData(accentColor: Colors.black87),
    home: HomePage(),
  ));
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Overview'),
        backgroundColor: Color.fromRGBO(53, 73, 94, 0.9),
        elevation: 0.0,
        leading: Container(),
      ),
      body: HomePageBody(),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          print("pressed it");
        },
      ),
    );
  }
}

class HomePageBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color.fromRGBO(53, 73, 94, 0.9),
      child: CustomScrollView(
        scrollDirection: Axis.vertical,
        slivers: <Widget>[
          SliverPadding(
            padding: const EdgeInsets.symmetric(vertical: 0.0),
            sliver: SliverFixedExtentList(
              itemExtent: 152.0,
              delegate: SliverChildBuilderDelegate(
                (context, index) => PlanetRow(planets[index]),
                childCount: planets.length,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class PlanetRow extends StatelessWidget {
  final Planet planet;

  PlanetRow(this.planet);

  Widget _planetValue({String value, String image}) {
    return Row(children: <Widget>[
      Image.asset(image, height: 12.0),
      Container(width: 8.0),
      Text(
        planet.gravity,
        style: Style.smallTextStyle,
      )
    ]);
  }

  @override
  Widget build(BuildContext context) {
    final planetThumbnail = Container(
      margin: EdgeInsets.symmetric(
        vertical: 16.0,
      ),
      alignment: FractionalOffset.centerLeft,
      child: Image(
        image: AssetImage(planet.image),
        height: 92.0,
        width: 92.0,
      ),
    );

    final planetCardContent = Container(
      margin: EdgeInsets.fromLTRB(76.0, 16.0, 16.0, 16.0), // left, top, right, bottom
      constraints: BoxConstraints.expand(),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Container(height: 4.0),
          Text(
            planet.name,
            style: Style.titleTextStyle,
          ),
          Container(height: 5.0),
          Text(
            planet.location,
            style: Style.commonTextStyle,
          ),
          Container(
              margin: EdgeInsets.symmetric(vertical: 8.0), height: 2.0, width: 18.0, color: new Color(0xff00c6ff)),
          Row(
            children: <Widget>[
              Expanded(child: _planetValue(value: planet.distance, image: 'assets/img/ic_distance.png')),
              Expanded(child: _planetValue(value: planet.gravity, image: 'assets/img/ic_gravity.png'))
            ],
          )
        ],
      ),
    );

    final planetCard = Container(
      child: planetCardContent,
      height: 124.0,
      margin: EdgeInsets.only(
        left: 46.0,
      ),
      decoration: BoxDecoration(
        color: Color(0xFF333366),
        shape: BoxShape.rectangle,
        borderRadius: BorderRadius.circular(8.0),
        boxShadow: <BoxShadow>[
          BoxShadow(
            color: Colors.black12,
            blurRadius: 10.0,
            offset: Offset(0.0, 10.0),
          ),
        ],
      ),
    );

    return Container(
      height: 120.0,
      margin: const EdgeInsets.symmetric(
        vertical: 12.0,
        horizontal: 24.0,
      ),
      child: Stack(
        children: <Widget>[
          planetCard,
          planetThumbnail,
        ],
      ),
    );
  }
}

class Planet {
  final String id;
  final String name;
  final String location;
  final String distance;
  final String gravity;
  final String description;
  final String image;
  final String picture;

  const Planet(
      {this.id, this.name, this.location, this.distance, this.gravity, this.description, this.image, this.picture});
}

List<Planet> planets = [
  const Planet(
      id: "1",
      name: "Mars",
      location: "Milkyway Galaxy",
      distance: "54.6m Km",
      gravity: "3.711 m/s ",
      description:
          "Mars is the fourth planet from the Sun and the second-smallest planet in the Solar System after Mercury. In English, Mars carries a name of the Roman god of war, and is often referred to as the 'Red Planet' because the reddish iron oxide prevalent on its surface gives it a reddish appearance that is distinctive among the astronomical bodies visible to the naked eye. Mars is a terrestrial planet with a thin atmosphere, having surface features reminiscent both of the impact craters of the Moon and the valleys, deserts, and polar ice caps of Earth.",
      image: "assets/img/mars.png",
      picture: "https://www.nasa.gov/sites/default/files/thumbnails/image/pia21723-16.jpg"),
  const Planet(
      id: "2",
      name: "Neptune",
      location: "Milkyway Galaxy",
      distance: "54.6m Km",
      gravity: "3.711 m/s ",
      description:
          "Neptune is the eighth and farthest known planet from the Sun in the Solar System. In the Solar System, it is the fourth-largest planet by diameter, the third-most-massive planet, and the densest giant planet. Neptune is 17 times the mass of Earth and is slightly more massive than its near-twin Uranus, which is 15 times the mass of Earth and slightly larger than Neptune. Neptune orbits the Sun once every 164.8 years at an average distance of 30.1 astronomical units (4.50×109 km). It is named after the Roman god of the sea and has the astronomical symbol ♆, a stylised version of the god Neptune's trident",
      image: "assets/img/neptune.png",
      picture:
          "https://www.nasa.gov/sites/default/files/styles/full_width_feature/public/images/110411main_Voyager2_280_yshires.jpg"),
  const Planet(
      id: "3",
      name: "Moon",
      location: "Milkyway Galaxy",
      distance: "54.6m Km",
      gravity: "3.711 m/s ",
      description:
          "The Moon is an astronomical body that orbits planet Earth, being Earth's only permanent natural satellite. It is the fifth-largest natural satellite in the Solar System, and the largest among planetary satellites relative to the size of the planet that it orbits (its primary). Following Jupiter's satellite Io, the Moon is second-densest satellite among those whose densities are known.",
      image: "assets/img/moon.png",
      picture: "https://farm5.staticflickr.com/4086/5052125139_43c31b7012.jpg"),
  const Planet(
      id: "4",
      name: "Earth",
      location: "Milkyway Galaxy",
      distance: "54.6m Km",
      gravity: "3.711 m/s ",
      description:
          "Earth is the third planet from the Sun and the only object in the Universe known to harbor life. According to radiometric dating and other sources of evidence, Earth formed over 4 billion years ago. Earth's gravity interacts with other objects in space, especially the Sun and the Moon, Earth's only natural satellite. Earth revolves around the Sun in 365.26 days, a period known as an Earth year. During this time, Earth rotates about its axis about 366.26 times.",
      image: "assets/img/earth.png",
      picture:
          "https://www.nasa.gov/sites/default/files/styles/full_width_feature/public/thumbnails/image/iss042e340851_1.jpg"),
  const Planet(
      id: "5",
      name: "Mercury",
      location: "Milkyway Galaxy",
      distance: "54.6m Km",
      gravity: "3.711 m/s ",
      description:
          "Mercury is the smallest and innermost planet in the Solar System. Its orbital period around the Sun of 88 days is the shortest of all the planets in the Solar System. It is named after the Roman deity Mercury, the messenger to the gods.",
      image: "assets/img/mercury.png",
      picture: "https://c1.staticflickr.com/9/8105/8497927473_2845ae671e_b.jpg"),
];

class Style {
  static final baseTextStyle = const TextStyle(fontFamily: 'Poppins');
  static final smallTextStyle = commonTextStyle.copyWith(
    fontSize: 9.0,
  );
  static final commonTextStyle =
      baseTextStyle.copyWith(color: const Color(0xffb6b2df), fontSize: 14.0, fontWeight: FontWeight.w400);
  static final titleTextStyle =
      baseTextStyle.copyWith(color: Colors.white, fontSize: 18.0, fontWeight: FontWeight.w600);
  static final headerTextStyle =
      baseTextStyle.copyWith(color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.w400);
}

原始

您可以将整个窗口小部件包装在一个支持浮动操作按钮的Scaffold中。

Here是一个实际行动的简单示例。对于您的情况,我想您希望将扩展内容扩展为Scaffold的body属性。像这样:

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.add),
        onPressed: () {
          // TODO add your logic here to add stuff
        },
      ),
      body: new Expanded(
        child: new Container(
          color: Color.fromRGBO(53, 73, 94, 0.9),
          child: new CustomScrollView(
            scrollDirection: Axis.vertical,
            slivers: <Widget>[
              new SliverPadding(
                padding: const EdgeInsets.symmetric(vertical: 0.0),
                sliver: new SliverFixedExtentList(
                  itemExtent: 152.0,
                  delegate: new SliverChildBuilderDelegate(
                    (context, index) => new PlanetRow(planets[index]),
                    childCount: planets.length,
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

让我知道是否可行。由于滚动视图具有自定义特性,因此很难确定是否还会遇到其他问题。

此外,请记住,如果要在单击浮动操作按钮时更新UI,则可能需要通过将主页转换为StatefulWidget来更新状态。

答案 1 :(得分:0)

您可以将Stack小部件与两个孩子一起使用,第一个孩子是您的列表,第二个孩子是您的浮动按钮,该按钮可让您将按钮放在列表上,然后只需要设置按钮的位置即可完成< / p>

答案 2 :(得分:0)

最方便的方法是使用@ {DerekFredrickson所说的floatingActionButton
另一种选择是使用@HaironChaviano所说的Stack。

以下是使用Stack的示例:

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  List<int> planets = [];
  int _number = 1;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          new Container(
            color: new Color(0xFF736AB7),
            child: new CustomScrollView(
              scrollDirection: Axis.vertical,
              slivers: <Widget>[
                new SliverPadding(
                  padding: const EdgeInsets.symmetric(vertical: 24.0),
                  sliver: new SliverFixedExtentList(
                    itemExtent: 152.0,
                    delegate: new SliverChildBuilderDelegate(
                      (context, index) => Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: new Container(
                          color: Colors.red,
                          child: Center(
                            child: Text('$index'),
                          ),
                        ),
                      ),
                      childCount: planets.length,
                    ),
                  ),
                ),
              ],
            ),
          ),
          Positioned(
            right: 20,
            bottom: 20,
            child: Align(
              alignment: Alignment.bottomRight,
              child: FloatingActionButton(
                child: Icon(Icons.add),
                onPressed: () {
                  setState(() {
                    planets.add(_number++);
                  });
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
}

答案 3 :(得分:0)

我更改了我在问题中发布的设置,如下所示:我删除了HomePageBody.dart文件,然后将内容移到HomePage文件中,如下所示:

import 'package:flutter/material.dart';
import 'package:crypti/home/HomePage.dart';
import 'package:crypti/model/planets.dart';

void main() {
  runApp(MaterialApp(
    home: HomePage(),
  ));
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Overview'),
        backgroundColor: Color.fromRGBO(53, 73, 94, 0.9),
        elevation: 0.0,
        leading: Container(),
      ),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.add),
          onPressed: () {
            // TODO add your logic here to add stuff
          },
      ),
      body: Column(
        children: <Widget>[
          new Expanded(
            child: new Container(
              color: Color.fromRGBO(53, 73, 94, 0.9),
              child: new CustomScrollView(
                scrollDirection: Axis.vertical,
                slivers: <Widget>[
                  new SliverPadding(
                    padding: const EdgeInsets.symmetric(vertical: 0.0),
                    sliver: new SliverFixedExtentList(
                      itemExtent: 152.0,
                      delegate: new SliverChildBuilderDelegate(
                            (context, index) => new PlanetRow(planets[index]),
                        childCount: planets.length,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

这成功了。感谢@lazos,尤其是@Derek Fredrickson!