英文:
Flutter - Constructor Confusion
问题
在应用的主页上,用户点击他们想要查看的账户,然后显示特定账户的数据模型页面上的余额(请参见截图)。我以为我知道该怎么做,但什么都不起作用。我已经在应用的其他部分让它工作了,但是在这里无法让它工作。我该如何实现这个目标?以下是代码:
在 OwenTab 页面上,我想用数据模型页面上的实际余额替换 "Text($20.00)"。
import 'package:flutter/material.dart';
class OwenTab extends StatelessWidget {
const OwenTab({super.key});
@override
Widget build(BuildContext context) {
// 这里应该显示实际余额,你需要将余额从数据模型中获取并替换下面的文本。
return Column(
children: [
const Text(
'$20.00',
style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'Available to spend',
style: TextStyle(fontSize: 15),
),
Icon(Icons.keyboard_arrow_down_rounded, size: 30),
],
),
],
);
}
}
这里是导入 OwenTab() 的地方。
import 'package:flutter/material.dart';
import '../../pages/eloise_tab.dart';
import '../../pages/henry_tab.dart';
import '../../pages/owen_tab.dart';
class MoneyTabBar extends StatelessWidget {
final int tabIndex;
const MoneyTabBar({
super.key,
required this.tabIndex,
});
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: tabIndex,
length: 3, // 3个标签页
child: Scaffold(
// 标签栏背景颜色
backgroundColor: Colors.white,
body: Column(
children: const [
TabBar(
padding: EdgeInsets.only(left: 80, right: 80),
indicatorColor: Colors.red,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Colors.black,
unselectedLabelColor: Colors.grey,
labelStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
tabs: [
// "Owen" 标签
Tab(
text: 'Owen',
),
// "Eloise" 标签
Tab(
text: 'Eloise',
),
// "Henry" 标签
Tab(
text: 'Henry',
),
],
),
SizedBox(height: 25),
Expanded(
child: TabBarView(
children: [
// "Owen" 标签内容
OwenTab(),
// "Eloise" 标签内容
EloiseTab(),
// "Henry" 标签内容
HenryTab(),
],
),
),
],
),
),
);
}
}
这是数据模型代码:
import 'package:flutter/material.dart';
import '../models/child_tile.dart';
import '../models/home_tile.dart';
class GoHenryData extends ChangeNotifier {
// 列表
final List<HomeTile> _homeTiles = [
// HomeTile 对象列表
// ...
];
final List<ChildTile> _childTiles = [
// ChildTile 对象列表
// ...
];
// 获取器
List<HomeTile> get homeTiles => _homeTiles;
List<ChildTile> get childTiles => _childTiles;
}
这是 HomePage(),以防万一:
import 'package:flutter/material.dart';
import 'package:gohenry_clone/components/tiles/child_tile.dart';
import 'package:gohenry_clone/pages/money_page.dart';
import 'package:gohenry_clone/pages/savings_page.dart';
import 'package:provider/provider.dart';
import '../components/tiles/home_tiles.dart';
import '../data/gohenry_data.dart';
import '../models/child_tile.dart';
import '../models/home_tile.dart';
import 'cards_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Consumer<GoHenryData>(
builder: (context, value, child) => Scaffold(
// AppBar
appBar: AppBar(
toolbarHeight: 255,
elevation: 0,
flexibleSpace: Container(
color: Colors.red.shade400,
child: SafeArea(
child: Column(
children: [
// Header
const Padding(
padding: EdgeInsets.only(top: 20.0),
child: Text(
'Your parent balance',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white),
),
),
// Balance
const Padding(
padding: EdgeInsets.only(top: 30.0),
child: Text(
'\$40.00',
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
// ...
],
),
),
),
),
// Home Banner Tiles
body: Column(
children: [
Container(
height: 100,
child: Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: value.homeTiles.length,
itemBuilder: (context, index) {
HomeTile individualHomeTile = value.homeTiles[index];
return Padding(
padding: index == value.homeTiles.length - 1
? const EdgeInsets.fromLTRB(20, 0, 20, 0)
: const EdgeInsets.only(left: 20.0),
child: HomeTiles(
homeTiles: individualHomeTile,
),
);
},
),
),
),
const SizedBox(height: 10),
// ...
],
),
),
);
}
}
这是 MoneyPage(),以防万一:
import 'package:flutter/material.dart';
import '../components/widgets/money_tab_bar.dart';
class MoneyPage extends StatefulWidget {
final int tabIndex;
const MoneyPage({super.key, required this.tabIndex});
@override
State<MoneyPage> createState() => _CardsPageState();
}
class _CardsPageState extends State<MoneyPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: const IconThemeData(color: Colors.black),
actions: const [
Padding(
padding: EdgeInsets.only(right: 20.0),
child: Icon(Icons.pie_chart_outline, color: Colors.black),
),
],
backgroundColor: Colors.white,
elevation: 0,
<details>
<summary>英文:</summary>
On the home page of the app, the user clicks on the account they want to view and the balance from the data model page for that specific account is displayed (see screenshots). I thought I knew what to do but nothing is working. I have it working for other sections of the app, however I can't get it to work here. How can I achieve this? Here is the code:
On the OwenTab page, i want to replace the "Text(\$20.00)" with the actual balance from the data model page.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import 'package:flutter/material.dart';
class OwenTab extends StatelessWidget {
const OwenTab({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text(
'\$20.00',
style: TextStyle(fontSize: 36, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'Available to spend',
style: TextStyle(fontSize: 15),
),
Icon(Icons.keyboard_arrow_down_rounded, size: 30),
],
),
],
);
}
}
<!-- end snippet -->
Here is where the OwenTab() is imported.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import 'package:flutter/material.dart';
import '../../pages/eloise_tab.dart';
import '../../pages/henry_tab.dart';
import '../../pages/owen_tab.dart';
class MoneyTabBar extends StatelessWidget {
final int tabIndex;
const MoneyTabBar({
super.key,
required this.tabIndex,
});
@override
Widget build(BuildContext context) {
return DefaultTabController(
initialIndex: tabIndex,
length: 3, // 3 tabs
child: Scaffold(
// TabBar Background Color
backgroundColor: Colors.white,
body: Column(
children: const [
TabBar(
padding: EdgeInsets.only(left: 80, right: 80),
indicatorColor: Colors.red,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Colors.black,
unselectedLabelColor: Colors.grey,
labelStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
tabs: [
// "Owen" Tab
Tab(
text: 'Owen',
),
// "Eloise" Tab
Tab(
text: 'Eloise',
),
// "Henry" Tab
Tab(
text: 'Henry',
),
],
),
SizedBox(height: 25),
Expanded(
child: TabBarView(
children: [
// "Owen" Tab Content
OwenTab(),
// "Eloise" Tab Content
EloiseTab(),
// "Henry" Tab Content
HenryTab(),
],
),
),
],
),
),
);
}
}
<!-- end snippet -->
Here is the data models code:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import 'package:flutter/material.dart';
import '../models/child_tile.dart';
import '../models/home_tile.dart';
class GoHenryData extends ChangeNotifier {
//////////////////////////////////////////////////////////// LISTS ////////////////////////////////////////////////////////////
final List<HomeTile> _homeTiles = [
HomeTile(
iconImagePath: 'lib/assets/images/price-sticker.png',
title: 'New in GoHenry',
subTitle: 'Your app has new features!',
boxColor: Colors.deepPurple,
borderRadius: BorderRadius.circular(10),
),
HomeTile(
iconImagePath: 'lib/assets/images/money.png',
title: 'Set up mission payments',
subTitle: 'Reward your kids for learning',
boxColor: Colors.deepPurple,
borderRadius: BorderRadius.circular(50)),
HomeTile(
iconImagePath: 'lib/assets/images/well-done.png',
title: 'School\'s out?',
subTitle: 'Transfer money, say well done',
boxColor: Colors.black,
borderRadius: BorderRadius.circular(10)),
HomeTile(
iconImagePath: 'lib/assets/images/chat.png',
title: 'Claim you bonus',
subTitle: '\$50 for every friend referral',
boxColor: Colors.white,
borderRadius: BorderRadius.circular(10)),
];
final List<ChildTile> _childTiles = [
ChildTile(
avatarImagePath: const AssetImage('lib/assets/images/owen.jpg'),
childName: 'Owen',
balance: '\$20.00',
totalBalance: '\$22.00',
savingsBalance: '\$0.00',
bottomName: 'Owen',
),
ChildTile(
avatarImagePath: const AssetImage('lib/assets/images/eloise.jpg'),
childName: 'Eloise',
balance: '\$22.00',
totalBalance: '\$40.00',
savingsBalance: '\$0.00',
bottomName: 'Eloise',
),
ChildTile(
avatarImagePath: const AssetImage('lib/assets/images/henry.jpg'),
childName: 'Henry',
balance: '\$15.00',
totalBalance: '\$20.00',
savingsBalance: '\$0.00',
bottomName: 'Henry',
)
];
//////////////////////////////////////////////////////////// GETTERS ////////////////////////////////////////////////////////////
List<HomeTile> get homeTiles => _homeTiles;
List<ChildTile> get childTiles => _childTiles;
//////////////////////////////////////////////////////////// ADDERS ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////// REMOVERS ////////////////////////////////////////////////////////////
}
<!-- end snippet -->
Here is the HomePage(), just in case:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import 'package:flutter/material.dart';
import 'package:gohenry_clone/components/tiles/child_tile.dart';
import 'package:gohenry_clone/pages/money_page.dart';
import 'package:gohenry_clone/pages/savings_page.dart';
import 'package:provider/provider.dart';
import '../components/tiles/home_tiles.dart';
import '../data/gohenry_data.dart';
import '../models/child_tile.dart';
import '../models/home_tile.dart';
import 'cards_page.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Consumer<GoHenryData>(
builder: (context, value, child) => Scaffold(
// AppBar
appBar: AppBar(
toolbarHeight: 255,
elevation: 0,
flexibleSpace: Container(
color: Colors.red.shade400,
child: SafeArea(
child: Column(
children: [
// Header
const Padding(
padding: EdgeInsets.only(top: 20.0),
child: Text(
'Your parent balance',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.white),
),
),
// Balance
const Padding(
padding: EdgeInsets.only(top: 30.0),
child: Text(
'\$40.00',
style: TextStyle(
fontSize: 36,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
// Text
const Padding(
padding: EdgeInsets.only(top: 30.0),
child: Text(
'Next allowance in 2 days \$10.00',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w500),
),
),
// "Add Money" Button
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () => {},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white,
),
width: 190,
child: const Padding(
padding: EdgeInsets.all(15.0),
child: Center(
child: Text('Add money',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500)),
),
),
),
),
const SizedBox(
width: 12.0,
),
// "Transfer" Button
GestureDetector(
onTap: () => {},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white,
),
width: 190,
child: const Padding(
padding: EdgeInsets.all(15.0),
child: Center(
child: Text('Transfer',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500)),
),
),
),
),
],
),
),
],
),
),
),
),
// Home Banner Tiles
body: Column(
children: [
Container(
height: 100,
child: Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: value.homeTiles.length,
itemBuilder: (context, index) {
HomeTile individualHomeTile = value.homeTiles[index];
return Padding(
padding: index == value.homeTiles.length - 1
? const EdgeInsets.fromLTRB(20, 0, 20, 0)
: const EdgeInsets.only(left: 20.0),
child: HomeTiles(
homeTiles: individualHomeTile,
),
);
},
),
),
),
const SizedBox(height: 10),
// Child's Main Tiles
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: value.childTiles.length,
itemBuilder: (context, index) {
ChildTile individualChildTile = value.childTiles[index];
return Padding(
padding: const EdgeInsets.only(bottom: 10),
child: ChildTiles(
childTiles: individualChildTile,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MoneyPage(
tabIndex:
index, // Goes to corresponding child's account tab
),
),
);
},
onPress: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const CardsPage(),
),
);
},
onPressTwo: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const SavingsPage(),
),
);
},
),
);
},
),
),
],
),
),
);
}
}
<!-- end snippet -->
Here is the MoneyPage(), just in case:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
import 'package:flutter/material.dart';
import '../components/widgets/money_tab_bar.dart';
class MoneyPage extends StatefulWidget {
final int tabIndex;
const MoneyPage({super.key, required this.tabIndex});
@override
State<MoneyPage> createState() => _CardsPageState();
}
class _CardsPageState extends State<MoneyPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: const IconThemeData(color: Colors.black),
actions: const [
Padding(
padding: EdgeInsets.only(right: 20.0),
child: Icon(Icons.pie_chart_outline, color: Colors.black),
),
],
backgroundColor: Colors.white,
elevation: 0,
title: const Text(
'Money',
style: TextStyle(color: Colors.black, fontSize: 16),
),
),
body: MoneyTabBar(tabIndex: widget.tabIndex),
);
}
}
<!-- end snippet -->
Here are the screenshots:
[![enter image description here][1]][1]
[![enter image description here][2]][2]
[1]: https://i.stack.imgur.com/3MlhQ.png
[2]: https://i.stack.imgur.com/11LVM.png
</details>
# 答案1
**得分**: 0
以下是翻译好的内容:
似乎您的数据位于GoHenryData小部件中,这是一个ChangeNotifier。正如您可能已经知道的那样,这个小部件的目的是为其后代提供应用程序状态。
我还假设您已经正确地将您的changenotifier提供给您的应用程序,如[这里][1]所示。
下一步是使用Consumer小部件访问该数据。您正在寻找的数据将是`goHenryData.childTiles[0].totalBalance`。
但是,为每个硬编码的子项创建一个单独的小部件是一个不好的设计。与其创建OwenTab、EloiseTab和HenryTab,不如创建一个ChildTab,它的构造函数接受一个ChildTile作为参数,并可以用于所有3个子项。然后,您可以根据状态中的ChildTiles列表动态创建选项卡。
假设childTiles是应用程序状态中的ChildTiles列表,您可以如下生成选项卡
```dart
childTabHeaders = childTiles.map((e) => Tab(text: e.childName)));
childTabs = childTiles.map((e) => ChildTab(childTile: e));
然后可以使用这些选项卡构建MoneyTabBar小部件,该小部件现在可以支持任意数量的子项。此外,您在编写代码时无需知道子项的数量/名称,这使您可以执行诸如从数据库加载数据之类的操作。这对于实际使用此类应用程序是必要的。
英文:
It seems your data is in the GoHenryData widget, which is a ChangeNotifier. As you presumably know from getting this far, the purpose of this widget is to provide application state to it's descendants.
I'm also going to assume that you have correctly provided your changenotifier to your application, as seen here.
The next step is to access that data with the Consumer widget. The data you are looking for would then be goHenryData.childTiles[0].totalBalance
.
However, creating an individual widget for each of the hardcoded children is a poor design. Rather than creating an OwenTab, an EloiseTab, and a HenryTab, create a ChildTab that takes a ChildTile as a parameter in it's constructor and can be re-used for all 3. You can then dynamically create tabs based on the list of ChildTiles in the state.
Assuming childTiles is the list of ChildTiles in the app's state, you could then generate the tabs as follows
childTabHeaders = childTiles.map((e) => Tab(text: e.childName)));
childTabs = childTiles.map((e) => ChildTab(childTile: e));
These can then be used to build the MoneyTabBar widget, which could now support any number of children. Additionally, you don't need to know anything about the number/names of the children as you write the code, allowing you to do something like load the data from a database. This would be necessary for any practical use of an app like this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论