Önceki widget'a değer aktarılıyor
Basit bir formum var, içinde CircularAvatar var buna basıldığında galeriden veya kameradan resim çekmek arasında seçim yapmak için ModalBottomSheet'i göster. Widget'ımı daha kompakt hale getirmek için onu bir dosyaya ayırdım.
- FormDosenScreen (Ana ekrandır)
- DosenImagePicker (Yalnızca CircularAvatar)
- ModalBottomSheetPickImage (ModalBottomSheet'i göstermek içindir)
Sorun şu ki, değeri ModalBottomSheetPickImage'dan FormDosenScreen'e nasıl geçireceğimi bilmiyorum . Çünkü ModalBottomSheetPickImage'dan gelen değer, işlemi eklemek için kullanacağım.
Ben sadece üçüncü Widget'tan ikinci Widget'a geçerken başarılı oluyorum, ancak ikinci Widget'tan birinci widget'a tekrar geçerken değer boş ve sorunun İkinci widget'tan birinci widget'a geçtiğini düşünüyorum.
Üçüncü Widget'tan ilk Widget'a nasıl geçebilirim?
İlk Widget
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,
)
],
),
);
}
}
İkinci Widget
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(),
),
),
);
}
}
Üçüncü Widget
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),
),
),
],
),
),
);
}
}
Yanıtlar
Bunu yapmanın en temiz ve en kolay yolu Sağlayıcıdır. Uygulamanın etrafındaki değerleri geçirmek ve yalnızca değişen widget'ları yeniden oluşturmak için kullanabileceğiniz durum yönetimi çözümlerinden biridir. (Örn: Metin widget'ının değeri değiştiğinde). Sağlayıcıyı senaryonuzda nasıl kullanabileceğiniz aşağıda açıklanmıştır:
Modelinizin şöyle görünmesi gerekir:
class ImageModel extends ChangeNotifier {
String _base64Image;
get base64Image => _base64Image;
set base64Image(String base64Image) {
_base64Image = base64Image;
notifyListeners();
}
}
Bağlı olan herhangi bir kullanıcı arayüzünüz varsa notifyListeners () 'ı kullanabilmeniz için alıcılar ve ayarlayıcılar eklemeyi unutmayın.
Kullanıcı arayüzünüzdeki ImageModel değerlerine şu şekilde erişebilirsiniz:
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
Verilerinizi bir Metin Widget'ında nasıl görüntüleyebileceğiniz aşağıda açıklanmıştır (İdeal olarak Tüketici yerine Seçici kullanmanız gerekir, böylece widget yalnızca dinleme değeri değişirse yeniden oluşturulur):
@override
Widget build(BuildContext context) {
//other widgets
Selector<ImageModel, String>(
selector: (_, model) => model.base64Image,
builder: (_, image, __) {
return Text(image);
},
);
}
)
}
Bunu kolayca başarabilirsin. Blocs kullanıyorsanız.