← Frontend / Flutter

04_常用容器Widget

Flutter 常用容器 Widget 介绍

Container、Scaffold、Card 等常用容器 Widget 的完整用法。


Container(万能容器)

对应 CSS 中带完整样式属性的 <div>:

Container(
  width: 200,
  height: 100,
  margin: const EdgeInsets.all(16),           // 外边距(CSS margin)
  padding: const EdgeInsets.symmetric(        // 内边距(CSS padding)
    horizontal: 20,
    vertical: 10,
  ),
  decoration: BoxDecoration(
    color: Colors.white,                      // 背景色
    borderRadius: BorderRadius.circular(12),  // 圆角(CSS border-radius)
    border: Border.all(color: Colors.grey, width: 1), // 边框
    boxShadow: [                              // 阴影(CSS box-shadow)
      BoxShadow(
        color: Colors.black.withOpacity(0.1),
        blurRadius: 8,
        offset: const Offset(0, 4),
      ),
    ],
    gradient: const LinearGradient(           // 渐变背景
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
      colors: [Colors.blue, Colors.purple],
    ),
    image: const DecorationImage(             // 背景图
      image: NetworkImage('https://example.com/bg.jpg'),
      fit: BoxFit.cover,
    ),
  ),
  child: const Text('内容'),
)

注意: decoration 和 color 不能同时设置(decoration 里已有 color 属性)。


Scaffold(页面脚手架)

Material Design 页面的标准骨架,提供 AppBar、Drawer、BottomNavigationBar 等插槽:

Scaffold(
  // 顶部导航栏
  appBar: AppBar(
    title: const Text('页面标题'),
    leading: IconButton(          // 左侧按钮(默认返回键)
      icon: const Icon(Icons.menu),
      onPressed: () {},
    ),
    actions: [                    // 右侧操作按钮
      IconButton(icon: const Icon(Icons.search), onPressed: () {}),
      IconButton(icon: const Icon(Icons.more_vert), onPressed: () {}),
    ],
    backgroundColor: Colors.blue,
    elevation: 0,                 // 阴影高度
  ),

  // 主内容区域
  body: const Center(child: Text('页面内容')),

  // 右下角悬浮按钮(FAB)
  floatingActionButton: FloatingActionButton(
    onPressed: () {},
    child: const Icon(Icons.add),
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,

  // 底部导航栏
  bottomNavigationBar: BottomNavigationBar(
    currentIndex: 0,
    type: BottomNavigationBarType.fixed, // 超 3 项必须设置 fixed
    selectedItemColor: Colors.blue,
    onTap: (index) {},
    items: const [
      BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
      BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'),
      BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
    ],
  ),

  // 侧边抽屉
  drawer: Drawer(
    child: ListView(
      padding: EdgeInsets.zero,
      children: [
        const DrawerHeader(
          decoration: BoxDecoration(color: Colors.blue),
          child: Text('用户名', style: TextStyle(color: Colors.white, fontSize: 20)),
        ),
        ListTile(
          leading: const Icon(Icons.home),
          title: const Text('首页'),
          onTap: () {},
        ),
        ListTile(
          leading: const Icon(Icons.settings),
          title: const Text('设置'),
          onTap: () {},
        ),
      ],
    ),
  ),
)

Card(卡片)

Card(
  elevation: 4,                        // 阴影高度
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(12),
  ),
  margin: const EdgeInsets.all(8),
  color: Colors.white,
  child: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('卡片标题', style: Theme.of(context).textTheme.titleLarge),
        const SizedBox(height: 8),
        const Text('卡片描述内容,可以是多行文字。'),
        const SizedBox(height: 12),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            TextButton(onPressed: () {}, child: const Text('取消')),
            const SizedBox(width: 8),
            ElevatedButton(onPressed: () {}, child: const Text('确认')),
          ],
        ),
      ],
    ),
  ),
)

AppBar 进阶

// 可滚动时折叠的 AppBar(SliverAppBar)
CustomScrollView(
  slivers: [
    SliverAppBar(
      expandedHeight: 200,           // 展开时的高度
      pinned: true,                  // 滚动时固定在顶部
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('标题'),
        background: Image.network(
          'https://example.com/banner.jpg',
          fit: BoxFit.cover,
        ),
      ),
    ),
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) => ListTile(title: Text('Item $index')),
        childCount: 30,
      ),
    ),
  ],
)

SnackBar 和 Dialog

// SnackBar(底部提示条,类似 Toast)
ScaffoldMessenger.of(context).showSnackBar(
  SnackBar(
    content: const Text('操作成功'),
    duration: const Duration(seconds: 2),
    action: SnackBarAction(
      label: '撤销',
      onPressed: () {},
    ),
  ),
);

// AlertDialog(确认对话框)
showDialog(
  context: context,
  builder: (context) => AlertDialog(
    title: const Text('确认删除'),
    content: const Text('此操作不可撤销,确认继续?'),
    actions: [
      TextButton(
        onPressed: () => Navigator.of(context).pop(false),
        child: const Text('取消'),
      ),
      ElevatedButton(
        onPressed: () => Navigator.of(context).pop(true),
        child: const Text('确认'),
      ),
    ],
  ),
);

// BottomSheet(底部弹出面板)
showModalBottomSheet(
  context: context,
  shape: const RoundedRectangleBorder(
    borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
  ),
  builder: (context) => Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ListTile(leading: const Icon(Icons.share), title: const Text('分享'), onTap: () {}),
        ListTile(leading: const Icon(Icons.copy), title: const Text('复制'), onTap: () {}),
        ListTile(leading: const Icon(Icons.delete, color: Colors.red),
            title: const Text('删除', style: TextStyle(color: Colors.red)),
            onTap: () {}),
      ],
    ),
  ),
);