DEV Community

Cover image for Flutter Form Widget ­čĺź ­čîî ÔťĘ
G├╝lsen Keskin
G├╝lsen Keskin

Posted on • Updated on

 

Flutter Form Widget ­čĺź ­čîî ÔťĘ

Form widget'─▒

Form widget'─▒, baz─▒ kullan─▒┼čl─▒ methodlar sa─člayan ve alt a─čac─▒ndaki t├╝m form field widget'lar─▒yla b├╝t├╝nle┼čen bir t├╝r sarmalay─▒c─▒d─▒r.
Formdaki t├╝m field'lar─▒n (alanlar─▒n) state'ini y├Ânetir ve her field i├žin ayr─▒ ayr─▒ state i┼čleme ihtiyac─▒n─▒ ortadan kald─▒r─▒r.

Ayr─▒nt─▒lara fazla dalmadan ├Ânce, ┼čekil 1'deki hava durumu uygulamas─▒ndaki ├╝st d├╝zey ├Ârne─če bir g├Âz at─▒n.

Image description
┼čekil:1

Form ile etkile┼čim kurman─▒n yolu ona FormState t├╝r├╝nde bir anahtar (key) iletmektir. Widget bu global key'i formun state nesnesiyle ili┼čkilendirerek state nesnesine her yerden eri┼čmenizi sa─člar. (Global anahtarlar─▒n kullan─▒lmas─▒n─▒n ├Ânerildi─či tek durum budur. anahtarlar hakk─▒nda daha fazla bilgi i├žin bkz)

T├╝m widget'lar gibi Form da ili┼čkili bir Element taraf─▒ndan y├Ânetilir. Bu elementin, Flutter'da dahili (internally) olarak olu┼čturulan bir FormState nesnesine referans─▒ vard─▒r. Bu state nesnesi, herhangi bir StatefulWidget i├žin olu┼čturulan State s─▒n─▒f─▒n─▒n bir ├Ârne─čidir, ancak daha fazla i┼člevsellik ile geni┼čletilmi┼čtir. Aradaki fark, global key'i olu┼čturdu─čunuzda bu state nesnesinin de dahili olarak olu┼čturulmas─▒d─▒r. Pratikte bu, bu anahtar vas─▒tas─▒yla formunuzun tamam─▒na eri┼čebilece─činiz anlam─▒na gelir.

Formun state'i element tree'ye kaydedilir:
Image description

GlobalKey

Bir form key kullanmak (FormState alt t├╝r├╝n├╝n global anahtar─▒), bir widget'ta controller kullanmaya benzer. ├ľrne─čin, ├Ânceki b├Âl├╝mde TabController'a bakm─▒┼čt─▒k. FormState, form mant─▒─č─▒n─▒ korumak i├žin bir dizi kullan─▒┼čl─▒ method sa─člayan yerle┼čik bir s─▒n─▒ft─▒r. Kullanmak isteyece─činiz FormState methodlar─▒ndan baz─▒lar─▒ FormState.save, FormState.reset ve FormState.validate'dir.

Formlarla ├žal─▒┼č─▒rken, FormState nesnesine ba┼čvuru sa─člayabilen anahtarlar─▒n kullan─▒lmas─▒ yayg─▒nd─▒r. FormState nesnesi ├╝zerindeki t├╝m mant─▒k ve ├Âzelliklere, olu┼čturaca─č─▒n─▒z bu anahtar vas─▒tas─▒yla eri┼čilebilirsiniz. Bu da formunuzda'ki t├╝m widget'larla, ├žocuklar da dahil olmak ├╝zere etkile┼čim kurabilece─činiz anlam─▒na gelir.

Not: Bu, global anahtar kullanman─▒n kabul edilebilir oldu─ču ├žok az yerden biridir. bkz.

import ...

class AddNewCityPage extends StatefulWidget {
  final AppSettings settings;
  const AddNewCityPage({Key key, this.settings}) : super(key: key);

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

class _AddNewCityPageState extends State<AddNewCityPage> {
  City _newCity = City.fromUserInput();
  bool _formChanged = false;
  bool _isDefaultFlag = false;
  FocusNode focusNode;

  final GlobalKey<FormState> _formKey =
    GlobalKey<FormState>(); //formun mevcut durumu i├žin kullan─▒l─▒r

  @override
  void initState() {...}

  @override
  void dispose() {...}

  bool validateTextFields() {...}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(...),
      body: Padding(
        padding: ...
        child: Form(
          key: _formKey,
          onChanged: _onFormChange,
          onWillPop: _onWillPop,
          child: Column(
            children: <Widget>[
              Padding(
                padding: ...
                child: TextFormField(...),
              ),
              Padding(
                padding: ...
                child: TextFormField(...),
              ),
              CountryDropdownField(...),
              FormField(...),
              Divider(...),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  Padding(
                    padding: ...
                    child: FlatButton(...),
                  ),
                  Padding(
                    padding: ...
                    child: RaisedButton(
                      color: Colors.blue[400],
                      child: Text("Submit"),
                      onPressed: _formChanged
                          ? () {
                              if (_formKey.currentState.validate()) {
                                _formKey.currentState.save();
                                _handleAddNewCity();
                                Navigator.pop(context);
                              } else {
                                FocusScope.of(context)
                                    .requestFocus(focusNode);
                              }
                            }
                          : null,
                    ),
                  )
        // ... many more closing brackets
    );
  }
  void _onFormChange() {...}
  void _handleAddNewCity() {...}
  Future<bool> _onWillPop() {
    if (!_formChanged) return Future<bool>.value(true);
    return showDialog<bool>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(...);
  }
}
Enter fullscreen mode Exit fullscreen mode

FormField widget'lar─▒

Formun girdileri y├Ânetebilmesi i├žin FormField widget'lar─▒ gerekir. Herhangi bir input widget, yaln─▒zca text input widget'lar─▒na de─čil, bir form field'─▒na da sar─▒labilir.

├ľrne─čin, formunuzda bir Checkbox kullanabilirsiniz, ancak bunun bir form alan─▒na sar─▒lmas─▒ gerekir:

return FormField(
    child: Checkbox(
        //...
Enter fullscreen mode Exit fullscreen mode

├ť├ž FormField widget'─▒ vard─▒r:

1.) FormField: Herhangi bir input widget'─▒n─▒ bir form field'─▒na d├Ân├╝┼čt├╝rebilen standart aland─▒r.

2.) TextFormField: Text field'─▒ saran ├Âzel bir form alan─▒.

3.) DropdownButtonFormField : DropdownButton ├Â─česini form field'─▒na saran widget

Image description

1.) TextFormField Widget

// weather_app/lib/page/add_city_page.dart -- line ~77
Padding(
  padding: const EdgeInsets.symetric(verical: 8.0),
  child: TextFormField( //TextFormField, TextField ve FormField'in birle┼čimidir ve ayn─▒ arg├╝manlar─▒n ├žo─čunu al─▒r.

    onSaved: (String val) => _newCity.name = val,

    decoration: InputDecoration(
      border: OutlineInputBorder(),
      helperText: "Required",
      labelText: "City name",
  ),
  autofocus: true,

  autoValidate: true,

  validator: (String val) {
    if (val.isEmpty) return "Field cannot be left blank";
    return null;
  },
),


Enter fullscreen mode Exit fullscreen mode

TextFormField'─▒n ├Âzellikleri: validator , autoValidate , onSaved

validator, callback bekleyen t├╝m form field'lar─▒ndaki bir arg├╝mand─▒r. Text form field s├Âz konusu oldu─čunda, callback, bu alan─▒n giri┼činden bir String olarak iletilir. Bu callback'den ne d├Ând├╝r├╝l├╝rse, field'a error text olarak eklenir. Hi├žbir ┼čey veya null d├Ând├╝rmezse, form field herhangi bir error text g├Âstermez. Kullan─▒c─▒n─▒n form field'lar─▒ndaki giri┼čini, form feld'n─▒n t├╝m validator calback'lerini d├Ând├╝ren ve ├ža─č─▒ran FormState.validate() ├Â─česini ├ža─č─▒rarak do─črulars─▒n─▒z.

autoValidate, true olarak ayarland─▒─č─▒nda, form alan─▒ de─či┼čti─činde validator callback'i hemen ├ža─č─▒r─▒r. Bu y├Ântem kullan─▒c─▒ya an─▒nda geri bildirim sa─člar.

onSaved, validator ile ayn─▒ ┼čekilde ├žal─▒┼č─▒r. Callback iletti─činiz bir arg├╝mand─▒r ve bu callback, FormState.save() ├ža─čr─▒ld─▒─č─▒nda y├╝r├╝t├╝l├╝r.

Widget get _titleField {
    // ...
    child: TextFormField(
      onSaved: (String val) => _newCity.name = val,
      decoration: InputDecoration(
     // ...
      autofocus: true,
      autoValidate: true,
      validator: (String val) {
        if (val.isEmpty)
            return "Field cannot be left blank";
        return null;
      },
    ),
  ),
}


Enter fullscreen mode Exit fullscreen mode

2.) DropdownFormButton Widget'─▒

DropdownFormButton, FormField widget'─▒n─▒n ba┼čka bir uzant─▒s─▒d─▒r. G├Âr├╝nt├╝ledi─či veriler ve kullan─▒c─▒n─▒n nas─▒l se├žim yapt─▒─č─▒ d─▒┼č─▒nda, TextFormField gibi ├žal─▒┼č─▒r.

Image description

Widget result = DefaultTextStyle(
       style: _textStyle,
       child: Container(
        // ...
         child: Row(
           mainAxisAlignment: MainAxisAlignment.spaceBetween,
           mainAxisSize: MainAxisSize.min,
           children: <Widget>[
             widget.isExpanded
                ? Expanded(child: innerItemsWidget)
                : innerItemsWidget,
             // ...


Enter fullscreen mode Exit fullscreen mode

isExpanded'─▒ ge├žmenin fark yaratt─▒─č─▒ yer buras─▒d─▒r. Telefonun geni┼čli─či ├žok k├╝├ž├╝kse, ├žocuklar─▒ Expanded'a sarmak ├Ânemlidir, ├ž├╝nk├╝ bu olmadan widget olabildi─čince b├╝y├╝k olmaya ├žal─▒┼č─▒r.

class CountryDropdownField extends StatelessWidget {
  final Function onChanged;
  final Country country;

  const CountryDropdownField({
    Key key,
    this.onChanged,
    this.country,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: DropDownExpanded<Country>(
        isExpanded: true,
        decoration: InputDecoration(
          border: OutlineInputBorder(),
          labelText: "Country",
        ),
        value: country ?? Country.AD, //value dropdown kapat─▒ld─▒─č─▒nda g├Âr├╝nt├╝lenmesi gereken se├žili de─čerdir.

        onChanged: (Country newSelection)
                => onChanged(newSelection), //onChanged, yeni bir se├žim yap─▒ld─▒─č─▒nda ├ža─čr─▒l─▒r. Flutter'─▒n dropdown field widget'lar─▒nda, yeni se├žim onChanged'─▒n callback'ine iletilir.

        items: Country.ALL.map((Country country) { 
          return DropdownMenuItem(
            value: country,
            child: Text(country.name),
          );
        }).toList(),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Generic form fields

Check box, date picker veya slider gibi ba┼čka bir input t├╝r├╝ kullanmak istiyorsan─▒z, herhangi bir witget'─▒ FormField widget'─▒na sarabilirsiniz.

Image description

class _AddNewCityPageState extends State<AddNewCityPage> {
  City _newCity = City.fromUserInput();
  bool _formChanged = false;
  bool _isDefaultFlag = false; //check box'─▒n state'ini y├Ânetmek i├žin kullan─▒lan boolean de─či┼čken
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  FocusNode focusNode;

    Widget build(BuildContext context) {
    return Scaffold(
      FormField(
        onSaved: (val) => _newCity.active =
            _isDefaultFlag,

        builder: (context) { //FormField, bir ├žocuk yerine bir builder al─▒r. ─░stedi─činiz widget'─▒ return edebilirsiniz. Herhangi bir widget teknik olarak bir form field olabilir.

          return Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Text("Default city?"),
              Checkbox(
                value: _isDefaultFlag, //Bu check box, formun d─▒┼č─▒ndaki herhangi bir check box gibi davran─▒r. Se├žili olup olmad─▒─č─▒ bilgisi i├žin boolean bir de─čer al─▒r.
                onChanged: (val) {
                  setState(
                    () => _isDefaultFlag = val //_isDefaultFlag  de─čerini de─či┼čtirmek i├žin setState'i ├ža─č─▒rmal─▒s─▒n─▒z
                  );
                },
              ),
            ],
          );
        },
      ),
  }


Enter fullscreen mode Exit fullscreen mode

Resource: Flutter in Action Chapter: 5

Top comments (0)

An Animated Guide to Node.js Event Loop

>> Check out this classic DEV post <<