이전 위젯에 값 전달

Aug 16 2020

나는 간단한 형태를 가지고 있으며, 내부에 CircularAvatar를 누르면 갤러리 또는 카메라에서 사진을 찍기 위해 ModalBottomSheet를 표시합니다. 내 위젯을 더 컴팩트하게 만들기 위해 일부 파일로 분리했습니다.

  1. FormDosenScreen (메인 화면)
  2. DosenImagePicker (CircularAvatar 전용)
  3. ModalBottomSheetPickImage (ModalBottomSheet을 표시하기위한 것임)

문제는 ModalBottomSheetPickImage 에서 FormDosenScreen 으로 값을 전달하는 방법을 모르겠다 입니다. ModalBottomSheetPickImage의 값은 작업을 삽입하는 데 사용할 것입니다.

세 번째 위젯에서 두 번째 위젯으로 전달하는 데 성공했지만 두 번째 위젯에서 첫 번째 위젯으로 다시 전달하면 값이 null이고 문제가 두 번째 위젯에서 첫 번째 위젯으로 전달되는 것 같습니다.

세 번째 위젯에서 첫 번째 위젯으로 어떻게 전달할 수 있습니까?

첫 번째 위젯

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,
          )
        ],
      ),
    );
  }
}

두 번째 위젯


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(),
        ),
      ),
    );
  }
}

세 번째 위젯


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),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

답변

2 Uni Aug 17 2020 at 04:30

이를 수행하는 가장 깨끗하고 쉬운 방법은 제공자를 이용하는 것입니다. 변경된 위젯 만 다시 빌드하고 앱 주변에 값을 전달하는 데 사용할 수있는 상태 관리 솔루션 중 하나입니다. (예 : 텍스트 위젯의 값이 변경되는 경우). 시나리오에서 Provider를 사용하는 방법은 다음과 같습니다.

모델의 모습은 다음과 같습니다.

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

의존하는 UI가있는 경우 notifyListeners ()를 사용할 수 있도록 getter 및 setter를 추가하는 것을 잊지 마십시오.

UI에서 ImageModel 값에 액세스하는 방법은 다음과 같습니다.

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

다음은 텍스트 위젯에 데이터를 표시하는 방법입니다 (이상적으로, 수신 대기하는 값이 변경되는 경우에만 위젯이 다시 빌드되도록 Consumer 대신 Selector를 사용해야합니다).

@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

이것을 쉽게 달성 할 수 있습니다. 블록을 사용하는 경우.