الگوی صفحه چینی فرم لاگین
جهت صفحه چینی فرم های اپلیکیشن ، شما راه حل های زیادی را پیش روی خود دارید . در این مطلب یک روش ساخت یافته و اصولی جهت صفحه چینی فرم لاگین خدمت شما ارائه می دهم .جهت این منظور من از ویجت های Container ، ویجت Stack ، ویجت Column ، ویجت Form و ویجت TextFormField به ترتیبی که در تصویر زیر قابل مشاهده است ، استفاده کرده ام .
در این پروژه از انیمیشن ها ، قابلیت ذخیره در Shared Preferences و اتصال به سرور استفاده شده است . جهت ایجاد این پروژه ، ابتدا یک پروژه جدید ایجاد نمایید ، سپس فایل های زیر را ایجاد و کدهای هر فایل را در آن کپی نمایید . حال پروژه را اجرا و خروجی را مشاهده نمایید .
کدهای مربوط به فایل اصلی صفحه لاگین ( فایلی به نام LoginUser.dart ) :
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:whatsapp_roocket/WebServices/Auth_Service.dart';
import 'package:whatsapp_roocket/animations/SingIn_animation.dart';
import 'package:whatsapp_roocket/components/FormContainer.dart' as form;
class LoginUser extends StatefulWidget {
@override
_LoginUserState createState() => _LoginUserState();
}
class _LoginUserState extends State<LoginUser>
with SingleTickerProviderStateMixin {
AnimationController _loginButtonController;
final formKey = GlobalKey<FormState>(); // کلید فرم ورود
final scaffoldKey = GlobalKey<ScaffoldState>(); // کلید اسکفولد
var _emailValue;
var _passwordValue;
@override
void initState() {
// TODO: implement initState
super.initState();
_loginButtonController = AnimationController(
vsync: this, duration: Duration(milliseconds: 3000));
}
@override
void dispose() {
// TODO: implement dispose
_loginButtonController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final sizeScreen = MediaQuery.of(context).size;
return Scaffold(
key: scaffoldKey,
resizeToAvoidBottomPadding: false,
body: Container(
//width: sizeScreen.width,
//height: sizeScreen.height,
decoration: BoxDecoration(
gradient: LinearGradient(colors: <Color>[
Color(0xFF456c7d),
Color(0xFF113746),
], begin: Alignment.topCenter, end: Alignment.bottomCenter),
),
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
Opacity(
opacity: 0.1,
child: Container(
width: sizeScreen.width,
height: sizeScreen.height,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://javareshkian.ir/wp-content/uploads/2020/04/icon-background.png'),
repeat: ImageRepeat.repeat,
),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 70),
child: Image(
width: 100,
height: 100,
image: NetworkImage(
'https://javareshkian.ir/wp-content/uploads/2020/03/javareshkian4.png'),
),
),
form.FormContainer(
formKey: formKey,
emailOnSaved: (String value) {
_emailValue = value;
//print(_emailValue);
},
passwordOnSaved: (String value) {
_passwordValue = value;
},
),
FlatButton(
onPressed: null,
child: Text(
'حساب کاربری ندارید ؟! ثبت نام',
style: TextStyle(
color: Colors.white70,
fontWeight: FontWeight.w300,
letterSpacing: 1.5),
),
)
],
),
GestureDetector(
onTap: () async {
if (formKey.currentState.validate()) {
formKey.currentState.save();
await checkUserForServer();
}
},
child: SingInAnimation(
controller: _loginButtonController.view,
sizeWidthScreen: sizeScreen.width,
))
],
),
),
);
}
checkUserForServer() async {
await _loginButtonController.animateTo(0.350);
var response = await (new AuthService())
.checkLoginUser({'email': _emailValue, 'password': _passwordValue});
if (response['status'] == 'success') {
// ذخیره اطلاعات در شیردرفرنسز
await storeUserData(response['data']);
await _loginButtonController.forward();
Navigator.pushReplacementNamed(context, '/');
} else {
await _loginButtonController.reverse();
scaffoldKey.currentState.showSnackBar(new SnackBar(
content: Text(
response['data'],
style: TextStyle(fontFamily: 'Vazir'),
)));
}
}
// تابع ذخیره اطلاعات در شیردرفرنسز
storeUserData(Map userData) async {
SharedPreferences sharedUserData = await SharedPreferences.getInstance();
sharedUserData.setString('user.api_token', userData['api_token']);
sharedUserData.setInt('user.user_id', userData['user_id']);
}
}
کدهای مربوط به فایل FormContainer.dart :
import 'package:flutter/material.dart';
import 'package:whatsapp_roocket/components/InputFieldArea.dart';
import 'package:validators/validators.dart' as validDart;
class FormContainer extends StatelessWidget {
final formKey;
final emailOnSaved;
final passwordOnSaved;
FormContainer(
{@required this.formKey,
@required this.emailOnSaved,
@required this.passwordOnSaved,
});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 50),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
new InputFieldArea(
obscureText: false,
hintText: 'ایمیل نام کاربری خود را وارد نمایید',
hintFontSize: 15,
hintColorText: Colors.grey[500],
textColor: Colors.white,
textFontSize: 15,
iconInput: Icons.person_outline,
iconColor: Colors.white,
textValidator: null,
// ignore: missing_return
validate: (String value) {
print('value : $value');
print('contains : ${value.contains('@') && value.contains('.')}');
if (value.contains('@') && value.contains('.')) {
}else
return 'نام کاربری نامعتبر است !';
},
onSaved: emailOnSaved,
),
new InputFieldArea(
obscureText: true,
hintText: 'رمز ورود خود را وارد نمایید',
hintFontSize: 15,
hintColorText: Colors.grey[500],
textColor: Colors.white,
textFontSize: 15,
iconInput: Icons.lock_outline,
iconColor: Colors.white,
textValidator: null,
// ignore: missing_return
validate: (String value) {
if (value.length < 6) {
return 'طول کلمه عبور باید حداقل ۶ کاراکتر باشد .';
}
},
onSaved: passwordOnSaved,
),
],
),
),
);
}
}
کدهای مربوط به فایل InputFieldArea.dart :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class InputFieldArea extends StatelessWidget {
final bool obscureText;
final String hintText;
final double hintFontSize;
final Color hintColorText;
final Color textColor;
final double textFontSize;
final IconData iconInput;
final Color iconColor;
final textValidator;
final validate;
final onSaved;
InputFieldArea(
{@required this.obscureText,
@required this.hintText,
@required this.hintFontSize,
@required this.hintColorText,
@required this.textColor,
@required this.textFontSize,
@required this.iconInput,
@required this.iconColor,
@required this.textValidator,
@required this.validate,
@required this.onSaved,
});
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 10),
child: TextFormField(
// ignore: missing_return
validator: validate,
onSaved: onSaved,
obscureText: obscureText,
textAlign: TextAlign.center,
style: TextStyle(color: textColor, fontSize: textFontSize,),
decoration: InputDecoration(
icon: Icon(
iconInput,
color: iconColor,
),
hintText: hintText,
hintStyle:
TextStyle(color: hintColorText, fontSize: hintFontSize),
contentPadding: EdgeInsets.symmetric(vertical: 15, horizontal: 5),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white30),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.yellow),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.yellow),
),
errorStyle: TextStyle(color: Colors.yellow, fontSize: 12)
),
));
}
}
class MyText extends StatelessWidget {
final onSaveValue;
MyText({this.onSaveValue});
@override
Widget build(BuildContext context) {
return TextFormField(
onSaved: onSaveValue,
);
}
}
کدهای مربوط به فایل SingIn_animation.dart :
import 'package:flutter/material.dart';
class SingInAnimation extends StatelessWidget {
final Animation<double> controller;
final Animation<double> buttonSizeReduction; // انیمیشن کاهش سایز دکمه
final Animation<double> buttonFullScreen; // انیمیشن تمام صفحه شدن دکمه
final double sizeWidthScreen;
SingInAnimation({this.controller, this.sizeWidthScreen})
: buttonSizeReduction =
Tween(begin: (sizeWidthScreen * 60) / 100, end: 60.0).animate(
CurvedAnimation(
parent: controller,
curve: Interval(0.0, 0.350, curve: Curves.bounceOut))),
buttonFullScreen = Tween(begin: 70.0, end: 1000.0).animate(
CurvedAnimation(
parent: controller,
curve: Interval(0.700, 0.950, curve: Curves.easeOutSine)));
Widget _animationBuilder(BuildContext context, Widget child) {
return buttonFullScreen.value <= 300
? Container(
margin: buttonFullScreen.value == 70
? EdgeInsets.only(bottom: 30)
: buttonFullScreen.value <= 100
? EdgeInsets.only(bottom: 20)
: buttonFullScreen.value <= 200
? EdgeInsets.only(bottom: 10)
: EdgeInsets.only(bottom: 0),
width: buttonFullScreen.value == 70.0
? buttonSizeReduction.value
: buttonFullScreen.value,
height:
buttonFullScreen.value == 70.0 ? 60.0 : buttonFullScreen.value,
alignment: Alignment.center,
child: buttonSizeReduction.value >= 120
? Text(
'ورود',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w300,
),
)
: buttonFullScreen.value <= 120
? CircularProgressIndicator(
backgroundColor: Colors.white,
)
: null,
decoration: BoxDecoration(
color: Color(0xff2258a6),
// borderRadius: BorderRadius.circular(30),
borderRadius: buttonFullScreen.value <= 200
? BorderRadius.circular(30)
: null,
),
)
: Container(
width: buttonFullScreen.value,
height: buttonFullScreen.value,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: Color(0xff2258a6),
),
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: _animationBuilder,
);
}
}
کدهای مربوط به فایل Auth_Service.dart :
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
class AuthService {
// تابع بررسی اطلاعات کاربری با سرور
Future<Map> checkLoginUser(Map bodyValue) async {
http.Response response = await http.post(
'http://roocket.org/api/login',
//headers: {"Content-Type": "application/json"},
encoding: Encoding.getByName('utf-8'),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: bodyValue,
);
var userValue = json.decode(utf8.decode(response.bodyBytes));
return userValue;
}
static Future<bool> checkApiToken(String userToken) async{
http.Response response = await http.get('http://roocket.org/api/user?api_token=$userToken', headers: {'Accept' : 'aplication/json'});
print((response.statusCode));
return response.statusCode == 200;
}
}
خروجی کدهای فوق به شکل زیر است :
امیدوارم این مطلب برای شما مفید باشد .