单击时重定向到其他页面的按钮的 Flutter 网格

Flutter grid of buttons that redirects to other page when clicked

大家好,我是 Flutter 新手。我有一个可点击按钮的网格。现在它只有两个,但它可以增长到很多。我如何重构它以使其更具动态性并处理许多未来的按钮?就像一个按钮的网格列表,您可以通过单击这些按钮来导航到不同的页面。

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Page'),
      ),
      body: Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(30.0),
        child: GridView.extent(
          maxCrossAxisExtent: 150,
          crossAxisSpacing: 15.0,
          mainAxisSpacing: 15.0,
          children: <Widget>[
            FlatButton(
              onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (_) => ProductScreen(),
                  ),
                );
              },
              padding: EdgeInsets.only(top: 33),
              child: Column(
                children: [
                  Icon(
                    Icons.shopping_cart_outlined,
                    color: Colors.white,
                  ),
                  Text(
                    "Products",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ],
              ),
            ),
            FlatButton(
                 onPressed: () {
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (_) => MailScreen(),
                  ),
                );
              },
              padding: EdgeInsets.only(top: 33),
              child: Column(
                children: [
                  Icon(
                    Icons.mail,
                    color: Colors.white,
                  ),
                  Text(
                    "Mail",
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

为按钮创建一个单独的小部件,并在参数中传递颜色、图标、文本和路径。

不要在导航器中使用 push,而是使用 pushNamed 并在此处使用传递的路由名称。

这是一个解决方案:

1。定义 AppAction 模型

class AppAction {
  final Color color;
  final String label;
  final Color labelColor;
  final IconData iconData;
  final Color iconColor;
  final void Function(BuildContext) callback;

  AppAction({
    this.color = Colors.blueGrey,
    this.label,
    this.labelColor = Colors.white,
    this.iconData,
    this.iconColor = Colors.white,
    this.callback,
  });
}

您也可以使用 route 或其名称来代替回调函数。不过,如果需要,回调将允许您定义其他类型的操作。 (例如:启动外部 URL、触发模态对话框等)

2。定义您的应用程序操作

final List<AppAction> actions = [
  AppAction(
    label: 'Products',
    iconData: Icons.shopping_cart_outlined,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => ProductScreen()));
    },
  ),
  AppAction(
    label: 'Mails',
    iconData: Icons.mail,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => MailScreen()));
    },
  ),
  AppAction(
    color: Colors.white,
    label: 'Urgent',
    labelColor: Colors.redAccent,
    iconData: Icons.dangerous,
    iconColor: Colors.redAccent,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => UrgentScreen()));
    },
  ),
  AppAction(
    color: Colors.green.shade200,
    label: 'News',
    labelColor: Colors.black,
    iconData: Icons.new_releases,
    iconColor: Colors.green,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => NewsScreen()));
    },
  ),
];

3。定义一个通用的 ActionButton

class ActionButton extends StatelessWidget {
  final AppAction action;

  const ActionButton({
    Key key,
    this.action,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return OutlinedButton.icon(
      onPressed: () => action.callback?.call(context),
      style: OutlinedButton.styleFrom(
        backgroundColor: action.color,
        padding: const EdgeInsets.all(16.0),
      ),
      label: Text(action.label, style: TextStyle(color: action.labelColor)),
      icon: Icon(action.iconData, color: action.iconColor),
    );
  }
}

4。简化您的主页

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: 'Home Page',
      child: Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(30.0),
        child: GridView.extent(
          maxCrossAxisExtent: 120,
          crossAxisSpacing: 15.0,
          mainAxisSpacing: 15.0,
          children: actions.map((action) => ActionButton(action: action)).toList(),
        ),
      ),
    );
  }
}

瞧!如果需要,这里有一个完整的独立代码示例供您使用:

import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      title: 'Flutter Demo',
      home: HomePage(),
    ),
  );
}

class AppAction {
  final Color color;
  final String label;
  final Color labelColor;
  final IconData iconData;
  final Color iconColor;
  final void Function(BuildContext) callback;

  AppAction({
    this.color = Colors.blueGrey,
    this.label,
    this.labelColor = Colors.white,
    this.iconData,
    this.iconColor = Colors.white,
    this.callback,
  });
}

final List<AppAction> actions = [
  AppAction(
    label: 'Products',
    iconData: Icons.shopping_cart_outlined,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => ProductScreen()));
    },
  ),
  AppAction(
    label: 'Mails',
    iconData: Icons.mail,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => MailScreen()));
    },
  ),
  AppAction(
    color: Colors.white,
    label: 'Urgent',
    labelColor: Colors.redAccent,
    iconData: Icons.dangerous,
    iconColor: Colors.redAccent,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => UrgentScreen()));
    },
  ),
  AppAction(
    color: Colors.green.shade200,
    label: 'News',
    labelColor: Colors.black,
    iconData: Icons.new_releases,
    iconColor: Colors.green,
    callback: (context) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (_) => NewsScreen()));
    },
  ),
];

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: 'Home Page',
      child: Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(30.0),
        child: GridView.extent(
          maxCrossAxisExtent: 120,
          crossAxisSpacing: 15.0,
          mainAxisSpacing: 15.0,
          children:
              actions.map((action) => ActionButton(action: action)).toList(),
        ),
      ),
    );
  }
}

class AppLayout extends StatelessWidget {
  final String pageTitle;
  final Widget child;

  const AppLayout({Key key, this.pageTitle, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(pageTitle)),
      body: child,
    );
  }
}

class ActionButton extends StatelessWidget {
  final AppAction action;

  const ActionButton({
    Key key,
    this.action,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return OutlinedButton.icon(
      onPressed: () => action.callback?.call(context),
      style: OutlinedButton.styleFrom(
        backgroundColor: action.color,
        padding: const EdgeInsets.all(16.0),
      ),
      label: Text(action.label, style: TextStyle(color: action.labelColor)),
      icon: Icon(action.iconData, color: action.iconColor),
    );
  }
}

class ProductScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: ('Products Page'),
      child: Center(
        child: Text('LIST OF PRODUCTS'),
      ),
    );
  }
}

class MailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: 'Mail Page',
      child: Center(
        child: Text('LIST OF MAIL'),
      ),
    );
  }
}

class UrgentScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: 'Urgent Page',
      child: Center(
        child: Text('URGENT', style: TextStyle(color: Colors.redAccent)),
      ),
    );
  }
}

class NewsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AppLayout(
      pageTitle: 'News Page',
      child: Center(
        child: Text('NEWS', style: TextStyle(color: Colors.green)),
      ),
    );
  }
}