Flutter带有标题的网格视图

16
如何在FLUTTER中创建带可滚动工具栏的网格视图。我已经找到了带有标题的列表视图ListViewWithHeader。但是我需要像下面提到的图片中一样带有标题的GridView。我使用了SilverGrid来构建这个布局,但是它有点卡顿。所以我需要另一个选项。

enter image description here

Container setDataToContainer() {
  return Container(
    color: Colors.white,
    margin: EdgeInsets.only(left: 4.0, right: 4, bottom: 4, top: 4),
    child: CustomScrollView(
      slivers: <Widget>[
        SliverList(
          delegate: SliverChildListDelegate(
            [
              HeaderWidget("Header 1"),
            ],
          ),
        ),
        SliverGrid(
          gridDelegate:
              SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
          delegate: SliverChildListDelegate(
            [
              BodyWidget("title", "key_x", "pnl.svg"),
              BodyWidget("title2", "key_x", "cls.svg"),
              BodyWidget(
                  "title3", "key_x", "irr.svg"),
              BodyWidget(
                  "title4", "key_x", "icp.svg"),
            ],
          ),
        ),
        SliverList(
          delegate: SliverChildListDelegate(
            [
              HeaderWidget("Header 2"),
            ],
          ),
        ),
        SliverGrid(
          gridDelegate:
              SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
          delegate: SliverChildListDelegate(
            [
              BodyWidget("title5", "key_x", "ict.svg"),
              BodyWidget("title6", "key_x", "icc.svg"),
            ],
          ),
        ),
        SliverList(
          delegate: SliverChildListDelegate(
            [
              HeaderWidget("Others"),
            ],
          ),
        ),
        SliverGrid(
          gridDelegate:
              SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
          delegate: SliverChildListDelegate(
            [
              BodyWidget("title7", "key_x", "icd.svg"),
              BodyWidget("title8", "6", "ici.svg"),
            ],
          ),
        ),
      ],
    ),
  );
}

class HeaderWidget extends StatelessWidget {
  final String text;

  HeaderWidget(this.text);

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(left: 10.0, right: 10, bottom: 2, top: 20),
      child: Text(
        text.toUpperCase(),
        style: TextStyle(
            color: hexToColor(themeColor1),
            fontSize: 16,
            fontWeight: FontWeight.bold),
      ),
      color: Colors.white,
    );
  }
}

class BodyWidget extends StatelessWidget {
  final String imagePath;
  final String title;
  final String navigationKey;

  BodyWidget(this.title, this.navigationKey, this.imagePath);

  @override
  Widget build(BuildContext context) {
    return Container(
        alignment: Alignment.center,
        child: Card(
          color: hexToColor(themeColor1),
          elevation: 5,
          child: InkWell(
            onTap: () {
              navigateToView(context, navigationKey);
            },
            child: Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.topCenter,
                  child: Container(
                    margin: EdgeInsets.only(top: 40),
                    child: SvgPicture.asset(
                      "assets/images/$imagePath",
                      color: Colors.white,
                      width: 35,
                      height: 35,
                    ),
                  ),
                ),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    verticalDirection: VerticalDirection.up,
                    children: <Widget>[
                      Container(
                        padding: EdgeInsets.all(10),
                        color: Colors.black.withOpacity(.2),
                        child: Text(
                          title,
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 14,
                              fontWeight: FontWeight.normal),
                        ),
                      )
                    ],
                  ),
                ),
              ],
            ),
          ),
        ));
  }

  void navigateToView(BuildContext context, String navigationKey) {

    Navigator.push(
      context,
      PageRouteBuilder(
        pageBuilder: (context, animation1, animation2) {
          return NewSections();
        },
        transitionsBuilder: (context, animation1, animation2, child) {
          return FadeTransition(
            opacity: animation1,
            child: child,
          );
        },
        transitionDuration: Duration(milliseconds: 600),
      ),
    );
  }
}

你尝试过使用sticky_headers插件来实现这个功能吗? - user4571931
1
不,我没有。我想用另一种选项替换SliverGrid,因为在我的情况下它有点卡顿。 - jazzbpn
嗨@jazzbpn,我遇到了同样的问题。你找到解决方案了吗? - Yousif
1
你可以使用 SliverToBoxAdapter 来编写标题文本,而不是使用只有一个子元素的 SliverList - Hossein Hadi
2个回答

13

你可以尝试使用这段代码替换 SliverGrid

sticky_headers: ^0.1.7

将上述插件添加到 pubspec.yaml 中

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

class GridHeader extends StatefulWidget {
  @override
  _GridHeaderState createState() => _GridHeaderState();
}

class _GridHeaderState extends State<GridHeader> {

  List<String> listHeader = ['HEADER1','HEADER2','HEADER3','HEADER4','HEADER5','HEADER6','HEADER7','HEADER8','HEADER9','HEADER10',];
  List<String> listTitle = ['title1','title2','title3','title4',];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Grid Header Demo"),
      ),
      body: gridHeader(),
    );
  }


  Widget gridHeader(){
    return new ListView.builder(itemCount: listHeader.length,itemBuilder: (context, index) {
      return new StickyHeader(
        header: new Container(
          height: 38.0,
          color: Colors.white,
          padding: new EdgeInsets.symmetric(horizontal: 12.0),
          alignment: Alignment.centerLeft,
          child: new Text(listHeader[index],
            style: const TextStyle(color: Colors.purple, fontSize: 20,fontWeight: FontWeight.bold),
          ),
        ),
        content: Container(
          child: GridView.builder(
            shrinkWrap: true,
            physics: NeverScrollableScrollPhysics(),
            itemCount: listTitle.length,
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2,childAspectRatio: 1,),
            itemBuilder: (contxt, indx){
              return Card(
                margin: EdgeInsets.all(4.0),
                color: Colors.purpleAccent,
                child: Padding(
                  padding: const EdgeInsets.only(left: 12.0, top: 6.0, bottom: 2.0),
                  child: Center(child: Text(listTitle[indx], style: TextStyle(fontSize: 14, color: Colors.black54),)),
                ),
              );
            },
          ),
        ),
      );
    },
      shrinkWrap: true,
    );
  }
}

根据您的需求更改listHeaderlistTitle数据


每次滚动时,图片都会重新加载。我该如何处理这个问题? - jazzbpn
本地的,来自资产文件夹。 - jazzbpn
如果你正在使用CachedNetworkImage和precacheImage,那么尝试使用Image.asset("")来加载本地图片。 - user4571931
是的,我尝试过了,但它仍然很卡顿。每次滚动时,项会一遍又一遍地重新加载。 - jazzbpn

0

在这里,我创建了flat_list小部件,其规格与React Native的FlatList类似。希望以下内容有效。

FlatList(
+  numColumns: 2,
+  listHeaderWidget: const Header(),
  data: items.value,
  buildItem: (item, index) {
    var person = items.value[index];

    return ListItemView(person: person);
  },
),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接