الگوی صفحه چینی فرم لاگین
جهت صفحه چینی فرم های اپلیکیشن ، شما راه حل های زیادی را پیش روی خود دارید . در این مطلب یک روش ساخت یافته و اصولی جهت صفحه چینی فرم لاگین خدمت شما ارائه می دهم .جهت این منظور من از ویجت های 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; } }
خروجی کدهای فوق به شکل زیر است :
امیدوارم این مطلب برای شما مفید باشد .