如何在Flutter健康应用中实现BoxDecoration下方的水平ListView
Flutter健康应用首页:添加水平ListView实现方案
我是Flutter新手,正在做一款健康应用的首页,想在现有带BoxDecoration的功能按钮容器下方添加一个水平ListView。
设计图与当前效果
- Figma设计图:

- 当前实现效果:

现有代码
//import 'dart:js'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get/get_navigation/get_navigation.dart'; import 'package:medreminder/NewsArticle/news_home.dart'; import 'package:medreminder/Recipe/recipe_home.dart'; import 'package:medreminder/Reminder/ui/theme.dart'; import 'package:medreminder/TipsAndTricks/screens/tips_screen.dart'; import 'Reminder/home_reminder.dart'; import 'Reminder/ui/widgets/button.dart'; import 'package:medreminder/main.dart'; import 'package:medreminder/home_page.dart'; void main() { // debugPaintSizeEnabled = true; runApp(const HomePage()); } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Mr. Health App"), backgroundColor: Color(0XFF0080FE), ), body: Stack( alignment: Alignment.topCenter, children: [ Image.asset('images/MenuImg.jpg'), Container( height: 250, width: 310, margin: const EdgeInsets.only(top: 150), padding: const EdgeInsets.only( left: 20, right: 20, top: 15, bottom: 15, ), decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(25.0)), color: context.theme.backgroundColor, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 6), ), ], ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( children: [ IconButton( icon: Image.asset('images/reminder.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const ReminderHomePage()), ); }, ), Text("Medicine\nReminder", style: normalStyle,) ], ), Column( children: [ IconButton( icon: Image.asset('images/news.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => NewsHomePage()), ); }, ), Text(" News \n& Article", style: normalStyle) ], ), Column( children: [ IconButton( icon: Image.asset('images/recipe.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => RecipeHomePage()), ); }, ), Text("Healty Food \n Recipe", style: normalStyle) ], ), ], ), SizedBox(height: 10,), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( children: [ IconButton( icon: Image.asset('images/tips.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const TipsList()), ); }, ), Text("Tips &\n Tricks", style: normalStyle,) ], ), Column( children: [ IconButton( icon: Image.asset('images/about.png'), iconSize: 45, onPressed: () { }, ), Text("About Us\n", style: normalStyle) ], ), Column( children: [ IconButton( icon: Image.asset('images/recipe.png'), iconSize: 45, onPressed: () {}, ), Text("Healty Food \n Recipe", style: normalStyle) ], ), ], ) ], ), ), ], )); } }
修改方案与完整代码
原来的Stack布局适合层叠元素,要实现上下排列的容器和ListView,换成Column更方便。同时添加水平ListView,具体修改如下:
- 将
body里的Stack替换为Column,背景图作为第一个子项,然后是功能容器,最后是水平ListView。 - 给功能容器添加
margin让它和背景图、ListView保持合适间距。 - 实现水平ListView,设置
scrollDirection: Axis.horizontal,并自定义item样式。
修改后的完整代码:
//import 'dart:js'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get/get_navigation/get_navigation.dart'; import 'package:medreminder/NewsArticle/news_home.dart'; import 'package:medreminder/Recipe/recipe_home.dart'; import 'package:medreminder/Reminder/ui/theme.dart'; import 'package:medreminder/TipsAndTricks/screens/tips_screen.dart'; import 'Reminder/home_reminder.dart'; import 'Reminder/ui/widgets/button.dart'; import 'package:medreminder/main.dart'; import 'package:medreminder/home_page.dart'; void main() { // debugPaintSizeEnabled = true; runApp(const HomePage()); } class HomePage extends StatelessWidget { const HomePage({super.key}); // 模拟水平ListView的数据 final List<Map<String, String>> listItems = [ {"title": "健康贴士1", "image": "images/tip1.png"}, {"title": "饮食指南", "image": "images/diet.png"}, {"title": "运动计划", "image": "images/exercise.png"}, {"title": "睡眠建议", "image": "images/sleep.png"}, ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Mr. Health App"), backgroundColor: const Color(0XFF0080FE), ), body: SingleChildScrollView( // 允许页面整体滚动 child: Column( children: [ // 顶部背景图 Image.asset('images/MenuImg.jpg'), // 功能按钮容器 Container( height: 250, width: 310, margin: const EdgeInsets.symmetric(vertical: 20), padding: const EdgeInsets.only( left: 20, right: 20, top: 15, bottom: 15, ), decoration: BoxDecoration( borderRadius: const BorderRadius.all(Radius.circular(25.0)), color: context.theme.backgroundColor, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), spreadRadius: 2, blurRadius: 5, offset: const Offset(0, 6), ), ], ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( children: [ IconButton( icon: Image.asset('images/reminder.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const ReminderHomePage()), ); }, ), Text("Medicine\nReminder", style: normalStyle,) ], ), Column( children: [ IconButton( icon: Image.asset('images/news.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => NewsHomePage()), ); }, ), Text(" News \n& Article", style: normalStyle) ], ), Column( children: [ IconButton( icon: Image.asset('images/recipe.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => RecipeHomePage()), ); }, ), Text("Healty Food \n Recipe", style: normalStyle) ], ), ], ), const SizedBox(height: 10,), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( children: [ IconButton( icon: Image.asset('images/tips.png'), iconSize: 45, onPressed: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute(builder: (context) => const TipsList()), ); }, ), Text("Tips &\n Tricks", style: normalStyle,) ], ), Column( children: [ IconButton( icon: Image.asset('images/about.png'), iconSize: 45, onPressed: () {}, ), Text("About Us\n", style: normalStyle) ], ), Column( children: [ IconButton( icon: Image.asset('images/recipe.png'), iconSize: 45, onPressed: () {}, ), Text("Healty Food \n Recipe", style: normalStyle) ], ), ], ) ], ), ), // 水平ListView Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "健康资讯", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), SizedBox( height: 180, // 设置ListView高度 child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: listItems.length, itemBuilder: (context, index) { final item = listItems[index]; return Container( width: 150, margin: const EdgeInsets.only(right: 12), decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ) ] ), child: Column( children: [ ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), child: Image.asset( item["image"]!, height: 120, width: double.infinity, fit: BoxFit.cover, ), ), Padding( padding: const EdgeInsets.all(8.0), child: Text( item["title"]!, textAlign: TextAlign.center, style: const TextStyle(fontSize: 14), ), ) ], ), ); }, ), ), ], ), ), const SizedBox(height: 20), ], ), ), ); } }
关键说明
- 用
SingleChildScrollView包裹Column,避免页面内容超出屏幕时出现溢出问题。 - 水平ListView通过
scrollDirection: Axis.horizontal实现,设置固定高度确保布局稳定。 - 可以根据设计图调整ListView的item样式、数据和间距,匹配UI需求。
内容的提问来源于stack exchange,提问作者NyK
相关产品推荐
相关产品推荐

