Как заполнить форму из списка при нажатии на флаттер - PullRequest
0 голосов
/ 19 июня 2019

У меня есть виджет формы, виджет списка и виджет «обертка» или, другими словами, виджет родителя / контейнера.Таким образом, чтобы дать представление о дереве виджетов, оно таково.

  • Родитель / Виджет контейнера
    • Виджет формы
    • Виджет кнопки
    • Виджет списка

Обратите внимание, что форма, кнопки и виджет списка - все одноуровневые элементы внутри виджета родитель / контейнер.То, что я хочу, это нажать на элемент списка в виджете списка и заполнить виджет формы данными, которые передаются из виджета списка.

Вот мой родительский виджет.

import 'package:andplus_flutter_7_gui/model/user.dart';
import 'package:andplus_flutter_7_gui/services/user_service.dart';
import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'crud_form.dart';
import 'crud_list.dart';

class Crud extends StatefulWidget {
  Crud({Key key, this.title}) : super(key: key);

  final String title;

  _CrudContainerState createState() => _CrudContainerState();
}

class _CrudContainerState extends State<Crud> {
  List<User> users;
  User user = User();
  UserService userService;

  @override
  void initState() {
    super.initState();
    if (userService == null) {
      userService = UserService(user);
    }
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    userService.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Scaffold(
        resizeToAvoidBottomPadding: false,
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Builder(
          builder: (context) => Column(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Expanded(
                    flex: 2,
                    child: StreamBuilder(
                      builder: (context, AsyncSnapshot<User> snapshot) {
                        return CrudForm(
                          user: snapshot.data,
                          onUserAdded: (user) {
                            userService.addUser(user);
                          },
                        );
                      },
                      stream: userService.userObservable,
                    ),
                  ),
                  Expanded(
                    child: Text("Future button widget"),
                  ),
                  Expanded(
                    flex: 3,
                    child: StreamBuilder(
                      builder: (ctx, AsyncSnapshot<List<User>> snap) {
                        return CrudList(
                          onUserSelected: userService.userSelected,
                          users: snap.data,
                        );
                      },
                      stream: userService.usersObservable,
                    ),
                  ),
                ],
              ),
        ),
      ),
    );
  }

  void onEditUser(User user) {
    setState(() {
      user = user;
    });
  }
}

Приведенный выше виджет объединяет три упомянутых мною виджета.

Вот дочерний виджет:

Форма:

import 'package:andplus_flutter_7_gui/model/user.dart';
import 'package:flutter/material.dart';

class CrudForm extends StatefulWidget {
  CrudForm({Key key, this.onUserAdded, this.user}) : super(key: key);

  final User user;
  final void Function(User user) onUserAdded;

  _CrudFormState createState() => _CrudFormState(user: user);
}

class _CrudFormState extends State<CrudForm> {
  _CrudFormState({this.user});

  User user = User();
  var _key = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Builder(
        builder: (context) => Container(
              color: Colors.blueAccent[100],
              child: Form(
                key: _key,
                child: Padding(
                  padding: const EdgeInsets.only(left: 8.0),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: <Widget>[
                      Row(
                        children: <Widget>[
                          Text(
                            "First Name",
                            style: TextStyle(fontSize: 20),
                          ),
                          Expanded(
                            child: Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: TextFormField(
                                initialValue: widget.user?.firstName == null ||
                                        widget.user.firstName.isEmpty
                                    ? user.firstName
                                    : widget.user.firstName,
                                validator: (value) {
                                  if (value.isEmpty) {
                                    return "First name is required";
                                  }

                                  return null;
                                },
                                onSaved: (value) {
                                  setState(() {
                                    user.firstName = value;
                                  });
                                },
                              ),
                            ),
                          )
                        ],
                      ),
                      Row(
                        children: <Widget>[
                          Text(
                            "Last Name",
                            style: TextStyle(fontSize: 20),
                          ),
                          Expanded(
                            child: Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: TextFormField(
                                validator: (value) {
                                  if (value.isEmpty) {
                                    return "Last name is required";
                                  }

                                  return null;
                                },
                                onSaved: (value) {
                                  setState(() {
                                    user.lastName = value;
                                  });
                                },
                              ),
                            ),
                          ),
                        ],
                      ),
                      RaisedButton(
                        child: Text(
                          "Save",
                        ),
                        splashColor: Colors.blueGrey,
                        onPressed: () {
                          if (!_key.currentState.validate()) {
                            return;
                          }
                          _key.currentState.save();
                          widget.onUserAdded(
                            new User(
                              firstName: user.firstName,
                              lastName: user.lastName,
                            ),
                          );
                        },
                      )
                    ],
                  ),
                ),
              ),
            ),
      ),
    );
  }
}

Вот мой виджет списка.

import 'package:andplus_flutter_7_gui/model/user.dart';
import 'package:flutter/material.dart';

class CrudList extends StatefulWidget {
  CrudList({Key key, this.users, this.onUserSelected}) : super(key: key);

  final List<User> users;

  final SelectUser onUserSelected;

  _CrudListState createState() => _CrudListState();
}

class _CrudListState extends State<CrudList> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      child: ListView.builder(
        itemCount: widget.users?.length ?? 0,
        itemBuilder: (BuildContext context, int index) {
          var user = widget.users[index];
          return ListTile(
            key: Key(index.toString()),
            title: Center(
              child: Text(
                "${user.firstName} ${user.lastName}",
                style: TextStyle(color: Colors.white),
              ),
            ),
            onTap: () {
              print("${widget.users[index]} $index");
              widget.onUserSelected(widget.users[index]);
            },
          );
        },
      ),
    );
  }
}

typedef void SelectUser(User user);

И просто для дальнейшего контекста, вот мой пользовательский сервис, отвечающий за добавление объектов в поток и использование построителя потока в rxdart для уведомления об изменениях состояния.

import 'package:andplus_flutter_7_gui/model/user.dart';
import 'package:rxdart/rxdart.dart';

class UserService {
  User _editedUser = User();
  List<User> _users = <User>[];
  BehaviorSubject<User> _userSubject;
  BehaviorSubject<List<User>> _usersSubject;

  UserService(this._editedUser) {
    _userSubject = BehaviorSubject<User>.seeded(_editedUser);
    _usersSubject = BehaviorSubject<List<User>>.seeded(_users);
  }

  Observable<List<User>> get usersObservable => _usersSubject.stream;
  Observable<User> get userObservable => _userSubject.stream;

  addUser(User user) {
    _users.add(user);
    _usersSubject.add(_users);
  }

  dispose() {
    _userSubject.close();
    _usersSubject.close();
  }

  void userSelected(User user) {
    _editedUser = user;
    _userSubject.add(_editedUser);
  }
}

Чего мне не хватает?Похоже, мой виджет перестраивается и пытается установить начальное значение в форме, когда я нажимаю на пользователя в виджете списка.Но фактическое поле не обновляется, и я не уверен, почему.

Буду признателен за любую документацию или статьи о том, как лучше подходить к управлению данными и состояниями между родственными виджетами в рамках флаттера.

...