Проблема в том, что вы создаете CBandeira> GerenciadorTelaLogadaCadastro> GerenciadorTelaLogada, и вместо того, чтобы позволить StatefulWidget выполнять и вызывать метод сборки каждого из них, когда это необходимо, вы вызываете их внутри других методов сборки при использовании .build(context)
, делая это, вы говорите классу использовать контекст, который вы им даете (вот почему ошибка, он не может найти каркас в дереве, потому что вы используете тот же контекст), вместо того, чтобы позволить StatefulWidget создать свой собственный ниже в дереве. Возьмем, к примеру, GMenu (), это виджет, который вы создаете где-то еще и из-за него можете повторно использовать в любое время. сначала вам нужно построить Scaffold, затем внутри тела, который вы хотите обернуть другим классом, и с помощью этого logi c вы go, пока не дойдете до минимального класса или виджета, который вам нужен в дереве.
//If you're not going to use setState or doens't need to update the widget then just use a StatelessWidget
class GerenciadorTelaLogada extends StatelessWidget {
final String titulo;
final Widget child;
final Widget floatingActButton;
GerenciadorTelaLogada(
{@required this.titulo, this.child, this.floatingActButton});
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(this.titulo),
centerTitle: true,
),
drawer: GMenu(),
floatingActionButton: this.floatingActButton,
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
color: Color(0xff5b71b3),
padding: EdgeInsets.only(top: 10),
child: this.child ?? const SizedBox(),
),
),
),
);
}
}
Затем вы можете повторно использовать этот виджет с любым другим классом
class CBandeira extends StatefulWidget {
@override
_CBandeiraState createState() => _CBandeiraState();
}
class _CBandeiraState extends State<CBandeira> {
final _formKey = GlobalKey<FormState>();
var formInputs = <GTextBox>[];
@override
Widget build(BuildContext context) {
// Now you can use it in other's widget build method and create your own child, title and fab
return GerenciadorTelaLogada(
titulo: "Cadastro de Bandeira",
floatingActButton: FloatingActionButton(
child: Icon(
Icons.save,
color: Colors.white,
),
backgroundColor: Colors.green,
onPressed: () {
if (_formKey.currentState.validate()) {
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text("Test"),
));
}
},
),
child: Form(
key: _formKey,
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
leading: Icon(
formInputs[index].icon,
color: Colors.white,
),
title: formInputs[index],
);
},
separatorBuilder: (context, index) {
return SizedBox(height: 10);
},
itemCount: formInputs.length),
),
);
}
}
ОБНОВЛЕНИЕ
Я использовал Scaffold перед созданием виджета, поэтому я не видел ошибки, теперь я ее вижу, и что вам нужно сделать в этом случае, это обернуть виджет, который вы хотите использовать Scaffold.of(context)
, с помощью Builder, он позволяет вам создать новый контекст и после этого он может проверить выше в дереве для помоста. До этого они оба находятся в одном контексте, поэтому он не нашел его
class CBandeira extends StatefulWidget {
@override
_CBandeiraState createState() => _CBandeiraState();
}
class _CBandeiraState extends State<CBandeira> {
final _formKey = GlobalKey<FormState>();
var formInputs = <GTextBox>[
GTextBox(
label: "Código",
tipo: TextBoxTipo.numerico,
icon: Icons.person,
),
GTextBox(
label: "Nome",
tipo: TextBoxTipo.tudo,
icon: Icons.person,
validator: (valor) {
if (valor.length < 3) {
return 'Nome muito curto';
}
return null;
},
),
GTextBox(
label: "Descrição",
tipo: TextBoxTipo.tudo,
icon: Icons.details,
),
];
@override
Widget build(BuildContext context) {
// Now you can use it in other's widget build method and create your own child, title and fab
return GerenciadorTelaLogada(
titulo: "Cadastro de Bandeira",
floatingActButton: Builder( //with this It can now check for a scaffold above the tree
builder: (context){
return FloatingActionButton(
child: Icon(
Icons.save,
color: Colors.white,
),
backgroundColor: Colors.green,
onPressed: () {
if (_formKey.currentState.validate()) {
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text("Test"),
));
}
},
);
},
),
child: Form(
key: _formKey,
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
leading: Icon(
formInputs[index].icon,
color: Colors.white,
),
title: formInputs[index],
);
},
separatorBuilder: (context, index) {
return SizedBox(height: 10);
},
itemCount: formInputs.length),
),
);
}
}

ОБНОВЛЕНИЕ С ГЛОБАЛЬНЫМ КЛЮЧОМ
class GerenciadorTelaLogada extends StatelessWidget {
final String titulo;
final Widget child;
final Widget floatActButton;
final GlobalKey<ScaffoldState> scaffoldKey;
const GerenciadorTelaLogada(
{this.child, @required this.titulo, @required this.scaffoldKey, this.floatActButton});
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey, //use it here
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(this.titulo),
centerTitle: true,
),
floatingActionButton: this.floatActButton,
// Side Menu
//drawer: GMenu(),
// Corpo do DashBoard
body: SafeArea(
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: Container(
child: this.child ?? const SizedBox(),
color: Color(0xff5b71b3),
padding: EdgeInsets.only(top: 10),
),
)),
);
}
}
class GerenciadorTelaLogadaCadastro extends StatelessWidget {
/// Função executada quando clicar no botão de salvar
final VoidCallback onSalvar;
final GlobalKey<ScaffoldState> scaffoldKey;
final String titulo;
final Widget child;
/// Construtor
const GerenciadorTelaLogadaCadastro(
{@required this.titulo, @required this.scaffoldKey, this.child, @required this.onSalvar});
// Costroi a parte excluisa das telas de cadastro
@override
Widget build(BuildContext context) {
/// Retorna a tela base construida com as informações possiveis em uma tela.
return GerenciadorTelaLogada(
scaffoldKey: scaffoldKey, //pass it to the scaffold
titulo: this.titulo,
child: this.child,
floatActButton: FloatingActionButton(
child: Icon(
Icons.save,
color: Colors.white,
),
backgroundColor: Colors.green,
onPressed: this.onSalvar,
),
);
}
}
//Just created this but I don't know how it really looks like
class GTextBox{
final String label;
final IconData icon;
GTextBox({this.label, this.icon});
}
class CBandeira extends StatefulWidget {
@override
_CBandeiraState createState() => _CBandeiraState();
}
class _CBandeiraState extends State<CBandeira>
with SingleTickerProviderStateMixin {
final _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
var formInputs = <GTextBox>[
GTextBox(
label: "Código",
tipo: TextBoxTipo.numerico,
icon: Icons.person,
),
GTextBox(
label: "Nome",
tipo: TextBoxTipo.tudo,
icon: Icons.person,
validator: (valor) {
if (valor.length < 3) {
return 'Nome muito curto';
}
return null;
},
),
GTextBox(
label: "Descrição",
tipo: TextBoxTipo.tudo,
icon: Icons.details,
),
];
@override
Widget build(BuildContext context) {
return GerenciadorTelaLogadaCadastro(
scaffoldKey: scaffoldKey, //pass the GlobalKey to the Scaffold
onSalvar: () {
if (_formKey.currentState.validate()) {
//use the scaffoldKey instead
scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text("Form is valid"),
));
}
},
titulo: "Cadastro de Bandeira",
child: Form(
key: _formKey,
child: ListView.separated(
itemBuilder: (context, index) {
return ListTile(
leading: Icon(
formInputs[index].icon,
color: Colors.white,
),
title: formInputs[index],
);
},
separatorBuilder: (context, index) {
return SizedBox(height: 10);
},
itemCount: formInputs.length),
),
);
}
}