Chuyển giá trị cho tiện ích con trước đó

Aug 16 2020

Tôi có biểu mẫu đơn giản, bên trong nó có CircularAvatar khi nó được nhấn, hiển thị ModalBottomSheet để chọn giữa chụp ảnh từ thư viện hoặc máy ảnh. Để làm cho tiện ích của tôi nhỏ gọn hơn, tôi đã tách nó thành một số tệp.

  1. FormDosenScreen (Đó là màn hình chính)
  2. DosenImagePicker (Nó chỉ là CircularAvatar)
  3. ModalBottomSheetPickImage (Nó để hiển thị ModalBottomSheet)

Vấn đề là tôi không biết cách chuyển giá trị từ ModalBottomSheetPickImage sang FormDosenScreen . Vì giá trị từ ModalBottomSheetPickImage tôi sẽ sử dụng để chèn hoạt động.

Tôi chỉ chuyển thành công từ Widget thứ ba sang Widget thứ hai, nhưng khi tôi chuyển lại từ Widget thứ hai sang widget thứ nhất thì giá trị là null và tôi nghĩ vấn đề đang chuyển từ widget thứ hai sang widget đầu tiên.

Làm cách nào tôi có thể chuyển từ Widget thứ ba sang Widget đầu tiên?

Tiện ích con đầu tiên

class FormDosenScreen extends StatefulWidget {
  static const routeNamed = '/formdosen-screen';

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

class _FormDosenScreenState extends State<FormDosenScreen> {
  String selectedFile;
  @override
  Widget build(BuildContext context) {
    final detectKeyboardOpen = MediaQuery.of(context).viewInsets.bottom;
    print('trigger');
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('Tambah Dosen'),
        actions: <Widget>[
          PopupMenuButton(
            itemBuilder: (_) => [
              PopupMenuItem(
                child: Text('Tambah Pelajaran'),
                value: 'add_pelajaran',
              ),
            ],
            onSelected: (String value) {
              switch (value) {
                case 'add_pelajaran':
                  Navigator.of(context).pushNamed(FormPelajaranScreen.routeNamed);
                  break;
                default:
              }
            },
          )
        ],
      ),
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                SizedBox(height: 20),
                DosenImagePicker(onPickedImage: (file) => selectedFile = file),
                SizedBox(height: 20),
                Card(
                  margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
                  child: Padding(
                    padding: const EdgeInsets.all(20),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: <Widget>[
                        TextFormFieldCustom(
                          onSaved: (value) {},
                          labelText: 'Nama Dosen',
                        ),
                        SizedBox(height: 20),
                        TextFormFieldCustom(
                          onSaved: (value) {},
                          prefixIcon: Icon(Icons.email),
                          labelText: 'Email Dosen',
                          keyboardType: TextInputType.emailAddress,
                        ),
                        SizedBox(height: 20),
                        TextFormFieldCustom(
                          onSaved: (value) {},
                          keyboardType: TextInputType.number,
                          inputFormatter: [
                            // InputNumberFormat(),
                            WhitelistingTextInputFormatter.digitsOnly
                          ],
                          prefixIcon: Icon(Icons.local_phone),
                          labelText: 'Telepon Dosen',
                        ),
                      ],
                    ),
                  ),
                ),
                SizedBox(height: kToolbarHeight),
              ],
            ),
          ),
          Positioned(
            child: Visibility(
              visible: detectKeyboardOpen > 0 ? false : true,
              child: RaisedButton(
                onPressed: () {
                  print(selectedFile);
                },
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                color: colorPallete.primaryColor,
                child: Text(
                  'SIMPAN',
                  style: TextStyle(fontWeight: FontWeight.bold, fontFamily: AppConfig.headerFont),
                ),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
                textTheme: ButtonTextTheme.primary,
              ),
            ),
            bottom: kToolbarHeight / 2,
            left: sizes.width(context) / 15,
            right: sizes.width(context) / 15,
          )
        ],
      ),
    );
  }
}

Widget thứ hai


class DosenImagePicker extends StatefulWidget {
  final Function(String file) onPickedImage;
  DosenImagePicker({@required this.onPickedImage});
  @override
  DosenImagePickerState createState() => DosenImagePickerState();
}

class DosenImagePickerState extends State<DosenImagePicker> {
  String selectedImage;
  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: Alignment.center,
      child: InkWell(
        onTap: () async {
          await showModalBottomSheet(
            context: context,
            builder: (context) => ModalBottomSheetPickImage(
              onPickedImage: (file) {
                setState(() {
                  selectedImage = file;
                  widget.onPickedImage(selectedImage);
                  print('Hellooo dosen image picker $selectedImage');
                });
              },
            ),
          );
        },
        child: CircleAvatar(
          foregroundColor: colorPallete.black,
          backgroundImage: selectedImage == null ? null : MemoryImage(base64.decode(selectedImage)),
          radius: sizes.width(context) / 6,
          backgroundColor: colorPallete.accentColor,
          child: selectedImage == null ? Text('Pilih Gambar') : SizedBox(),
        ),
      ),
    );
  }
}

Widget thứ ba


class ModalBottomSheetPickImage extends StatelessWidget {
  final Function(String file) onPickedImage;

  ModalBottomSheetPickImage({@required this.onPickedImage});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      child: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Wrap(
          alignment: WrapAlignment.spaceEvenly,
          children: <Widget>[
            InkWell(
              onTap: () async {
                final String resultBase64 =
                    await commonFunction.pickImage(quality: 80, returnFile: ReturnFile.BASE64);
                onPickedImage(resultBase64);
              },
              child: CircleAvatar(
                foregroundColor: colorPallete.white,
                backgroundColor: colorPallete.green,
                child: Icon(Icons.camera_alt),
              ),
            ),
            InkWell(
              onTap: () async {
                final String resultBase64 =
                    await commonFunction.pickImage(returnFile: ReturnFile.BASE64, isCamera: false);
                onPickedImage(resultBase64);
              },
              child: CircleAvatar(
                foregroundColor: colorPallete.white,
                backgroundColor: colorPallete.blue,
                child: Icon(Icons.photo_library),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Trả lời

2 Uni Aug 17 2020 at 04:30

Cách sạch nhất và dễ nhất để làm điều này là thông qua Nhà cung cấp. Đây là một trong những giải pháp quản lý nhà nước mà bạn có thể sử dụng để chuyển các giá trị xung quanh ứng dụng cũng như chỉ xây dựng lại các widget đã thay đổi. (Ví dụ: Khi giá trị của tiện ích Văn bản thay đổi). Đây là cách bạn có thể sử dụng Nhà cung cấp trong trường hợp của mình:

Đây là cách mô hình của bạn sẽ trông như thế nào:

class ImageModel extends ChangeNotifier {
  String _base64Image;
  get base64Image => _base64Image;
  set base64Image(String base64Image) {
    _base64Image = base64Image;
    notifyListeners();
  }
}

Đừng quên thêm getters và setters để bạn có thể sử dụng InformListists () nếu bạn có bất kỳ ui nào phụ thuộc vào nó.

Đây là cách bạn có thể truy cập các giá trị của ImageModel trong giao diện người dùng của mình:

final model=Provider.of<ImageModel>(context,listen:false);
String image=model.base64Image; //get data
model.base64Image=resultBase64; //set your image data after you used ImagePicker

Đây là cách bạn có thể hiển thị dữ liệu của mình trong Tiện ích văn bản (Tốt nhất, bạn nên sử dụng Bộ chọn thay vì Người tiêu dùng để tiện ích chỉ xây dựng lại nếu giá trị của nó thay đổi):

@override
Widget build(BuildContext context) {
 //other widgets
 Selector<ImageModel, String>(
  selector: (_, model) => model.base64Image,
  builder: (_, image, __) {
   return Text(image);
     },
   );
  }
 )
}
VasilKanev Aug 17 2020 at 09:45

Bạn có thể đạt được điều này một cách dễ dàng. Nếu bạn đang sử dụng Blocs.