#firebase #flutter #dart #google-cloud-firestore
#firebase #трепетание #дротик #google-облако-firestore
Вопрос:
Когда пользователь запускает мое приложение в первый раз, он может переключаться между формой регистрации и формой входа. После заполнения одной из этих форм он должен видеть экран загрузки до тех пор, пока пользователь не будет создан или не войдет в систему. В моем случае, к сожалению, экран загрузки не исчезает, хотя пользователь создан. Как я могу решить эту проблему?
форма входа:
class SignIn extends StatefulWidget {
final Function toggleView;
SignIn({this.toggleView});
@override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
// text field state
String email = '';
String password = '';
String error = '';
static const color = const Color(0xFF2F80ED);
@override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
child: Positioned(
top: 0,
right: 0,
child: Image.asset(
'assets/canvas-1-ws.png',
),
),
),
Positioned(
top: 25.0,
left: 5.0,
child: IconButton(
icon: Icon(
Icons.close,
color: Colors.black,
size: 35.0,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Welcome(),
),
);
},
),
),
Container(
child: Positioned(
bottom: 0,
left: 0,
child: Image.asset(
'assets/canvas-2-ws.png',
),
),
),
Center(
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(
left: 50.0,
right: 50.0,
),
child: Container(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Login',
style: TextStyle(
color: Colors.black,
fontFamily: 'Roboto Black',
fontSize: 35.0,
),
),
SizedBox(
height: 30.0,
),
TextFormField(
style: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
cursorColor: Colors.black,
decoration: InputDecoration(
fillColor: Colors.black,
hintText: 'Email',
hintStyle: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
),
validator: (val) => val.isEmpty
? 'Bitte gültige Email'
: null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(
height: 20.0,
),
TextFormField(
style: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
cursorColor: Colors.black,
decoration: InputDecoration(
fillColor: Colors.black,
hintText: 'Passwort',
hintStyle: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
),
obscureText: true,
validator: (val) => val.isEmpty
? 'Bitte gültiges Passwort'
: null,
onChanged: (val) {
setState(() => password = val);
}),
SizedBox(
height: 45.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Login',
style: TextStyle(
fontFamily: 'Roboto Light',
fontSize: 25.0),
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.signInWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
error = 'Falsche Email/Password';
loading = false;
});
}
}
},
),
),
],
),
),
),
),
],
),
),
],
),
);
}
}
форма регистрации почти аналогична…
файл, в котором пользователь может переключаться между формами:
class Welcome extends StatefulWidget {
final Function toggleView;
Welcome({this.toggleView});
@override
_WelcomeState createState() => _WelcomeState();
}
class _WelcomeState extends State<Welcome> {
static const color = const Color(0xFF2F80ED);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
Positioned(
top: 0,
right: 0,
child: Image.asset('assets/canvas-1-ws.png'),
),
Positioned(
bottom: 0,
left: 0,
child: Image.asset('assets/canvas-2-ws.png'),
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/Skiclublogo_transparent.png',
scale: 4,
),
SizedBox(
height: 40.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Registrieren',
style: TextStyle(
fontFamily: 'Roboto Light', fontSize: 25.0),
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Register(),
),
);
}),
),
SizedBox(
height: 40.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Login',
style: TextStyle(
fontFamily: 'Roboto Light', fontSize: 25.0),
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SignIn(),
),
);
}),
),
],
),
),
],
),
);
}
}
файл авторизации, в котором пользователь создается или входит в систему:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on FirrebaseUser
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
// sign in anonmously
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(
user.displayName, user.email, user.photoUrl, user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in email amp; password
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// register with email amp; password
Future registerWithEmailAndPassword(
String email, String password, String name) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
// update user info
UserUpdateInfo userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = name;
await user.updateProfile(userUpdateInfo);
await user.reload();
user = await FirebaseAuth.instance.currentUser();
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(
user.displayName, user.email, user.photoUrl, user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
// current user
void inputData() async {
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
// here you write the codes to input the data into firestore
}
}
файл-оболочка, в котором приложение проверяет, является ли пользователь новым:
class Wrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
// return either Home or Authenticate widget
if (user == null) {
return Welcome();
} else {
return DrawerNav();
}
}
}
файл экрана загрузки:
class Loading extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: SpinKitWave(
color: Colors.black,
size: 50.0,
),
),
);
}
}
Большое вам спасибо, когда вы прочитали все это!
Ответ №1:
Вы не всегда вызываете setState после создания пользователя.
Это будет работать
onPressed: (){ if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.signInWithEmailAndPassword(
email, password);
setState(() => loading = false);
if (result == null) {
setState(() {
error = 'Falsche Email/Password';
});
}
}},
Комментарии:
1. Нет, это не работает. Когда я нажимаю кнопку входа, появляется экран загрузки, а после входа снова появляется экран…
2. Конечно, я удалил экран загрузки только после _auth.signInWithEmailAndPassword, как вы просили. Может быть, вы хотите перейти на другую страницу, поэтому используйте Navigator.push( контекст, MaterialPageRoute( builder: (context) => NewPage(), ), );
Ответ №2:
Я объясню тебе, мой друг
установите boolean
переменную с именем loading
loading = false;
если loading
true
отображать экран загрузки, то отображать пользовательский интерфейс формы с помощью ternary operator
при создании пользователя измените state
loading
значение, чтобы появился экран загрузки
setState(() { loading=true; });
после создания пользователя state
loading
снова измените значение на false
setState(() { loading=false; });
Это шаблон в build
function
loading==false?yourui():loading()