我正在开发我的第一个Flutter应用程序(在我的Android手机上调试)。我有一个包含行项目的列表。当您长按该行时,它会将内容复制到用户的剪贴板中。这很棒!
但我需要让用户知道内容已被复制。
我试图遵循许多关于尝试将行包围在构建方法或Scaffold中的教程,但我无法使用任何工作。是否有另一种方法可以通知用户(简单地)“复制!”之类的东西。发生?
请注意下面注释掉的Scaffold.of(...
。看起来除了在脚手架中包装所有东西之外,似乎必须有一种更简单的方法来通知用户。 (当我尝试时,它会破坏我的布局)。
import 'package:flutter/material.dart';
import 'package:my_app/Theme.dart' as MyTheme;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/services.dart';
class RowRule extends StatelessWidget {
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(new Text(ruleGroup['label'],
style: MyTheme.TextStyles.articleContentLabelTextStyle));
}
if (!ruleGroup['details'].isEmpty) {
builder.add(new Text(ruleGroup['details'],
style: MyTheme.TextStyles.articleContentTextStyle));
}
return builder;
}
@override
Widget build(BuildContext context) {
return new GestureDetector(
onLongPress: () {
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
// Scaffold.of(context).showSnackBar(SnackBar
// (content: Text('text copied')));
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 3.0),
child: new FlatButton(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 0.0),
child: new Stack(
children: <Widget>[
new Container(
margin: const EdgeInsets.symmetric(
vertical: MyTheme.Dimens.ruleGroupListRowMarginVertical),
child: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.0, vertical: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildChildren(),
),
)),
)
],
),
),
));
}
}
我的目标是拥有一个这样的页面(见图),我有它,它可以工作和滚动......等等,但是我不能让它与Scaffold一起使用,因此,无法使用小吃店。每个“行”(此文件用于)应该在longPress上显示一个快餐栏。
这是一个名为“Flushbar”的Snackbar的简单插件替代品。你可以在这里获得插件 - https://pub.dartlang.org/packages/flushbar你不需要处理任何小部件包装到脚手架中也可以为你做很多修改,比如背景渐变,添加表格等等到Snackbar和所有。你可以在GestureDetectore中使用onLongPressed进行操作。
onLongPressed:(){
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
Flushbar(
message: "Copied !!",
duration: Duration(seconds: 3),
)..show(context);
}
这将显示您应用程序中的小吃栏,您可以在其中查看它,您可以获得大量修改,以便您可以根据您的应用程序查看它。
您可以使用GlobalKey
使其按您希望的方式工作。
由于我无法访问您的数据库内容,因此我就是这样做的。将此代码复制并粘贴到您的班级中并相应地进行更改。我也相信你的RowRule
课有什么问题,你能复制我给你的完整代码并运行吗?
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatelessWidget {
final GlobalKey<ScaffoldState> _key = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFFFFFFF).withOpacity(0.9),
key: _key,
body: Column(
children: <Widget>[
Container(
color: Color.fromRGBO(52, 56, 245, 1),
height: 150,
alignment: Alignment.center,
child: Container(width: 56, padding: EdgeInsets.only(top: 12), decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.yellow)),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: 120,
itemBuilder: (context, index) {
return Container(
color: Colors.white,
margin: const EdgeInsets.all(4),
child: ListTile(
title: Text("Row #$index"),
onLongPress: () => _key.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Copied \"Row #$index\""))),
),
);
},
),
),
],
),
);
}
}
我不确定你的build()
方法是否已经完成,或者你还没有改变它,因为它包含许多小部件,这些小部件只是多余的。就像没有必要在Container
和Container
以及Padding
中使用FlatButton
,这将使整个屏幕可点击。还有Column
不是一个好主意,因为如果你有更多的数据,你的屏幕可能会溢出。请改用ListView
。
所以,如果您接受我的建议,请使用这个简单的代码,它可以为您提供您真正想要的东西。 (参见build()
方法只有5行。
class RowRule extends StatelessWidget {
final GlobalKey<ScaffoldState> globalKey = GlobalKey();
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(
ListTile(
title: Text(ruleGroup['label'], style: MyTheme.TextStyles.articleContentLabelTextStyle),
onLongPress: () {
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Clicked")));
},
),
);
}
if (!ruleGroup['details'].isEmpty) {
builder.add(
ListTile(
title: Text(ruleGroup['details'], style: MyTheme.TextStyles.articleContentTextStyle),
onLongPress: () {
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("Clicked")));
},
),
);
}
return builder;
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: globalKey,
body: ListView(children: _buildChildren()),
);
}
}
有几件事你需要做,比如使用onPressed
的FlatButton
属性,必须允许点击,将你的GestureDetector
包裹在Scaffold
中。我进一步修改了代码,以便它使用GlobalKey
让事情变得简单。
这是最终的代码(你的方式)
class RowRule extends StatelessWidget {
final GlobalKey<ScaffoldState> globalKey = GlobalKey();
final DocumentSnapshot ruleGroup;
RowRule(this.ruleGroup);
_buildChildren() {
var builder = <Widget>[];
if (!ruleGroup['label'].isEmpty) {
builder.add(new Text(ruleGroup['label'], style: MyTheme.TextStyles.articleContentLabelTextStyle));
}
if (!ruleGroup['details'].isEmpty) {
builder.add(new Text(ruleGroup['details'], style: MyTheme.TextStyles.articleContentTextStyle));
}
return builder;
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: globalKey,
body: GestureDetector(
onLongPress: () {
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
globalKey.currentState
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text('text copied')));
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 3.0),
child: new FlatButton(
onPressed: () => print("Handle button press here"),
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 0.0),
child: new Stack(
children: <Widget>[
new Container(
margin: const EdgeInsets.symmetric(vertical: MyTheme.Dimens.ruleGroupListRowMarginVertical),
child: new Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 32.0, vertical: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _buildChildren(),
),
),
),
)
],
),
),
),
),
);
}
}
我读了你对所有答案的评论,这是我的结论:
你需要ScaffoldState
对象,它位于树中的小部件上方,以显示Snackbar
。正如许多人所建议的那样,你可以通过GlobalKey
获得它。如果Scaffold
是在widget的build
中创建的,那么相当简单,但是如果它在widget之外(在你的情况下)那么它就变得复杂了。您需要通过子窗口小部件的构造函数参数在任何需要的地方传递该密钥。
Scaffold.of(context)
是一个非常巧妙的方式来做到这一点。就像InheritedWidget一样,Scaffold.of(BuildContext context)
让您可以访问树上方最近的ScaffoldState
物体。如果您的树非常深,那么获取该实例(通过将其作为构造函数参数传递)可能是一场噩梦。
对不起,令人失望,但我认为没有比这更好或更干净的方法,如果你想获得不在该小部件的构建内部构建的ScaffoldState
。您可以在任何以Scaffold
作为父级的小部件中调用它。