0%

Flutter 026 - Presentation Login & Splash Screen (part10)

前言

Hi, 今天就是把之前寫的一堆功能放到Screen裡面,由於是UI的部分所以程式碼會很長,有些地方我只會擷取片段,建議大家看完整程式碼。

完整程式碼

需要具備知識

Splash Screen

把首頁的MultiBlocProvider加上AuthenticationBloc,並觸發事件AppStarted()來檢查是否有登入過。

1
2
3
4
5
6
7
// main.dart

BlocProvider(
create: (context) => AuthenticationBloc(
authRepository: authRepository,
)..add(AppStarted()),
),

把這個畫面設置成初始畫面,然後當事件觸發後BlocListener會監聽AuthenticationBloc現在的狀態進行頁面切換。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class SplashScreen extends StatelessWidget {
const SplashScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is Unauthenticated) {
context.replaceRoute(LoginScreen());
}
if (state is Authenticated) {
context.replaceRoute(HomeScreen());
}
},
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
),
);
}
}

Login Screen

LoginScreen這邊一樣加一個AuthenticationBloc監聽器,檢查是否登入成功取得驗證。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class LoginScreen extends StatelessWidget {
const LoginScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is Authenticated) {
context.replaceRoute(HomeScreen());
}
},
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
alignment: Alignment.center,
children: [
Positioned(
top: 200,
child: Text(
"Hello",
style: Theme.of(context).textTheme.bodyText1,
),
),
Positioned(
top: 370,
child: BlocProvider(
create: (context) =>
SignInBloc(authRepository: AuthRepository()),
child: LoginFrom(),
),
),
],
),
),
),
);
}
}

Login From

創建SignInBloc然後在LoginForm裡面寫一個SignInBloc的監聽器來檢查登入成功或失敗,如果登入成功的話就觸法LoggedIn的事件。

1
2
3
4
5
6
7
8
Positioned(
top: 370,
child: BlocProvider(
create: (context) =>
SignInBloc(authRepository: AuthRepository()),
child: LoginFrom(),
),
),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class LoginFrom extends StatelessWidget {
const LoginFrom({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return BlocListener<SignInBloc, SignInState>(
listener: (context, state) {
if (state is SignInStateSuccess) {
BlocProvider.of<AuthenticationBloc>(context).add(LoggedIn());
}
if (state is SignInStateFailure) {
// TODO: Display a snackbar
}
},
child: Column(
children: [
GoogleSignInButton(),
],
),
);
}
}

Home Screen

在首頁檢查驗證登入狀態,然後在登出按鈕(左上角的小啤酒)新增LoggedOut事件。

1
2
3
4
5
6
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is Unauthenticated) {
context.replaceRoute(LoginScreen());
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SignOutButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return IconButton(
onPressed: () {
BlocProvider.of<AuthenticationBloc>(context).add(LoggedOut());
},
icon: Icon(
Icons.sports_bar_rounded,
color: Theme.of(context).shadowColor,
size: 30,
),
);
}
}