Cara Mudah Membuat BLoC Stream Provider Pada Flutter
Memastikan possible untuk memisahkan business login dari ui dengan memanfaatkan fungsionalitas Stream untuk mengelola dan menyebarkan perubahan.
1. Install
pubspec.yaml
dependencies:
rxdart: 0.18.1
provider: 1.4.0
kemudian jalankan
flutter pub get
2. Membuat BLoC Stream Provider
Contoh
susunan directory
❏ lib
❏ page
❏ profile_form_page.dart
❏ profile_page.dart
❏ model
❏ profile.dart
❏ bloc
❏ profile_bloc.dart
❏ main.dart
lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_app/page/profile_form_page.dart';
import 'package:my_app/bloc/profile_bloc.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final appTitle = 'BLoC Stream Demo';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: StatefulProvider<ProfileBloc>(
valueBuilder: (context) => ProfileBloc(),
onDispose: (context, bloc) => bloc.dispose(),
child: ProfileFormPage(appTitle: appTitle),
),
);
}
}
lib/bloc/profile_bloc.dart
import 'package:rxdart/rxdart.dart';
import 'package:my_app/model/profile.dart';
class ProfileBloc {
final BehaviorSubject _profileSubject = BehaviorSubject<Profile>(seedValue: Profile());
Stream<Profile> get profileStream => _profileSubject.controller.stream;
void updateWith({ String name, String email, String phone }) {
Profile value = _profileSubject.value.copyWith(name: name, email: email, phone: phone);
_profileSubject.add(value);
}
void dispose() {
_profileSubject.close();
}
}
lib/model/profile.dart
class Profile {
final String name;
final String email;
final String phone;
Profile({ this.name, this.email, this.phone });
Profile copyWith({ String name, String email, String phone }) {
return Profile(
name: name ?? this.name,
email: email ?? this.email,
phone: phone ?? this.phone,
);
}
}
lib/page/profile_form_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:my_app/page/profile_page.dart';
import 'package:my_app/bloc/profile_bloc.dart';
import 'package:my_app/model/profile.dart';
class ProfileFormPage extends StatefulWidget {
ProfileFormPage({ this.appTitle });
String appTitle;
@override
_ProfileFormPageState createState() => new _ProfileFormPageState(appTitle: appTitle);
}
class _ProfileFormPageState extends State<ProfileFormPage> {
_ProfileFormPageState({ this.appTitle });
String appTitle;
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
final profileBloc = Provider.of<ProfileBloc>(context);
return Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: Form(
key: _formKey,
child: StreamBuilder(
stream: profileBloc.profileStream,
initialData: Profile(),
builder: (context, snapshot) {
return Container(
margin: EdgeInsets.all(20.0),
child: ListView(
children: [
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) return 'Name must filled';
return null;
},
keyboardType: TextInputType.text,
decoration: InputDecoration(
hintText: 'Barry allen',
labelText: 'Name',
icon: Icon(Icons.verified_user),
),
onChanged: (text) => profileBloc.updateWith(name: text),
),
TextFormField(
validator: (value) {
if (value.contains('@') && value.contains('.')) return null;
return "Not valid email";
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'hero@example.com',
labelText: 'Email',
errorText: snapshot.error,
icon: Icon(Icons.email),
),
onChanged: (text) => profileBloc.updateWith(email: text),
),
TextFormField(
validator: (value) {
if (value == null || value.isEmpty) return 'Phone must filled';
return null;
},
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter your phone',
labelText: 'Phone',
errorText: snapshot.error,
icon: Icon(Icons.contact_phone),
),
onChanged: (text) => profileBloc.updateWith(phone: text),
),
SizedBox(height: 10.0),
RaisedButton(
child: Text('submit'),
color: Colors.blue,
onPressed: () {
final FormState form = _formKey.currentState;
if (form.validate()) {
// form.save();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProfilePage(appTitle: appTitle, profile: snapshot.data)),
);
form.reset();
}
}
),
]
),
);
}
),
),
);
}
}
lib/page/profile_page.dart
import 'package:flutter/material.dart';
import 'package:my_app/model/profile.dart';
class ProfilePage extends StatelessWidget {
ProfilePage({ this.appTitle, this.profile });
String appTitle;
Profile profile;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: ListView(
shrinkWrap: true,
padding: EdgeInsets.all(10.0),
children: [
_information('Name', profile.name),
_information('Email', profile.email),
_information('Phone', profile.phone),
],
),
);
}
Expanded _information(String title, String value) {
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(bottom: 8),
child: Text(
title,
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
),
),
Text(
value,
style: TextStyle(
fontSize: 14.0,
),
),
Padding(
padding: EdgeInsets.all(1.0),
child: new Divider(),
),
],
),
);
}
}
Sekian untuk kali ini semoga bermanfaat :D untuk lebih lanjut bisa kunjungi link tersebut.