Я работаю над своим первым приложением Flutter (отладка на моем телефоне Android). У меня есть список с элементами строки. Когда вы долго нажимаете строку, она копирует содержимое в буфер обмена пользователя. Это отлично работает!
Но мне нужно, чтобы пользователь знал, что контент был скопирован.
Я пытался следовать многим руководствам по попытке получить строку, окруженную методом сборки или внутри Scaffold, но я не могу заставить ее работать. Есть ли альтернативный способ уведомления пользователя (просто) о том, что что-то вроде «Скопировано!» произошло?
Обратите внимание на закомментированный Scaffold.of(...
ниже. Просто кажется, что должен быть более простой способ уведомления пользователя, кроме обертывания всего в Scaffold. (и когда я пытаюсь, это ломает мой макет).
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(),
),
)),
)
],
),
),
));
}
}
Цель состоит в том, чтобы иметь такую страницу (см. Изображение), которая у меня есть, и она работает и прокручивается... и т. д., но я не могу заставить ее работать с эшафотом и, следовательно, не смог использовать Снэк-бар. Каждая «строка» (для которой предназначен этот файл) должна отображать закусочную на longPress.
Вы можете использовать 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\""))),
),
);
},
),
),
],
),
);
}
}
@Dave Вы можете легко обернуть свой виджет в Scaffold
, сделайте GestureDetector
дочерним элементом Scaffold
в своем примере.
Когда я оборачиваю GestureDetector в Scaffold и делаю GestureDetector «телом», я получаю: Another exception was thrown: RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
Та же ошибка также для «_RenderInkFeatures», «RenderPhysicalModel», «RenderRepaintBoundary» и «RenderIndexedSemantics».
Есть несколько вещей, которые вам нужно сделать, например, использовать 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(),
),
),
),
)
],
),
),
),
),
);
}
}
Это вызывает следующую ошибку: RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
Я не уверен, завершен ли ваш метод 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()),
);
}
}
Я пробовал это и получаю много ошибок, некоторые из которых такие же, как и при попытке использовать Scaffold: «Было выбрано другое исключение: объекту _RenderInkFeatures был присвоен бесконечный размер во время макета». и ряд других.
Не могли бы вы поделиться классом, где вы используете RowRule
?
Я прочитал ваши комментарии ко всем ответам и вот мой вывод:
Вам нужен ScaffoldState
объект, который находится чуть выше виджета в дереве, чтобы показать Snackbar
. Вы можете пройти через GlobalKey
, как многие предлагали. Довольно просто, если Scaffold
создается внутри build
виджета, но если он находится вне виджета (в вашем случае), то это усложняется. Вам нужно передать этот ключ везде, где он вам нужен, через аргументы конструктора дочерних виджетов.
Scaffold.of(context)
— очень удобный способ сделать это. Как и Унаследованный виджет, Scaffold.of(BuildContext context)
дает вам доступ к ближайшему ScaffoldState
объекту над деревом. В противном случае получить этот экземпляр (передав его в качестве аргументов конструктора) может быть кошмаром, если ваше дерево было очень глубоким.
Извините, чтобы разочаровать, но я не думаю, что есть лучший или более чистый метод, чем этот, если вы хотите получить ScaffoldState
, который не встроен в сборку этого виджета. Вы можете вызвать его в любом виджете, который имеет Scaffold
в качестве родителя.
Scaffold.of(context)
не имеет ничего общего с унаследованными виджетами
@RémiRousselet Я немного поискал, и вы правы, Scafoold не является IW, но он предоставляет аналогичный .of()
статический метод для получения ближайшего объекта State. Я просто предположил, что это будет IW. В любом случае исправил мой ответ. Спасибо, что просветили меня!!
Это простая замена плагина для Snackbar под названием «Flushbar». Вы можете получить плагин здесь - https://pub.dartlang.org/packages/flushbar Вам не нужно заботиться о какой-либо упаковке виджетов в каркас, также вы получаете множество модификаций для вас, таких как градиент фона, добавление форм и т. д. В Snackbar и все такое. Внутри вашего onLongPressed в GestureDetectore вы можете сделать это.
onLongPressed:(){
Clipboard.setData(new ClipboardData(text: ruleGroup['label'] + " " + ruleGroup['details']));
Flushbar(
message: "Copied !!",
duration: Duration(seconds: 3),
)..show(context);
}
Это отобразит закусочную в вашем приложении, где вы хотели бы ее видеть, и вы можете получить множество доступных вам модификаций, чтобы вы могли сделать ее похожей на ваше приложение.
Для чего нужен буфер обмена? Это вообще связано с вашим ответом?
FYI: Flushbar СНЯТ С ПРОИЗВОДСТВА. pub.dartlang.org/packages/flushbar
Я сделал выпадающий баннер упаковка на пабе, который позволяет легко оповещать пользователей об ошибках или подтверждать успех. Работа продолжается, так как я продолжаю добавлять визуально богатые функции.
У меня нет Scaffold в этом файле/макете. Я видел это как рекомендуемый метод, но как мне получить доступ к GlobalKey здесь? Все примеры, которые я видел, похожи на этот, где Scaffold находится в том же файле, что и longPress.