Flutter用户订阅节目列表布局问题:重复调用组件仅显示一次
Flutter 用户个人页面组件重复显示与滚动布局问题
我在开发Flutter用户个人页面时,两次调用_userprofile(context)组件来展示用户订阅的节目,但组件只显示了一次。我需要展示6个该组件,并且布局支持滚动展开。
当前效果:
现有代码
import 'package:flutter/material.dart'; import 'package:flashy_tab_bar2/flashy_tab_bar2.dart'; import 'workout_post_detail.dart'; import 'editprofile_business.dart'; import 'seeall_workout.dart'; class ClientPage extends StatefulWidget { const ClientPage({super.key}); @override ClientPageState createState() => ClientPageState(); } class ClientPageState extends State<ClientPage> { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: const Text( 'Your profile', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ), ), backgroundColor: Colors.black, ), body: Padding( padding: const EdgeInsets.all(10), child: Stack( alignment: Alignment.bottomCenter, children: [ Column( children: [ const SizedBox( height: 10, ), Center( child: CircleAvatar( radius: 60, backgroundColor: Colors.white, child: CircleAvatar( radius: 46, backgroundColor: Colors.grey.shade100, child: const Text('Pic'), ), ), ), const SizedBox( height: 10, ), const Text( 'Usermane', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), const SizedBox( height: 20, ), Container( height: 60, width: MediaQuery.of(context).size.width * 0.90, decoration: ShapeDecoration( shape: const StadiumBorder(), color: Colors.grey[200], shadows: [ BoxShadow( color: Colors.grey.shade400, blurRadius: 10, spreadRadius: 2, ), ]), child: const Padding( padding: EdgeInsets.only(left: 25.0, right: 25), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Subscribers', style: TextStyle(fontWeight: FontWeight.bold), ), Text( '8', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.grey, ), ), ], ), ), ), const SizedBox( height: 20, ), const Text( 'PROGRAMS SUBSCRIBED', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), const SizedBox( height: 20, ), Stack( children: [ //align your container to center here with Align widget Align( alignment: Alignment.center, child: Container( height: 300, width: MediaQuery.of(context).size.width * 0.90, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), // shape: const StadiumBorder(), color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 5, blurRadius: 7, offset: const Offset( 0, 3), // changes position of shadow ), ], ), ), ), _userprofile(context), _userprofile(context) ], ), ], ) ], ), ), ); } } _userprofile(context) { return Padding( padding: const EdgeInsets.fromLTRB(16, 10, 16, 10), //wrap the Row in a Column and take out the Divider out of Row, // and put it inside the Column right below the Row child: Column( children: [ Row( children: [ CircleAvatar( radius: 35, backgroundColor: Colors.white, child: CircleAvatar( radius: 30, backgroundColor: Colors.grey.shade100, child: const Text('Pic'))), const SizedBox( height: 20, ), const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(left: 8.0), child: Text( 'username', style: TextStyle(fontWeight: FontWeight.bold), ), ), Padding( padding: EdgeInsets.only(left: 8.0), child: Text('Name of the program'), ), ], ), const SizedBox( width: 20, ), const Padding( padding: EdgeInsets.all(8.0), ), ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all<Color>(Colors.black), ), child: const Text( 'ACCESS', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white), ), ), ], ), const Divider( thickness: 1, color: Color.fromARGB(255, 172, 172, 172), ) ], ), ); }
问题原因
- Stack布局导致组件重叠:用
Stack放置_userprofile组件时,所有子组件会堆叠在同一位置,所以两次调用看起来只显示了一个。 - 固定高度容器限制滚动:外层容器设置了固定高度300,无法容纳6个组件,也不支持滚动。
修复后的代码
import 'package:flutter/material.dart'; import 'package:flashy_tab_bar2/flashy_tab_bar2.dart'; import 'workout_post_detail.dart'; import 'editprofile_business.dart'; import 'seeall_workout.dart'; class ClientPage extends StatefulWidget { const ClientPage({super.key}); @override ClientPageState createState() => ClientPageState(); } class ClientPageState extends State<ClientPage> { // 模拟6个订阅节目数据 final List<Map<String, String>> subscribedPrograms = List.generate(6, (index) => { 'username': '用户$index', 'programName': '健身计划$index' }); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: const Text( 'Your profile', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.white, ), ), backgroundColor: Colors.black, ), body: Padding( padding: const EdgeInsets.all(10), // 外层添加SingleChildScrollView,让整个页面可滚动 child: SingleChildScrollView( child: Column( children: [ const SizedBox(height: 10), Center( child: CircleAvatar( radius: 60, backgroundColor: Colors.white, child: CircleAvatar( radius: 46, backgroundColor: Colors.grey.shade100, child: const Text('Pic'), ), ), ), const SizedBox(height: 10), const Text( 'Usermane', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), const SizedBox(height: 20), Container( height: 60, width: MediaQuery.of(context).size.width * 0.90, decoration: ShapeDecoration( shape: const StadiumBorder(), color: Colors.grey[200], shadows: [ BoxShadow( color: Colors.grey.shade400, blurRadius: 10, spreadRadius: 2, ), ]), child: const Padding( padding: EdgeInsets.only(left: 25.0, right: 25), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Subscribers', style: TextStyle(fontWeight: FontWeight.bold), ), Text( '8', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.grey, ), ), ], ), ), ), const SizedBox(height: 20), const Text( 'PROGRAMS SUBSCRIBED', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), ), const SizedBox(height: 20), // 替换Stack为带背景的ListView Container( width: MediaQuery.of(context).size.width * 0.90, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: Colors.white, boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 5, blurRadius: 7, offset: const Offset(0, 3), ), ], ), child: ListView.builder( shrinkWrap: true, // 让ListView自适应内容高度 physics: const NeverScrollableScrollPhysics(), // 外层已有滚动,禁止内部滚动 itemCount: subscribedPrograms.length, itemBuilder: (context, index) { return _userprofile( context, username: subscribedPrograms[index]['username']!, programName: subscribedPrograms[index]['programName']! ); }, ), ), ], ), ), ), ); } } // 修改组件,支持传入动态数据 Widget _userprofile(BuildContext context, {required String username, required String programName}) { return Padding( padding: const EdgeInsets.fromLTRB(16, 10, 16, 10), child: Column( children: [ Row( children: [ CircleAvatar( radius: 35, backgroundColor: Colors.white, child: CircleAvatar( radius: 30, backgroundColor: Colors.grey.shade100, child: const Text('Pic'))), const SizedBox(width: 20), // 修复原代码中SizedBox的height错误 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( username, style: const TextStyle(fontWeight: FontWeight.bold), ), ), Padding( padding: const EdgeInsets.only(left: 8.0), child: Text(programName), ), ], ), const Spacer(), // 用Spacer让按钮自动靠右对齐 ElevatedButton( onPressed: () {}, style: ButtonStyle( backgroundColor: WidgetStateProperty.all<Color>(Colors.black), ), child: const Text( 'ACCESS', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white), ), ), ], ), const Divider( thickness: 1, color: Color.fromARGB(255, 172, 172, 172), ) ], ), ); }
关键修改点
- 外层添加
SingleChildScrollView,让整个页面支持滚动。 - 用
Container包裹ListView.builder替代原Stack,保留卡片样式的同时,动态生成6个组件。 - 修改
_userprofile组件,支持传入动态用户名和节目名称,适配真实数据场景。 - 修复原代码中Row里的
SizedBox错误(误用height属性),并用Spacer优化按钮布局,适配不同屏幕宽度。
内容的提问来源于stack exchange,提问作者sanda17
相关产品推荐
相关产品推荐

