Flutter小实战----我们使用BLoc来实现一个登录的功能

前言:近来换了一份工作。在新工作中,由于公司产品是使用bloc开发的,那么没办法了,只能学了一下。在学习bloc的过程中,比较顺畅吧。感觉他跟provider(仅仅使用的区别,不是源码还有他跟provider适用场景的区别!!!!再次提示,勿喷)的区别就是,provider做一个封装过InheritWidget的特殊顶层变量它里面镶嵌这widget,而bloc是把自己的数据层,事件,状态,全部分割出来,当然你开始会觉得他很乱,要是用明白之后,发现其实这个框架开发产品挺舒服的。毕竟逻辑清晰。

准备

当然还是导包了对吧。
Flutter小实战----我们使用BLoc来实现一个登录的功能_第1张图片

好了有人问我为什么要用equatable这个库呢,其实这个库很好用的,enmm怎么说呢,榨干Flutter的最后性能。这个库会将我们暴露出来的对象进行比较,如果发生了变化,他就会指导bloc进行重构,反之。。。

开始

1.我们创建属于我们的bloc文件夹,这样方便以后我们进行管理。
Flutter小实战----我们使用BLoc来实现一个登录的功能_第2张图片

不要管这个sinple_bloc_delegate.dart是什么,用也行不用也行,就是我们可以做的一个全局捕捉,个人感觉没啥用啊!!!!

2.创建我们正常需要的bloc通用文件

Flutter小实战----我们使用BLoc来实现一个登录的功能_第3张图片

在这里我说一下,login_bloc是我们组装的bloc的用法,login_state是我们每个操作返回的页面state状态,login_event是我们的操作动作,就是我们的事件,login_repository是我们的数据层。

不说别的了上代码:

login_state是记录我们页面的state状态,用它来判断我们页面的显示


import 'package:equatable/equatable.dart';
import 'package:flutterbloccart/model/user_model.dart';

abstract class LoginState extends Equatable{
  const LoginState();

  @override
  List get props => [];
}

class LoginInitialState extends LoginState{}

class LoginInProgressState extends LoginState{}

class LoginSuccessState extends LoginState{
  final UserModel model;

  LoginSuccessState(this.model);

  @override
  List get props => [model];
}

class LoginFailureState extends LoginState{
  final String errMsg;

  LoginFailureState(this.errMsg);

  @override
  List get props => [errMsg];
}
 
  

login_event是我们的事件,用来判断bloc返回哪一个state


import 'package:equatable/equatable.dart';

abstract class LoginEvent extends Equatable{
  const LoginEvent();

  @override
  List get props => [];
}

class LoginPressEvent extends LoginEvent{
  final String name;
  final String pwd;

  LoginPressEvent(this.name, this.pwd);

  @override
  List get props => [name,pwd];
}
 
  

login_bloc组合login_state和login_event


import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterbloccart/bloc/login_event.dart';
import 'package:flutterbloccart/bloc/login_repository.dart';
import 'package:flutterbloccart/bloc/login_state.dart';
import 'package:flutterbloccart/model/user_model.dart';

class LoginBloc extends Bloc{

  @override
  LoginState get initialState => LoginInitialState();

  @override
  Stream mapEventToState(LoginEvent event) async* {
    try{
      if(event is LoginPressEvent){
        UserModel model = UserModel.init();
        yield LoginInProgressState();
        final currentEvent = event;
        model = await LoginRepository.login(currentEvent.name.trim(), currentEvent.pwd.trim());
        yield LoginSuccessState(model);
      }
    }catch(e){
      final errMsg = '登录错误';
      yield LoginFailureState(errMsg);
    }
  }
}

login_repositor是与网络交互的数据层,这里我是模拟了一下过程。


import 'package:flutterbloccart/model/user_model.dart';

class LoginRepository{

  static Future login(String name,String pwd) async {
    if(name.length >= 6 && pwd.length >= 6){
      await Future.delayed(Duration(seconds: 2));
      return UserModel(name: name, pwd: pwd);
    }else{
      throw Exception('登录错误');
    }

  }

}

还有我们建立的UserModel数据模型,这是我们存储在bloc实例上的数据


import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';

class UserModel extends Equatable{
  final String name;
  final String pwd;

  UserModel({@required this.name, @required this.pwd}) :assert(name != null,pwd != null);

  factory UserModel.init(){
    return UserModel(name: '',pwd: '');
  }

  @override
  List get props => [name,pwd];
}
 
  

然后看我们的页面布局
login_page

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterbloccart/bloc/login_bloc.dart';
import 'package:flutterbloccart/bloc/login_event.dart';
import 'package:flutterbloccart/bloc/login_state.dart';
import 'package:flutterbloccart/home_page.dart';

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State {
  final nameCtr = new TextEditingController();
  final pwdCtr = new TextEditingController();

  @override
  void initState() {
    super.initState();
    nameCtr.addListener(() {
      print('name输入框的实时变化::::${nameCtr.text}');
    });
    pwdCtr.addListener(() {
      print('pwd输入框的实时变化::::${pwdCtr.text}');
    });
  }

  @override
  void dispose() {
    super.dispose();
    nameCtr?.removeListener(() { });
    nameCtr?.dispose();
    pwdCtr?.removeListener(() { });
    pwdCtr?.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('登录'),
        centerTitle: true,
      ),
      body: BlocBuilder(
        builder: (context,state){
          if(state is LoginInitialState){
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                nameTF(),
                pwdTF(),
                loginBtn(context,(){
                  BlocProvider.of(context).add(LoginPressEvent(nameCtr.text.trim(), pwdCtr.text.trim()));
                }),
              ],
            );
          }

          if(state is LoginInProgressState){
            return Center(
              child: CircularProgressIndicator(),
            );
          }

          if(state is LoginSuccessState){
            return SuccessDialog();
          }

          if(state is LoginFailureState){
            final currentState = state;
            return Center(
              child: Text(currentState.errMsg,style: TextStyle(fontSize: 18,color: Colors.black),),
            );
          }

          return Container();
        },
      ),
    );
  }

  Widget nameTF(){
    return Container(
      height: 60,
      margin: EdgeInsets.symmetric(horizontal: 50),
      width: double.infinity,
      child: TextField(
        controller: nameCtr,
        decoration: InputDecoration(
          fillColor: Color(0x30cccccc),
          filled: true,
          enabledBorder: OutlineInputBorder(
            borderSide: BorderSide(color: Color(0x00FF0000)),
            borderRadius: BorderRadius.circular(100)
          ),
          focusedBorder: OutlineInputBorder(
              borderSide: BorderSide(color: Color(0x00FF0000)),
              borderRadius: BorderRadius.circular(100)
          ),
          hintText: '请输入用户名'
        ),
      ),
    );
  }

  Widget pwdTF(){
    return Container(
      height: 60,
      margin: EdgeInsets.symmetric(horizontal: 50,vertical: 10),
      width: double.infinity,
      child: TextField(
        controller: pwdCtr,
        decoration: InputDecoration(
            fillColor: Color(0x30cccccc),
            filled: true,
            enabledBorder: OutlineInputBorder(
                borderSide: BorderSide(color: Color(0x00FF0000)),
                borderRadius: BorderRadius.circular(100)
            ),
            focusedBorder: OutlineInputBorder(
                borderSide: BorderSide(color: Color(0x00FF0000)),
                borderRadius: BorderRadius.circular(100)
            ),
            hintText: '请输入密码',
        ),
        obscureText: true,
      ),
    );
  }

  Widget loginBtn(context,onPressed){
    return Container(
      height: 50,
      margin: EdgeInsets.symmetric(horizontal: 50),
      width: double.infinity,
      child: RaisedButton(
        child: Text('登录',style: TextStyle(fontSize: 16,color: Colors.white),),
        color: Theme.of(context).accentColor,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(100),
        ),
        onPressed: onPressed,
      ),
    );
  }
}


class SuccessDialog extends StatefulWidget {
  @override
  _SuccessDialogState createState() => _SuccessDialogState();
}

class _SuccessDialogState extends State {

  Future waitFuture() async{
    await Future.delayed(Duration(milliseconds: 500));
    Navigator.of(context).push(MaterialPageRoute(
      builder: (context) => HomePage()
    ));
  }

  @override
  void initState() {
    super.initState();
    waitFuture();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('登录成功',style: TextStyle(fontSize: 18,color: Colors.black),),
    );
  }
}

home_page

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterbloccart/bloc/login_bloc.dart';
import 'package:flutterbloccart/bloc/login_state.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State {
  LoginBloc loginBloc;

  @override
  void initState() {
    super.initState();
    loginBloc =  BlocProvider.of(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('登录成功的页面'),
        centerTitle: true,
      ),
      body: BlocBuilder(
        builder: (context,state){
          if(state is LoginSuccessState){
            final currentState = state;
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('登录成功',style: TextStyle(fontSize: 24,color: Colors.black),),
                SizedBox(height: 10,),
                Text('登录账号::::${state.model.name}',style: TextStyle(fontSize: 18,color: Colors.black),),
                SizedBox(height: 10,),
                Text('登录密码::::${state.model.pwd}',style: TextStyle(fontSize: 18,color: Colors.black),),
              ],
            );
          }

          return Container();
        },
      ),
    );
  }
}

然后我们需要将这个实例注入到MaterialApp上面做最底层的数据共享

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterbloccart/bloc/login_bloc.dart';
import 'package:flutterbloccart/login_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => LoginBloc(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: LoginPage(),
      ),
    );
  }
}

好了,我们使用BLoc设计的登录功能已经完成了。

我也不想多解释什么了,其实很明白了。就是我们在LoginBloc中重写的mapEventToState方法,至少每个事件要yield一个state对象,这个对象就是我们的login_state需要用它来判断当前页面的显示。

我也不放图了。代码copy下来就能运行。这就是一个最简单的bloc功能的设计。当然还有其他的bloc的方法。就需要你们自己去研究了。。。

你可能感兴趣的:(Flutter实战,Flutter/Dart,flutter,Dart)