- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我想使用 TabBar 和 BottomNavigationBar 来控制相同的 TabBarView,其主体是自定义小部件 RankingTable 的列表(仅在演示中放置一个并使用文本小部件作为第二个子部件)。我的问题是点击导航栏时,它不会更新 TabBarView 主体,例如排名表不更新;在下面的演示代码中,我在表格中放置了相同的数据,但表格上方的日期下拉格式应该不同,因为我在点击导航栏时将不同的格式化程序传递到每个数据表中。也就是说,在第二张截图中,在 Nav1 上,它仍然显示与 Nav0 上的第一张截图相同的下拉日期格式。截图1:
如果我在 TabBarView
主体中放置一个简单的小部件,例如 Text,那么当点击导航栏项目时它会按预期更新,不确定这是否意味着问题出在我的自定义 RankingTable
小部件。此外,尽管在导航栏中点击新项目时主体不会更新,但如果我切换选项卡,例如从 Tab1
到 Tab2
并将其切换回 Tab1
,然后主体得到正确更新,与相应的导航栏项目匹配。感觉当点击导航时 body 数据确实得到了更新,但它只是没有得到呈现。
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() => runApp(new Demo());
class Demo extends StatefulWidget {
@override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> with TickerProviderStateMixin {
int _currentIndex = 0;
Map<DateTime, List<RankingBase>> _playerDateRanking;
TabController controller;
List<_NavigationIconView> _navigationIconViews;
@override
void initState() {
super.initState();
controller = TabController(length: 2, vsync: this);
_navigationIconViews = <_NavigationIconView>[
_NavigationIconView(
icon: Icon(Icons.calendar_view_day),
title: 'Nav0',
color: Colors.deepOrange,
vsync: this,
),
_NavigationIconView(
icon: Icon(Icons.date_range),
title: 'Nav1',
color: Colors.deepOrange,
vsync: this,
),
];
_playerDateRanking = {
DateTime(2018, 9, 10): [
PlayerRanking('Tony', 7, 6, 140, 110, 80),
PlayerRanking('John', 7, 2, 120, 130, 56),
PlayerRanking('Mike', 8, 5, 120, 130, 70),
PlayerRanking('Clar', 6, 2, 100, 134, 63)
],
DateTime(2018, 9, 12): [
PlayerRanking('Tony', 7, 6, 140, 110, 80),
PlayerRanking('John', 7, 2, 120, 130, 56),
PlayerRanking('Mike', 8, 5, 120, 130, 70),
PlayerRanking('Clare', 6, 2, 100, 134, 63),
PlayerRanking('Jo', 5, 1, 100, 134, 63)
]
};
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
bottom: TabBar(
controller: controller,
tabs: <Widget>[Text('Tab1'), Text('Tab2')],
),
),
body: TabBarView(
controller: controller, //TabController(length: 2, vsync: this),
children: <Widget>[
buildRankingTable(_currentIndex),
Text('TEst'),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: _navigationIconViews.map((x) => x.item).toList(),
onTap: (int index) {
setState(() {
_currentIndex = index;
});
},
),
),
);
}
Widget buildRankingTable(int currentIndex) {
if (currentIndex == 0) {
return RankingTable(_playerDateRanking, dateFormatter: 'yMMMEd');
} else if (currentIndex == 1) {
return RankingTable(_playerDateRanking,
dateFormatter: 'MMMM'); // different date formatter here!
}
return Text('TODO...');
}
}
class _NavigationIconView {
_NavigationIconView({
Widget icon,
//Widget activeIcon,
String title,
Color color,
TickerProvider vsync,
}) : _icon = icon,
_color = color,
_title = title,
item = new BottomNavigationBarItem(
icon: icon,
// activeIcon: activeIcon,
title: new Text(title),
backgroundColor: color,
),
controller = new AnimationController(
duration: kThemeAnimationDuration,
vsync: vsync,
) {
_animation = new CurvedAnimation(
parent: controller,
curve: const Interval(0.5, 1.0, curve: Curves.fastOutSlowIn),
);
}
final Widget _icon;
final Color _color;
final String _title;
final BottomNavigationBarItem item;
final AnimationController controller;
CurvedAnimation _animation;
}
class PlayerRanking extends RankingBase {
String name;
PlayerRanking(this.name, played, won, pointsWon, pointsLost, duration)
: super(played, won, pointsWon, pointsLost, duration);
}
class RankingBase {
DateTime date;
int won;
int played;
int duration;
int pointsWon;
int pointsLost;
double get winRatio => won / played;
RankingBase(
this.played, this.won, this.pointsWon, this.pointsLost, this.duration);
static int performanceSort(RankingBase rb1, RankingBase rb2) {
if (rb1.winRatio > rb2.winRatio) return -1;
if (rb1.winRatio < rb2.winRatio) return 1;
if (rb1.played > rb2.played) return -1;
if (rb2.played == rb2.played) return rb1.pointsWon.compareTo(rb2.pointsWon);
return -1;
}
}
// this puts a scrollable datatable and optionally a header widget into a ListView
class RankingTable extends StatefulWidget {
final Map<DateTime, List<RankingBase>> rankingMap;
final bool hasHeaderWidget;
final String dateFormatter;
//final bool isPlayer;
RankingTable(this.rankingMap,
{this.dateFormatter, this.hasHeaderWidget = true});
@override
_RankingTableState createState() => _RankingTableState(this.rankingMap,
dateFormatter: this.dateFormatter, hasHeaderWidget: this.hasHeaderWidget);
}
class _RankingTableState extends State<RankingTable> {
Map<DateTime, List<RankingBase>> rankingMap;
final bool hasHeaderWidget;
final String dateFormatter;
//final bool isPlayer;
_RankingTableState(this.rankingMap,
{this.dateFormatter, this.hasHeaderWidget = true});
DateTime _selectedDate;
@override
initState() {
super.initState();
_selectedDate = rankingMap.keys.last;
}
DataTable buildRankingTable() {
rankingMap[_selectedDate].sort(RankingBase.performanceSort);
String nameOrPair =
rankingMap[_selectedDate].first is PlayerRanking ? 'Name' : 'Pair';
int rank = 1;
return DataTable(
columns: <DataColumn>[
DataColumn(label: Text('Rank')),
DataColumn(label: Text(nameOrPair)),
DataColumn(label: Text('Played')),
DataColumn(label: Text('Win Ratio')),
DataColumn(label: Text('Points Won-Loss')),
DataColumn(label: Text('Duration')),
],
rows: rankingMap[_selectedDate].map((RankingBase pr) {
DataCell titleCell;
if (pr is PlayerRanking)
titleCell = DataCell(Text('${pr.name}'));
else {
// var pair = pr as PairRanking;
// titleCell = DataCell(Text('${pair.player1Name}\n${pair.player2Name}'));
}
return DataRow(cells: [
DataCell(Text('${rank++}')),
titleCell,
DataCell(Text('${pr.played}')),
DataCell(Text('${NumberFormat("0.##%").format(pr.won / pr.played)}')),
DataCell(Text('${pr.pointsWon} - ${pr.pointsLost}')),
DataCell(Text('${pr.duration}')),
]);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
List<Widget> childrenWidgets = [];
if (hasHeaderWidget) {
var dateDropdown = DropdownButton<DateTime>(
items: rankingMap.keys
.map((date) => DropdownMenuItem(
child: Text(
'${DateFormat(dateFormatter).format(date)}'), //yMMMEd
value: date,
))
.toList(),
value: _selectedDate,
onChanged: (value) {
setState(() {
_selectedDate = value;
});
},
);
childrenWidgets.add(dateDropdown);
}
childrenWidgets.add(SingleChildScrollView(
padding: EdgeInsets.all(20.0),
scrollDirection: Axis.horizontal,
child: buildRankingTable(),
));
return ListView(
padding: EdgeInsets.all(10.0),
children: childrenWidgets,
);
}
}
最佳答案
问题出在你的State
上。
首先,您所在的州不需要构造函数。您可以通过调用 widget.youFinalField
访问小部件的变量。
问题是:当您返回一个 new RankingTable
时,底层的 state
不是重新创建而是重建(build
和 didUpdateWidget
方法被调用)。因为您在构造中传递了变量(仅在第一次使用),所以您的格式化程序不会更新。
解决方案非常简单,而不是在您的 state
中使用构造函数,只需通过小部件访问变量即可。
工作代码状态代码:
// this puts a scrollable datatable and optionally a header widget into a ListView
class RankingTable extends StatefulWidget {
final Map<DateTime, List<RankingBase>> rankingMap;
final bool hasHeaderWidget;
final String dateFormatter;
//final bool isPlayer;
RankingTable(this.rankingMap,
{this.dateFormatter, this.hasHeaderWidget = true});
@override
_RankingTableState createState() => _RankingTableState();
}
class _RankingTableState extends State<RankingTable> {
DateTime _selectedDate;
@override
void initState() {
super.initState();
_selectedDate = widget.rankingMap.keys.last;
}
DataTable buildRankingTable() {
widget.rankingMap[_selectedDate].sort(RankingBase.performanceSort);
String nameOrPair =
widget.rankingMap[_selectedDate].first is PlayerRanking ? 'Name' : 'Pair';
int rank = 1;
return DataTable(
columns: <DataColumn>[
DataColumn(label: Text('Rank')),
DataColumn(label: Text(nameOrPair)),
DataColumn(label: Text('Played')),
DataColumn(label: Text('Win Ratio')),
DataColumn(label: Text('Points Won-Loss')),
DataColumn(label: Text('Duration')),
],
rows: widget.rankingMap[_selectedDate].map((RankingBase pr) {
DataCell titleCell;
if (pr is PlayerRanking)
titleCell = DataCell(Text('${pr.name}'));
else {
// var pair = pr as PairRanking;
// titleCell = DataCell(Text('${pair.player1Name}\n${pair.player2Name}'));
}
return DataRow(cells: [
DataCell(Text('${rank++}')),
titleCell,
DataCell(Text('${pr.played}')),
DataCell(Text('')),
DataCell(Text('${pr.pointsWon} - ${pr.pointsLost}')),
DataCell(Text('${pr.duration}')),
]);
}).toList(),
);
}
@override
Widget build(BuildContext context) {
List<Widget> childrenWidgets = [];
if (widget.hasHeaderWidget) {
var dateDropdown = DropdownButton<DateTime>(
items: widget.rankingMap.keys
.map((date) => DropdownMenuItem(
child: Text(
'$date ${widget.dateFormatter}'), //yMMMEd
value: date,
))
.toList(),
value: _selectedDate,
onChanged: (value) {
setState(() {
_selectedDate = value;
});
},
);
childrenWidgets.add(dateDropdown);
}
childrenWidgets.add(SingleChildScrollView(
padding: EdgeInsets.all(20.0),
scrollDirection: Axis.horizontal,
child: buildRankingTable(),
));
return ListView(
padding: EdgeInsets.all(10.0),
children: childrenWidgets,
);
}
}
关于flutter - 导航不会使用自定义小部件更新 TabBarView 主体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52431855/
我查看了网站上的一些问题,但还没有完全弄清楚我做错了什么。我有一些这样的代码: var mongoose = require('mongoose'), db = mongoose.connect('m
基本上,根据 this bl.ocks,我试图在开始新序列之前让所有 block 都变为 0。我认为我需要的是以下顺序: 更新为0 退出到0 更新随机数 输入新号码 我尝试通过添加以下代码块来遵循上述
我试图通过使用随机数在循环中设置 JSlider 位置来模拟“赛马”的投注结果。我的问题是,当然,我无法在线程执行时更新 GUI,因此我的 JSlider 似乎没有在竞赛,它们从头到尾都在运行。我尝试
该功能非常简单: 变量:$table是正在更新的表$fields 是表中的字段,$values 从帖子生成并放入 $values 数组中而$where是表的索引字段的id值$indxfldnm 是索引
让我们想象一个环境:有一个数据库客户端和一个数据库服务器。数据库客户端可以是 Java 程序或其他程序等;数据库服务器可以是mysql、oracle等。 需求是在数据库服务器上的一个表中插入大量记录。
在我当前的应用程序中,我正在制作一个菜单结构,它可以递归地创建自己的子菜单。然而,由于这个原因,我发现很难也允许某种重新排序方法。大多数应用程序可能只是通过“排序”列进行排序,但是在这种情况下,尽管这
Provisioning Profile 有 key , key 链依赖于它。我想知道 key 什么时候会改变。 Key will change after renew Provisioning Pr
截至目前,我在\server\publications.js 中有我的 MongoDB“选择”,例如: Meteor.publish("jobLocations", function () { r
我读到 UI 应该始终在主线程上更新。但是,当谈到实现这些更新的首选方法时,我有点困惑。 我有各种函数可以执行一些条件检查,然后使用结果来确定如何更新 UI。我的问题是整个函数应该在主线程上运行吗?应
我在代理后面,我无法构建 Docker 镜像。 我试过 FROM ubuntu , FROM centos和 FROM alpine ,但是 apt-get update/yum update/apk
我构建了一个 Java 应用程序,它向外部授权客户端公开网络服务。 Web 服务使用带有证书身份验证的 WS-security。基本上我们充当自定义证书颁发机构 - 我们在我们的服务器上维护一个 ja
因此,我有时会在上传新版本时使用 app_offline.htm 使应用程序离线。 但是,当我上传较大的 dll 时,我收到黄色错误屏幕,指出无法加载 dll。 这似乎与我对 app_offline.
我刚刚下载了 VS Apache Cordova Tools Update 5,但遇到了 Node 和 NPM 的问题。我使用默认的空白 cordova 项目进行测试。 版本 如果我在 VS 项目中对
所以我有一个使用传单库实例化的 map 对象。 map 实例在单独的模板中创建并以这种方式路由:- var app = angular.module('myApp', ['ui', 'ngResour
我使用较早的 Java 6 u 3 获得的帧速率是新版本的两倍。很奇怪。谁能解释一下? 在 Core 2 Duo 1.83ghz 上,集成视频(仅使用一个内核)- 1500(较旧的 java)与 70
我正在使用 angular 1.2 ng-repeat 创建的 div 也包含 ng-click 点击时 ng-click 更新 $scope $scope 中的变化反射(reflect)在使用 $a
这些方法有什么区别 public final void moveCamera(CameraUpdate更新)和public final void animateCamera (CameraUpdate
我尝试了另一篇文章中某人评论中关于如何将树更改为列表的建议。但是,我在某处(或某物)有未声明的变量,所以我列表中的值是 [_G667, _G673, _G679],而不是 [5, 2, 6],这是正确
实现以下场景的最佳方法是什么? 我需要从java应用程序调用/查询包含数百万条记录的数据库表。然后,对于表中的每条记录,我的应用程序应该调用第三方 API 并获取状态字段作为响应。然后我的应用程序应该
只是在编写一些与 java 图形相关的代码,这是我今天的讲座中的非常简单的示例。不管怎样,互联网似乎说更新不会被系统触发器调用,例如调整框架大小等。在这个例子中,更新是由这样的触发器调用的(因此当我只
我是一名优秀的程序员,十分优秀!