我正在构建一个 Flutter 应用程序,我正试图将注意力集中在导航和状态上。我在下面构建了一个非常简单的应用程序,它有两个页面,上面都有递增按钮。它们都共享一个 Scaffold 定义,因此两个页面上都有一个一致的抽屉导航。
基本上我想要的功能是 FirstPage 和 SecondPage 是单例。因此,如果您将 FirstPage 上的计数器递增几次,转到 SecondPage,然后通过抽屉返回到 FirstPage(而不是后退按钮),FirstPage 的计数器仍应递增。
现在,如果您这样做,由于 Navigation.push(),它似乎会创建一个新的 FirstPage 实例。此外,如果您在 FirstPage 上并出于某种原因使用抽屉再次单击“First Page”,您不应丢失状态。
我在这里看到一位 Flutter 开发人员提到术语“non-linear navigation”,这让我觉得这样的事情是可能的。感谢您的帮助。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(title: "Navigation", home: FirstPage());
}
}
class MyScaffold extends Scaffold {
final BuildContext context;
final Text title;
final Widget body;
MyScaffold({
@required this.context,
@required this.title,
@required this.body,
}) : assert(context != null),
assert(title != null),
assert(body != null),
super(
appBar: AppBar(title: title),
drawer: Drawer(
child: ListView(padding: EdgeInsets.zero, children: <Widget>[
SizedBox(height: 100.0),
ListTile(
title: Text("First Page"),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => FirstPage()))),
ListTile(
title: Text("Second Page"),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => SecondPage()))),
])),
body: body);
}
class FirstPage extends StatefulWidget {
@override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
int _counter = 0;
void _increment() => setState(() => _counter++);
@override
Widget build(BuildContext context) {
return MyScaffold(
context: context,
title: Text("First Page"),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$_counter'),
RaisedButton(onPressed: _increment, child: Icon(Icons.add))
])));
}
}
class SecondPage extends StatefulWidget {
@override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
int _counter = 0;
void _increment() => setState(() => _counter++);
@override
Widget build(BuildContext context) {
return MyScaffold(
context: context,
title: Text("Second Page"),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('$_counter'),
RaisedButton(onPressed: _increment, child: Icon(Icons.add))
])));
}
}
最佳答案
与其扩展 Scaffold,我建议制作一个 StatelessWidget,它构建一个脚手架并将一个子 widget 作为参数。按照您的方式进行操作,您不会获得 context 或任何东西,并且在 Flutter 中通常建议封装而不是继承。
除此之外,您还可以分离前进/后退的逻辑。您可以执行 push(secondPage) 然后 pop 回到第一页,而不是每次都推送一个新页面。 flutter 中的导航是一个栈;每次按下都是在添加到它的顶部,每次弹出都是在移除顶部元素。
如果您希望 SecondPage 保留其计数器,那将有点困难。您在这里有几个选择——第一个是在构建它时传入一个初始值。然后它会在内部增加该值,然后当您调用 Navigator.pop(context, [value]) 时,您会将该值传回。它将保存到第一个屏幕的状态,然后当您再次推送页面时,您将传递新的初始值。
第二个选项是将计数器的值保留在高于第二页的级别(使用 StatefulWidget 和可能的 InheritedWidget)- 即在任何包含导航器/ Material 应用程序的小部件中。不过,这可能有点矫枉过正。
编辑:为了回应 OP 的评论,已经明确表示实际上有几个页面和更复杂的信息,而不仅仅是一个计数器。
有多种方法可以处理这个问题;一种是使用 Redux 实现应用程序作为策略;当与 flutter_persist 一起使用时它可以成为一个非常强大的持久状态工具,我相信还有一个插件可以与 firestore 集成以进行云备份(对此不确定)。
不过我自己并不是 redux 的 super 粉丝;它增加了相当多的开销,在我看来这与 flutter 的简单性背道而驰(尽管我可以看到对于大型应用程序或团队它如何创造一致性)。
一个更简单的选项如编辑前所述;使用 InheritedWidget 包含更高级别的状态。我在下面做了一个简单的例子:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => new MyAppState();
}
class MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return CounterInfo(
child: new MaterialApp(
routes: {
"/": (context) => new FirstPage(),
"/second": (context) => new SecondPage(),
},
),
);
}
}
class _InheritedCounterInfo extends InheritedWidget {
final CounterInfoState data;
_InheritedCounterInfo({
Key key,
@required this.data,
@required Widget child,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(_InheritedCounterInfo old) => true;
}
class CounterInfo extends StatefulWidget {
final Widget child;
const CounterInfo({Key key, this.child}) : super(key: key);
static CounterInfoState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_InheritedCounterInfo) as _InheritedCounterInfo).data;
}
@override
State<StatefulWidget> createState() => new CounterInfoState();
}
class CounterInfoState extends State<CounterInfo> {
int firstCounter = 0;
int secondCounter = 0;
void incrementFirst() {
setState(() {
firstCounter++;
});
}
void incrementSecond() {
setState(() {
secondCounter++;
});
}
@override
Widget build(BuildContext context) => new _InheritedCounterInfo(data: this, child: widget.child);
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterInfo = CounterInfo.of(context);
return new MyScaffold(
title: "First page",
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("${counterInfo.firstCounter}"),
RaisedButton(onPressed: counterInfo.incrementFirst, child: Icon(Icons.add)),
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counterInfo = CounterInfo.of(context);
return new MyScaffold(
title: "Second page",
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("${counterInfo.secondCounter}"),
RaisedButton(onPressed: counterInfo.incrementSecond, child: Icon(Icons.add)),
],
),
),
);
}
}
class MyScaffold extends StatelessWidget {
final String title;
final Widget child;
const MyScaffold({Key key, this.title, this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(title: new Text(title)),
drawer: Drawer(
child: ListView(padding: EdgeInsets.zero, children: <Widget>[
SizedBox(height: 100.0),
ListTile(
title: Text("First Page"),
onTap: () => Navigator.of(context).pushReplacementNamed("/"),
),
ListTile(title: Text("Second Page"), onTap: () => Navigator.of(context).pushReplacementNamed("/second")),
])),
body: child,
);
}
}
无论您是走这条路还是考虑使用 Redux,this是一个有用的网站,具有各种 Flutter 架构模型,包括使用继承的小部件。
关于dart - 保留或恢复页面状态的抽屉式导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51067916/
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested
对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我想为我的Task模型创建一个status属性,该属性将按以下顺序指示它在三部分进度中的位置:打开=>进行中=>完成。它的工作方式类似于亚马逊包裹的交付方式:已订购=>已发货=>已交付。我想知道设置此属性的最佳方法是什么。我可能是错的,但创建三个独立的bool属性似乎有点多余。实现此目标的最佳方法是什么? 最佳答案 Rails4有一个内置的enummacro.它使用单个整数列并映射到键列表。classOrderenumstatus:[:ordered,:shipped,:delivered]end状态映射如下:{ordered:0,
s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成
require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
据我们所知,Jekyll默认分页仅支持index.html,我想创建blog.html并在那里包含分页。有什么解决办法吗? 最佳答案 如果您创建一个名为/blog的目录并在其中放置一个index.html文件,那么您可以向_config.yml表示paginate_path:"blog/page:num"。不是使用根文件夹中的默认index.html作为分页器模板,而是使用/blog/index.html。分页器将根据需要生成类似/blog/page2/和/blog/page3/的页面。这将使您到达yourwebsite.com/b