Flutter FutureBuilder, StreamBuilder, Form vs.
Videolu anlatım: https://youtu.be/H8cyZtzkSY4

//pubspec.yaml
name: futurestreambuilderornek
description: A new Flutter project.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
signal: ^0.2.2+1
validators: ^2.0.1
regexed_validator: ^1.0.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
//mxVopForm.dart
import 'package:flutter/material.dart';
mixin MxVopForm {
String mxValidator(bool isValidate, String errorText) =>
isValidate ? null : errorText;
String mxOnSaved(String value) => value.trim();
mxSaveForm(GlobalKey<FormState> formKey, Function() onSavedForm) {
if (formKey?.currentState?.validate() ?? false) {
formKey?.currentState?.save();
onSavedForm?.call();
}
}
}
//mxVopValidators.dart
import 'package:regexed_validator/regexed_validator.dart';
import 'package:validators/validators.dart';
mixin MxVopIsEmail {
bool mxIsEmail(dynamic value) {
try {
return isEmail(value.trim());
} catch (e) {
return false;
}
}
}
mixin MxVopIsLength {
bool mxIsLength(dynamic value, int min, [int max]) {
try {
return isLength(value.trim(), min, max);
} catch (e) {
return false;
}
}
}
mixin MxVopIsPhone {
bool mxIsPhone(dynamic value) {
try {
return validator.phone(value.trim());
} catch (e) {
return false;
}
}
}
mixin MxVopIsUrl {
bool mxIsUrl(dynamic url) {
if(url == null) return false;
try {
return isURL(url.trim());
} catch (e) {
return false;
}
}
}
mixin MxVopIsEquals {
bool mxIsEquals(String str, dynamic comparison) {
try {
return equals(str.trim(),comparison.trim());
} catch (e) {
return false;
}
}
}
//RandomGenerate.dart
import 'dart:math';
import 'dart:ui';
class RandomGenerate {
static int getInt(int minValue, int maxValue) => Random().nextInt((maxValue - minValue).abs() + 1) + min(minValue, maxValue);
static bool getBool() => Random().nextBool();
static int getHex() => getInt(0xFF0587D8, 0xFF0345B5);
static Color getColor() => Color(getHex());
static String getTitle() => capitalize(nouns[Random().nextInt(nouns.length)]);
static String capitalize(String s) => s[0].toUpperCase() + s.substring(1);
}
const List<String> nouns = [
'time',
'year',
'people',
'way',
'day',
'man',
'thing',
'woman',
'life',
'child',
'world',
'school',
'state',
'family',
'student',
'group',
'country',
'problem',
'hand',
'part',
'place',
'case',
'week',
'company',
'system',
'program',
'question',
'work',
'government',
'number',
'night',
'point',
'home',
'water',
'room',
'mother',
'area',
'money',
'story',
'fact',
'month',
'lot',
'right',
'study',
'book',
'eye',
'job',
'word',
'business',
'issue',
'side',
'kind',
'head',
'house',
'service',
'friend',
'father',
'power',
'hour',
'game',
'line',
'end',
'member',
'law',
'car',
'city',
'community',
'name',
'president',
'team',
'minute',
'idea',
'kid',
'body',
'information',
'back',
'parent',
'face',
'others',
'level',
'office',
'door',
'health',
'person',
'art',
'war',
'history',
'party',
'result',
'change',
'morning',
'reason',
'research',
'girl',
'guy',
'food',
'moment',
'air',
'teacher',
'force',
'education',
'foot',
'boy',
'age',
'policy',
'process',
'music',
'market',
'sense',
'nation',
'plan',
'college',
'interest',
'death',
'experience',
'effect',
'use',
'class',
'control',
'care',
'field',
'development',
'role',
'effort',
'rate',
'heart',
'drug',
'show',
'leader',
'light',
'voice',
'wife',
'police',
'mind',
'price',
'report',
'decision',
'son',
'view',
'relationship',
'town',
'road',
'arm',
'difference',
'value',
'building',
'action',
'model',
'season',
'society',
'tax',
'director',
'position',
'player',
'record',
'paper',
'space',
'ground',
'form',
'event',
'official',
'matter',
'center',
'couple',
'site',
'project',
'activity',
'star',
'table',
'need',
'court',
'American',
'oil',
'situation',
'cost',
'industry',
'figure',
'street',
'image',
'phone',
'data',
'picture',
'practice',
'piece',
'land',
'product',
'doctor',
'wall',
'patient',
'worker',
'news',
'test',
'movie',
'north',
'love',
'support'
];
//stWsChangeable.dart
import 'dart:async';
import 'package:signal/signal.dart';
class StWsChangeable extends BaseState {
StWsChangeable(void Function() onStateChanged) : super(onStateChanged);
String _formText;
String _text;
bool _showForm;
String get text => _text;
bool get showForm => _showForm;
String get formText => _formText;
@override
void initState({String nText, bool nshowForm = false}) {
_showForm = nshowForm;
_text = nText;
}
setShowForm(bool value) {
_showForm = value;
doneSucces();
}
Future<String> initFuture() async => await Future.delayed(
Duration(seconds: 2), () => 'İlk future değer geldi');
String onSaved(String value) => _formText = value.trim();
Future<void> onSavedForm(
{FutureOr<void> Function(String value) onSaved,
void Function(String value) onDoneSuccess}) async {
try {
wait();
await Future.value(onSaved(formText));
_showForm = false;
_text = formText;
doneSucces();
onDoneSuccess?.call(text);
} catch (e) {
_showForm = true;
doneError(e.toString());
}
}
@override
Future<void> afterInitState({Future<String> Function() future}) async {
try {
var tempText = await future?.call();
if (tempText != null) _text = tempText;
doneSucces();
} catch (e) {
doneError(e.toString());
}
}
@override
void dispose() {
// TODO: implement dispose
}
}
//wsChangeableText.dart
import 'package:flutter/material.dart';
import 'stWsChangeable.dart';
class WsChangeableText extends StatefulWidget {
const WsChangeableText({
Key key,
this.future,
this.text,
this.icon,
@required this.labelText,
@required this.onValidator,
@required this.onSavedForm,
this.onDoneSuccess,
this.keyboardType,
}) : assert(labelText != null),
assert(onValidator != null),
assert(onSavedForm != null),
super(key: key);
final Future<String> Function() future;
final String text;
final Widget icon;
final String labelText;
final String Function(String value) onValidator;
final void Function(String value) onSavedForm;
final void Function(String value) onDoneSuccess;
final TextInputType keyboardType;
@override
_WsChangeableTextState createState() => _WsChangeableTextState();
}
class _WsChangeableTextState extends State<WsChangeableText> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
StWsChangeable _state;
StWsChangeable get state => _state;
@override
void initState() {
super.initState();
_state = StWsChangeable(() {
if (mounted) {
setState(() {});
}
})
..initState(nText: widget.text);
if (widget.future != null){
state.wait(signal:false);
state.afterInitState(future: widget.future);
}
}
@override
void didUpdateWidget(WsChangeableText oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.text != widget.text) {
_state.initState(nText: widget.text);
_state.doneSucces(signal: false);
}
}
@override
Widget build(BuildContext context) {
return Center(
child: !state.showForm
? state.busy
? CircularProgressIndicator(strokeWidth: 2)
: !state.success
? Text('Hata : ${state.error} ')
: ListTile(
leading: widget.icon ??
SizedBox(
width: 0,
height: 0,
),
title: Text(state.text ?? ''),
onTap: () => state.setShowForm(true),
)
: Stack(alignment: Alignment.center, children: [
AbsorbPointer(
absorbing: state.busy,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: Form(
key: _formKey,
child: TextFormField(
enabled: !state.busy,
autofocus: true,
keyboardType:
widget.keyboardType ?? TextInputType.text,
decoration: InputDecoration(
border: const OutlineInputBorder(),
icon: widget.icon ??
SizedBox(
width: 0,
height: 0,
),
labelText: widget.labelText),
validator: (value) => widget.onValidator(value),
onSaved: (value) => state.onSaved(value),
),
),
),
SizedBox(
width: 10,
),
Expanded(
child: RaisedButton(
child: Text(
"Ok",
style: TextStyle(
color: Colors.lightBlue, fontSize: 15),
),
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
state.onSavedForm(
onSaved: widget.onSavedForm,
onDoneSuccess: widget.onDoneSuccess);
}
},
),
),
SizedBox(
width: 10,
),
Expanded(
child: RaisedButton(
child: Text(
"Vazgeç",
style: TextStyle(
color: Colors.lightBlue, fontSize: 15),
),
onPressed: () => state.setShowForm(false),
),
),
],
),
if (!state.success && !state.busy)
Text(
'stLocalization.getTranslated(state.error)' +
state.error,
style: TextStyle(color: Colors.red),
)
],
),
),
if (state.busy) CircularProgressIndicator(strokeWidth: 2),
]),
);
}
}
//main.dart
import 'package:flutter/material.dart';
import 'Mx/mxVop/mxVopForm.dart';
import 'Mx/mxVop/mxVopValidators.dart';
import 'test/RandomGenerate.dart';
import 'wsChangeableText.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class _Op with MxVopForm, MxVopIsLength {}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _title = 'parent ilk data';
String get title => _title;
final _op = _Op();
set title(String title) {
setState(() {
_title = title;
});
}
Future<void> updateTitle(String value) async {
await Future.delayed(Duration(seconds: 2), () {
_title = value;
});
}
Future<String> future() async {
return await Future.delayed(Duration(seconds: 5), () {
return _title = 'future ilk data';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MyHomePage'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
WsChangeableText(
future: future ,
text: _title,
icon: Icon(Icons.account_circle),
onDoneSuccess: (value) {
title = value;
},
labelText: 'Name',
onValidator: (value) => _op.mxValidator(_op.mxIsLength(value, 5),
'En az 5 karekter uzunluğunda olmalı!'),
onSavedForm: updateTitle,
),
// Text('Parent title : ' + title),
FutureBuilder<String>(
// initialData: title,
future: future() ,
builder: (context, snapshot) {
if (snapshot.hasData)
return Text('FutureBuilder title : ' + snapshot.data);
else if (snapshot.hasError)
return Text('FutureBuilder Hata: ' + snapshot.error);
else
return Text('FutureBuilder Veri getiriliyor..');
})
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
title = RandomGenerate.getTitle();
});
},
tooltip: 'Değiştir',
child: Icon(Icons.add),
),
);
}
}