Передача данных текстового поля Flutter в родительский виджет

Как использовать данные текстового поля дочернего виджета из родительского виджета.

Я разрабатываю приложение типа flutter калькулятора. я хочу

Это основной класс калькулятора

class Calculator extends StatefulWidget {
  @override
  _CalculatorState createState() => _CalculatorState();
}

class _CalculatorState extends State<Calculator> {

  double soldPrice=0.00;
 
  void printSoldPrice(){
    print(soldPrice);
  }
  
 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: BgColor ,
      bottomNavigationBar: Container(
        decoration: BoxDecoration(
          borderRadius:BorderRadius.only(topLeft: Radius.circular(10), topRight:Radius.circular(10) ),
          color:YellowBg,
        ),
        alignment: Alignment.center,
        height: 50,
        
        child: Text('RESET',
        style: TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.w500,
          letterSpacing: 5,

        ),
        ),
      ),

      body: SafeArea(
              child: Column(
          children: <Widget>[
            SizedBox(height:10),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                EcalLogo(logoSize: 30,),  
              ],
            ),
            SizedBox(height:10),
         
            
            Padding(
              padding:EdgeInsets.symmetric(horizontal:10.0),
              child:FractionallySizedBox(
                widthFactor: 0.9,
                child: Container(
                height:1.0,
                width:130.0,
                color:Colors.white,),
              ),),

            SizedBox(height: 10,),

            Expanded(
              child:ListView(
                children: <Widget>[

                  TextFieldContainer1(
                    title: 'SOLD PRICE',
                    tagLine: "SALE PRICE WITOHUT SHIPPING",
                    icon: Icons.check_circle,
                    
                
                  ),
        
                ],
            ))


          ],
        ),
      )
      
    );
  }
}



Это дочерний класс TextFieldContainer1

class TextFieldContainer1 extends StatefulWidget {
  final String title;
  final String tagLine;
  final IconData icon;
  
  
  
  TextFieldContainer1({this.title,this.tagLine,this.icon});


  @override
  _TextFieldContainer1State createState() => _TextFieldContainer1State();
}

class _TextFieldContainer1State extends State<TextFieldContainer1> {

  final controller1 = TextEditingController();


  

  @override
  Widget build(BuildContext context) {
    return FractionallySizedBox(
      widthFactor: 0.95,
        child: Container(
         
          padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(10)),
            color: tileBackground,
          ),                      
          height: 57,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children:<Widget>[
              Container(
                child:Column(
                  
                  children:<Widget>[
                    Row(
                      
                      children:<Widget>[
                        Icon(widget.icon,
                        color: Colors.white,
                        size:27.5
                        ),
                        SizedBox(width:5),
                        Text(widget.title,
                        style: TextStyle(
                          
                          fontSize: 20,
                          color:Colors.white,
                          fontWeight: FontWeight.w500
                        ),
                        )
                      ]          
                    ),
                    Text(widget.tagLine,
                    style: TextStyle(
                      color:Color.fromRGBO(255, 255, 255, 0.5),
                      fontSize: 12
                    ),
                    )
                  ]
                )
              ),
              Container(
                padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
                decoration: BoxDecoration(
                  color: Color.fromRGBO(252, 205, 0, 0.2),
                  borderRadius: BorderRadius.all(Radius.circular(10)
                  )
                ),
                height: 40,
                width: 92,
                child: TextField(
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20
                  ),
                  autofocus: false,
                  decoration:InputDecoration( 
                    focusColor: YellowBg,
                    fillColor: YellowBg,
                    hoverColor: YellowBg,
                    enabledBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),
                    ),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),)
                  ) ,
                  keyboardType: TextInputType.number,
                  controller: controller1,
                  
                 
                ),
              )
            ],
          ),

      ),
    );
  }
}



Я хочу использовать данные controller1 (данные из текстового поля) в классе TextFieldContainer1 для обновления переменной soldPrice в классе калькулятора и просто распечатать ее при срабатывании textField onChanged. Как это сделать?


person Pasan Madhushan    schedule 10.05.2020    source источник


Ответы (3)


Полный рабочий код:

Добавлять

final Function(String) onChange;

в TextFieldContainer1

Добавлять

onChanged: widget.onChange,

в TextField (и удалить контроллер)

Добавлять

onChange: (val) => setState(() {
                          soldPrice = double.parse(val);
                          print(val);
                        })

к вызову TextFieldContainer1 в калькуляторе.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(child: Calculator()),
      ),
    );
  }
}

Color BgColor = Colors.white;
Color YellowBg = Colors.yellow;
Color tileBackground = Colors.black;

class Calculator extends StatefulWidget {
  @override
  _CalculatorState createState() => _CalculatorState();
}

class _CalculatorState extends State<Calculator> {

  double soldPrice=0.00;

  void printSoldPrice(){
    print(soldPrice);
  }



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: BgColor ,
      bottomNavigationBar: Container(
        decoration: BoxDecoration(
          borderRadius:BorderRadius.only(topLeft: Radius.circular(10), topRight:Radius.circular(10) ),
          color:YellowBg,
        ),
        alignment: Alignment.center,
        height: 50,

        child: Text('RESET',
        style: TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.w500,
          letterSpacing: 5,

        ),
        ),
      ),

      body: SafeArea(
              child: Column(
          children: <Widget>[
            SizedBox(height:10),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                FlutterLogo(size: 30,),  
              ],
            ),
            SizedBox(height:10),


            Padding(
              padding:EdgeInsets.symmetric(horizontal:10.0),
              child:FractionallySizedBox(
                widthFactor: 0.9,
                child: Container(
                height:1.0,
                width:130.0,
                color:Colors.white,),
              ),),

            SizedBox(height: 10,),

            Expanded(
              child:ListView(
                children: <Widget>[

                  TextFieldContainer1(
                    title: 'SOLD PRICE',
                    tagLine: "SALE PRICE WITOHUT SHIPPING",
                    icon: Icons.check_circle,

                    onChange: (val) => setState(() {
                      soldPrice = double.parse(val);
                      print(val);
                    })
                  ),

                ],
            )),
            Text("$soldPrice")

          ],
        ),
      )

    );
  }
}

class TextFieldContainer1 extends StatefulWidget {
  final String title;
  final String tagLine;
  final IconData icon;

  final Function(String) onChange;

  TextFieldContainer1({this.title,this.tagLine,this.icon, this.onChange});


  @override
  _TextFieldContainer1State createState() => _TextFieldContainer1State();
}

class _TextFieldContainer1State extends State<TextFieldContainer1> {

  @override
  Widget build(BuildContext context) {



    return FractionallySizedBox(
      widthFactor: 0.95,
        child: Container(

          padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(10)),
            color: tileBackground,
          ),                      
          height: 57,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children:<Widget>[
              Container(
                child:Column(

                  children:<Widget>[
                    Row(

                      children:<Widget>[
                        Icon(widget.icon,
                        color: Colors.white,
                        size:27.5
                        ),
                        SizedBox(width:5),
                        Text(widget.title,
                        style: TextStyle(

                          fontSize: 20,
                          color:Colors.white,
                          fontWeight: FontWeight.w500
                        ),
                        )
                      ]          
                    ),
                    Text(widget.tagLine,
                    style: TextStyle(
                      color:Color.fromRGBO(255, 255, 255, 0.5),
                      fontSize: 12
                    ),
                    )
                  ]
                )
              ),
              Container(
                padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
                decoration: BoxDecoration(
                  color: Color.fromRGBO(252, 205, 0, 0.2),
                  borderRadius: BorderRadius.all(Radius.circular(10)
                  )
                ),
                height: 40,
                width: 92,
                child: TextField(
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20
                  ),
                  autofocus: false,
                  decoration:InputDecoration( 
                    focusColor: YellowBg,
                    fillColor: YellowBg,
                    hoverColor: YellowBg,
                    enabledBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),
                    ),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),)
                  ) ,
                  keyboardType: TextInputType.number,
                  onChanged: widget.onChange,
                ),
              )
            ],
          ),

      ),
    );
  }
}
person camillo777    schedule 10.05.2020
comment
Теперь работает нормально. Это правильный метод передачи данных текстового поля родительскому виджету. Спасибо - person Pasan Madhushan; 10.05.2020

Создать собственный класс для textField довольно просто. Ниже приведены два шага для этого. Первый шаг - создать виджет с отслеживанием состояния для текстового поля.

 RCTextField({
@required this.hintText,
@required this.labelText,
@required this.prefixIcon,
@required this.suffixIcon,
@required this.kType,
@required this.kAction,
@required this.validatorFunction,
@required this.onChange,
});

final String hintText;
final String labelText;
final String prefixIcon;
final String suffixIcon;
final TextInputType kType;
final TextInputAction kAction;
final Function validatorFunction;
final Function(String) onChange;

@override
_RCTextFieldState createState() => _RCTextFieldState();
}

class _RCTextFieldState extends State<RCTextField> {
FocusNode myFocusNode;

get validatorFunction => null;
get textFieldValue => null;
get onChange => null;
@override
void initState() {
  super.initState();
  myFocusNode = FocusNode();
  myFocusNode.addListener(_onOnFocusNodeEvent);
}

_onOnFocusNodeEvent() {
  setState(() {
    // Re-renders
  });
}

@override
void dispose() {
  // Clean up the focus node when the Form is disposed.
  myFocusNode.dispose();
  super.dispose();
}

@override
Widget build(BuildContext context) {
  return Container(
    // margin: EdgeInsets.fromLTRB(20, 20, 20, 0),
    child: TextFormField(
    onEditingComplete: () => FocusScope.of(context).nextFocus(),
    textInputAction: widget.kAction,
    cursorColor: Colors.black,
    style: new TextStyle(color: _getInputTextColor()),
    focusNode: myFocusNode,
    validator: validatorFunction,
    decoration: InputDecoration(
      // focusColor: Colors.red,
      // fillColor: Colors.blueGrey,
      enabledBorder: UnderlineInputBorder(
        borderSide: BorderSide(color: kInactiveTextFieldColour),
      ),
      focusedBorder: UnderlineInputBorder(
        borderSide: BorderSide(color: kActiveTextFieldColour),
      ),
      border: UnderlineInputBorder(),
      filled: false,
      prefixIcon: Padding(
        padding: EdgeInsets.all(14.0),
        child: SvgPicture.asset(
          'images/' + widget.prefixIcon + '.svg',
          semanticsLabel: 'Acme Logo',
          color: myFocusNode.hasFocus
              ? kActiveTextFieldColour
              : kInactiveTextFieldColour,
        ),
      ),
      hintText: widget.hintText,
      labelText: widget.labelText,
      labelStyle: TextStyle(
          color: myFocusNode.hasFocus
              ? kActiveTextFieldColour
              : kInactiveTextFieldColour),
    ),
    keyboardType: widget.kType,
    onChanged: widget.onChange,
  ),
);
}

Color _getInputTextColor() {
return myFocusNode.hasFocus ? Colors.black : Colors.black;
}
}

Ниже приведен предпоследний шаг по использованию этого класса.

RCTextField(
            hintText: 'Enter your text',
            labelText: 'Text',
            prefixIcon: 'plus',
            suffixIcon: null,
            kType: TextInputType.visiblePassword,
            kAction: TextInputAction.done,
            onChange: (val) => setState(() {
              print(val);
            }),
          ),

Сообщите мне, если возникнут проблемы.

person shubham    schedule 09.10.2020

заставьте конструктор класса текстового поля принять функцию, затем используйте эту функцию в onChange, как показано ниже:

 @override
  _TextFieldContainer1State createState() => _TextFieldContainer1State();
}

class _TextFieldContainer1State extends State<TextFieldContainer1> {

  final controller1 = TextEditingController();
  final Function onChange;



  @override
  Widget build(BuildContext context) {
    return FractionallySizedBox(
      widthFactor: 0.95,
        child: Container(

          padding: EdgeInsets.symmetric(horizontal:20, vertical:5),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(10)),
            color: tileBackground,
          ),                      
          height: 57,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children:<Widget>[
              Container(
                child:Column(

                  children:<Widget>[
                    Row(

                      children:<Widget>[
                        Icon(widget.icon,
                        color: Colors.white,
                        size:27.5
                        ),
                        SizedBox(width:5),
                        Text(widget.title,
                        style: TextStyle(

                          fontSize: 20,
                          color:Colors.white,
                          fontWeight: FontWeight.w500
                        ),
                        )
                      ]          
                    ),
                    Text(widget.tagLine,
                    style: TextStyle(
                      color:Color.fromRGBO(255, 255, 255, 0.5),
                      fontSize: 12
                    ),
                    )
                  ]
                )
              ),
              Container(
                padding: EdgeInsets.symmetric(horizontal: 15,vertical: 5),
                decoration: BoxDecoration(
                  color: Color.fromRGBO(252, 205, 0, 0.2),
                  borderRadius: BorderRadius.all(Radius.circular(10)
                  )
                ),
                height: 40,
                width: 92,
                child: TextField(
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20
                  ),
                  onChange: widget.onChange,
                  autofocus: false,
                  decoration:InputDecoration( 
                    focusColor: YellowBg,
                    fillColor: YellowBg,
                    hoverColor: YellowBg,
                    enabledBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),
                    ),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: YellowBg),)
                  ) ,
                  keyboardType: TextInputType.number,
                  controller: controller1,


                ),
              )
            ],
          ),

      ),
    );
  }
}

теперь, когда вы используете его в классе калькулятора, вы используете его так:

TextFieldContainer1(
                    title: 'SOLD PRICE',
                    tagLine: "SALE PRICE WITOHUT SHIPPING",
                    icon: Icons.check_circle,
                    onChanga: (value) => print(value);
// now you have access to your text field value inside your calculator class
                  ),

вы также можете сделать свое текстовое поле классом Stateless, поскольку вы нигде не используете setState.

person hewa jalal    schedule 10.05.2020
comment
как обновить текст с родительского виджета / экрана? - person Manoj Perumarath; 22.06.2021
comment
Я не уверен, что вы имеете в виду, пожалуйста, создайте вопрос о переполнении стека. - person hewa jalal; 23.06.2021