Flutter-Widgets: Unterschied zwischen den Versionen

Aus Info-Theke
Zur Navigation springen Zur Suche springen
(Die Seite wurde neu angelegt: „= Links = * Flutter = Häufige Widgets = == Column / Row == Ein Container, in dem die Unterelemente senkrecht (Column) oder waagrecht (Row) angeordnet wer…“)
 
 
(7 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 8: Zeile 8:
<pre>
<pre>
List<Widget> = [
List<Widget> = [
   Col( children = [
   Col(  
    Row( children: [
    crossAxisAlignment: CrossAxisAlignment.start,
      Expanded(
    children = [
        child: const Text('Be surprised!'),
      Row( children: [
      ),
        Expanded(
      const SizedBox(width: 16),
          child: const Text('Be surprised!'),
      ElevatedButton(
        ),
        child: Text('Click it'),
        const SizedBox(width: 16),
        onPressed: () => sayHello(),
        ElevatedButton(
      ),
          child: Text('Click it'),
      ]),
          onPressed: () => sayHello(),
    const SizedBox(height: 16),
        ),
    Row( children: [
        ]),
      const Expanded (flex: 7,  
      const SizedBox(height: 16),
        child: Text('You need help?'),
      Row( children: [
        const Expanded (flex: 7,  
          child: Text('You need help?'),
       ),
       ),
      const SizedBox(height: padding),
        const SizedBox(height: padding),
      const Expanded (flex: 2,
        const Expanded (flex: 2,
        child: ElevatedButton(
          child: ElevatedButton(
          child: Text('Help me'),
            child: Text('Help me'),
          onPressed: () => help(),
            onPressed: () => help(),
          ),  
         ),
         ),
      ),
       ]),
       ]),
  ]),
    ]),
];
];
</pre>
</pre>


=== Platzverteilung ===
=== Platzverteilung ===
Normalerweise bestimmen die Unterelemente (children) die Dimensionen, sie werden einfach untereinander / hintereinander positioniert.
Normalerweise bestimmen die Unterelemente (<code>children</code>) die Dimensionen, sie werden einfach untereinander / hintereinander positioniert.


Will man eine '''automatische Anpassung''', werden die "dynamischen" Elemente jeweils in ein '''Expanded'''-Element eingebettet.
Will man eine '''automatische Anpassung''', werden die "dynamischen" Elemente jeweils in ein '''Expanded'''-Element eingebettet.
In diesem Fall wird der Restplatz an alle dynamischen Elemente gleichmäßig verteilt. Mit dem Parameter '''flex'' von Expanded kann das Verhältnis eingestellt werden.
In diesem Fall wird der Restplatz an alle dynamischen Elemente gleichmäßig verteilt. Mit dem Parameter <code>flex</code> von Expanded kann das Verhältnis eingestellt werden.


= Formular =
= Card =
<pre>
final widget = Card(
  margin: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
  child: Padding(
    padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
    child: Text('Wow!'),
  ),
);
</pre>
 
= Abwandlungen =
== Visibility ==
Damit kann die Sichtbarkeit eines Elements gesteuert werden. Ganz wichtig für GetX-Layouts!
 
Im folgenden Beispiel wird entweder das eine oder das andere Element angezeigt.
<pre>
final widgets = <Widget>[
  Visibility(
    visible: controller.isEmpty.value,
    child: buildEmptyImage()
  ),
  Visibility(
    visible: !controller.isEmpty.value,
    child: buildImage()
  ),
];
</pre>
 
== Tooltip ==
Dieses Element erzeugt einen Erklärungstext, der erscheint, wenn die Maus kurz auf dem Kindelement verweilt.
<pre>
final widget = Tooltip(
  message: 'Löschen',
  child: Icon(Icons.delete_forever_outlined)
);
</pre>
 
== Inkwell (Reaktionsfläche) ==
Mit diesem Element ist es möglich, eine Aktion zu definieren, wenn das Kindelement berührt/angeklickt wird.
<pre>
final Widget = Material(
  color: Colors.green,
  child: InkWell(
    onTap: () async { Get.toNamed(Routes.routeAction); }
    child: SizedBox(width: 200, height: 200, child: image.value,),
    ),
);
</pre>
 
= Formular (Text und Dropdown) =
Jedes Formular benötigt einen '''Key''', der normalerweise im Controller erzeugt/gespeichert wird:
Jedes Formular benötigt einen '''Key''', der normalerweise im Controller erzeugt/gespeichert wird:


Zeile 56: Zeile 108:


<pre>
<pre>
final items = [
  DropdownMenuItem<bool>(value: false, child: Text('inaktive)),
  DropdownMenuItem<bool>(value: true, child: Text('active))
];
final form = Form(
final form = Form(
   key: controller.formKey,
   key: controller.formKey,
Zeile 61: Zeile 117:
     children: [
     children: [
       TextFormField(
       TextFormField(
        decoration: InputDecoration(labelText: 'Age'),
         validator: checkInt,
         validator: checkInt,
         onSaved: (input) => controller.controllerData = input,
         onSaved: (input) => controller.age.value = input,
         controller: ,
         controller: controller.controllerAge,
      ),
      DropdownButtonFormField<bool>(
        value: fieldData.locationId,
        items: items,
        isExpanded: true,
        decoration: const InputDecoration(labelText: 'Status'),
        onSaved: (value) => controller.status.value = value,
       ),
       ),
   ]),
   ]),
Zeile 70: Zeile 134:


void store(controller, String input){
void store(controller, String input){
    if (controller, formKey.currentState?.validate() ?? false) {
  if (controller, formKey.currentState?.validate() ?? false) {
      controller.formKey.currentState?.save();
    controller.formKey.currentState?.save();
    }
  }
}
}
</pre>
= DropDownButton (Combobox) =
<pre>
<pre>
final items1 = [
  DropdownMenuItem(child: Image.asset('img/undefined.png'), value: ''),
  DropdownMenuItem(child: Text('Active'), value: 'A'),
  DropdownMenuItem(child: Text('Inactive'), value: 'I'),
];
final button1 = DropdownButton<String>(
  value: '',
  items: items1,
  onChanged: (value) {
    controller.active = value
  },
);
final item2 = List<int>generate(5, (i) => i+1).map((no) => DropdownMenuItem(child: Text('Element $no'), value: no));
final button2 = DropdownButton<int>(
  value: 0,
  items: items2,
  onChanged: (value) {
    controller.no = value
  },
);
</pre>
== DropDownField ==
<pre>
import 'package:dropdown_textfield/dropdown_textfield.dart';
...
final widget =  DropDownTextField(
  // initialValue: "name4",
  controller: controller.nameController,
  clearOption: false,
  enableSearch: true,
  searchDecoration: const InputDecoration(hintText: "Type part of the name"),
  validator: (value) value != null ? null : "Required field",
  dropDownItemCount: 6,
  dropDownList: const [
    DropDownValueModel(name: 'name1', value: "value1"),
    DropDownValueModel(name: 'name2', value: "value2", toolTipMsg: "Select an item from the list"),
DropDownValueModel(name: 'name3', value: "value3"),
DropDownValueModel(name: 'name4', value: "value4", toolTipMsg: "This is value4",
  ],
  onChanged: (val) { controller.selectedName = val; },
);
</pre>


= Rückgabe der GetView.build() Methode =
= Rückgabe der GetView.build() Methode =

Aktuelle Version vom 27. September 2022, 07:06 Uhr

Links[Bearbeiten]

Häufige Widgets[Bearbeiten]

Column / Row[Bearbeiten]

Ein Container, in dem die Unterelemente senkrecht (Column) oder waagrecht (Row) angeordnet werden. Die Unterelemente bestimmen

List<Widget> = [
  Col( 
    crossAxisAlignment: CrossAxisAlignment.start,
    children = [
      Row( children: [
        Expanded(
          child: const Text('Be surprised!'),
        ),
        const SizedBox(width: 16),
        ElevatedButton(
          child: Text('Click it'),
          onPressed: () => sayHello(),
        ),
        ]),
      const SizedBox(height: 16),
      Row( children: [
        const Expanded (flex: 7, 
          child: Text('You need help?'),
      ),
        const SizedBox(height: padding),
        const Expanded (flex: 2,
          child: ElevatedButton(
            child: Text('Help me'),
            onPressed: () => help(),
          ), 
        ),
      ]),
    ]),
];

Platzverteilung[Bearbeiten]

Normalerweise bestimmen die Unterelemente (children) die Dimensionen, sie werden einfach untereinander / hintereinander positioniert.

Will man eine automatische Anpassung, werden die "dynamischen" Elemente jeweils in ein Expanded-Element eingebettet. In diesem Fall wird der Restplatz an alle dynamischen Elemente gleichmäßig verteilt. Mit dem Parameter flex von Expanded kann das Verhältnis eingestellt werden.

Card[Bearbeiten]

final widget = Card(
  margin: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
  child: Padding(
    padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 16.0),
    child: Text('Wow!'),
  ),
);

Abwandlungen[Bearbeiten]

Visibility[Bearbeiten]

Damit kann die Sichtbarkeit eines Elements gesteuert werden. Ganz wichtig für GetX-Layouts!

Im folgenden Beispiel wird entweder das eine oder das andere Element angezeigt.

final widgets = <Widget>[
  Visibility(
    visible: controller.isEmpty.value,
    child: buildEmptyImage()
  ),
  Visibility(
    visible: !controller.isEmpty.value,
    child: buildImage()
  ),
];

Tooltip[Bearbeiten]

Dieses Element erzeugt einen Erklärungstext, der erscheint, wenn die Maus kurz auf dem Kindelement verweilt.

final widget = Tooltip(
  message: 'Löschen',
  child: Icon(Icons.delete_forever_outlined)
);

Inkwell (Reaktionsfläche)[Bearbeiten]

Mit diesem Element ist es möglich, eine Aktion zu definieren, wenn das Kindelement berührt/angeklickt wird.

final Widget = Material(
  color: Colors.green,
  child: InkWell(
    onTap: () async { Get.toNamed(Routes.routeAction); }
    child: SizedBox(width: 200, height: 200, child: image.value,),
    ),
);

Formular (Text und Dropdown)[Bearbeiten]

Jedes Formular benötigt einen Key, der normalerweise im Controller erzeugt/gespeichert wird:

key = GlobalKey<FormState>(debugLabel: 'MyForm');

Ein Formular bietet die Möglichkeit der Eingabeprüfung (Validierung).

  • Dazu wird für jedes Formularfeld eine (eventuell anonyme) Funktion angegeben, die im Fehlerfall einen Fehlertext zurückgibt, sonst null.
  • Außerdem hat das Formularfeld einen Parameter onSave, der eine Funktion entgegennimmt, die das Speichern des Wertes übernimmt.
  • Die Validierung wird normalerweise beim Anklicken eines Buttons angestoßen: Alle Textfelder werden validiert.
  • Ist die Validierung erfolgreich, wird formKey.currentKey.store() aufgerufen.
  • Dies löst bei allen Textfeldern den Aufruf der Parameterfunktion onSave auf.
final items = [
  DropdownMenuItem<bool>(value: false, child: Text('inaktive)),
  DropdownMenuItem<bool>(value: true, child: Text('active))
];
final form = Form(
  key: controller.formKey,
  child: Column(
    children: [
      TextFormField(
        decoration: InputDecoration(labelText: 'Age'),
        validator: checkInt,
        onSaved: (input) => controller.age.value = input,
        controller: controller.controllerAge,
      ),
      DropdownButtonFormField<bool>(
        value: fieldData.locationId,
        items: items,
        isExpanded: true,
        decoration: const InputDecoration(labelText: 'Status'),
        onSaved: (value) => controller.status.value = value,
      ),
  ]),
);
String? checkInt(String input) int.parseInt(input) == null ? 'Not an integer' : null;

void store(controller, String input){
  if (controller, formKey.currentState?.validate() ?? false) {
    controller.formKey.currentState?.save();
  }
}

DropDownButton (Combobox)[Bearbeiten]

final items1 = [
  DropdownMenuItem(child: Image.asset('img/undefined.png'), value: ''),
  DropdownMenuItem(child: Text('Active'), value: 'A'),
  DropdownMenuItem(child: Text('Inactive'), value: 'I'),
];
final button1 = DropdownButton<String>(
  value: '',
  items: items1,
  onChanged: (value) {
    controller.active = value
  },
);
final item2 = List<int>generate(5, (i) => i+1).map((no) => DropdownMenuItem(child: Text('Element $no'), value: no));
final button2 = DropdownButton<int>(
  value: 0,
  items: items2,
  onChanged: (value) {
    controller.no = value
  },
);

DropDownField[Bearbeiten]

import 'package:dropdown_textfield/dropdown_textfield.dart';
...
final widget =  DropDownTextField(
  // initialValue: "name4",
  controller: controller.nameController,
  clearOption: false,
  enableSearch: true,
  searchDecoration: const InputDecoration(hintText: "Type part of the name"),
  validator: (value) value != null ? null : "Required field",
  dropDownItemCount: 6,
  dropDownList: const [
    DropDownValueModel(name: 'name1', value: "value1"),
    DropDownValueModel(name: 'name2', value: "value2", toolTipMsg: "Select an item from the list"),
	DropDownValueModel(name: 'name3', value: "value3"),
	DropDownValueModel(name: 'name4', value: "value4", toolTipMsg: "This is value4",
  ],
  onChanged: (val) { controller.selectedName = val; },
);

Rückgabe der GetView.build() Methode[Bearbeiten]

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: controller.applicationData.appBarBuilder('Demo'),
        drawer: controller.applicationData.drawerBuilder(context),
        body: Text('Hello world!'),
  }

Grundgerüst einer GUI-App[Bearbeiten]

void main() {
  globalLogger = GetxLogger();
  ApplicationData.createDummy();
  runApp(
    GetMaterialApp(
      title: "MyApp",
      initialRoute: AppPages.initialRoute,
      getPages: AppPages.routes,
    ),
  );
}