Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
book-app
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
book-app
Commits
e695958e
提交
e695958e
authored
1月 02, 2024
作者:
yueweilu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
登录界面
上级
0a5b3ac8
显示空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
552 行增加
和
85 行删除
+552
-85
controller.dart
lib/pages/login/controller.dart
+14
-24
index.dart
lib/pages/login/index.dart
+3
-0
view.dart
lib/pages/login/view.dart
+106
-39
routes.dart
lib/routes/routes.dart
+2
-2
theme.dart
lib/theme.dart
+20
-20
index.dart
lib/utils/index.dart
+2
-0
styles.dart
lib/utils/styles.dart
+2
-0
validator.dart
lib/utils/validator.dart
+81
-0
input.dart
lib/widgets/input.dart
+322
-0
没有找到文件。
lib/pages/login/controller.dart
浏览文件 @
e695958e
...
...
@@ -5,20 +5,13 @@ enum LoginType{code, password}
class
LoginController
extends
GetxController
{
/// 登录方式
final
loginType
=
LoginType
.
code
;
/// 1、验证码登录
/// 账号
final
TextEditingController
codePhoneInput
=
TextEditingController
();
/// 密码
final
TextEditingController
codeInput
=
TextEditingController
();
/// 2、密码登录
/// 账号
final
TextEditingController
phoneInput
=
TextEditingController
();
/// 密码
final
TextEditingController
passwordInput
=
TextEditingController
();
// 显示密码
final
ValueNotifier
<
bool
>
showPassword
=
ValueNotifier
(
false
);
...
...
@@ -26,7 +19,7 @@ class LoginController extends GetxController {
void
onInit
()
{
/// 测试账号
if
(
kDebugMode
)
{
phoneInput
.
text
=
'1
8810760819
'
;
phoneInput
.
text
=
'1
3521054068
'
;
passwordInput
.
text
=
'123456'
;
}
super
.
onInit
();
...
...
@@ -36,18 +29,13 @@ class LoginController extends GetxController {
void
onClose
()
{
phoneInput
.
dispose
();
passwordInput
.
dispose
();
showPassword
.
dispose
();
super
.
onClose
();
}
void
onShowPassword
()
=>
showPassword
.
value
=
!
showPassword
.
value
;
void
submit
(
BuildContext
context
)
async
{
/// 验证码登录
if
(
loginType
==
LoginType
.
code
){
}
else
if
(
loginType
==
LoginType
.
password
){
}
Future
<
bool
>
onLogin
(
GlobalKey
<
FormState
>
key
)
async
{
final
result
=
AccountAPI
.
login
(
phone:
''
,
...
...
@@ -65,13 +53,15 @@ class LoginController extends GetxController {
]);
if
(!
context
.
mounted
)
return
;
if
(
context
.
canPop
()){
context
.
pop
();
}
else
{
context
.
goNamed
(
Routes
.
main
);
}
// if (!context.mounted) return;
// if (context.canPop()){
// context.pop();
// }else {
// context.goNamed(Routes.main);
// }
return
true
;
...
...
lib/pages/login/index.dart
浏览文件 @
e695958e
...
...
@@ -3,8 +3,10 @@ library login;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_book/apis/index.dart'
;
import
'package:flutter_book/store/index.dart'
;
import
'package:flutter_book/theme.dart'
;
import
'package:flutter_book/utils/index.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:get/get.dart'
;
...
...
@@ -14,6 +16,7 @@ import 'package:ionicons/ionicons.dart';
import
'../../routes/index.dart'
;
import
'../../services/index.dart'
;
import
'../../widgets/index.dart'
;
...
...
lib/pages/login/view.dart
浏览文件 @
e695958e
part of
login
;
class
LoginPage
extends
State
less
Widget
{
class
LoginPage
extends
State
ful
Widget
{
const
LoginPage
({
Key
?
key
})
:
super
(
key:
key
);
@override
State
<
LoginPage
>
createState
()
=>
_LoginPageState
();
}
class
_LoginPageState
extends
State
<
LoginPage
>
{
final
_formKey
=
GlobalKey
<
FormState
>();
bool
isChecked
=
false
;
@override
Widget
build
(
BuildContext
context
)
{
return
GetBuilder
<
LoginController
>(
...
...
@@ -11,59 +18,119 @@ class LoginPage extends StatelessWidget {
builder:
(
controller
)
=>
GestureDetector
(
onTap:
()
=>
Tools
.
unfocus
(),
child:
Scaffold
(
extendBodyBehindAppBar:
true
,
body:
SingleChildScrollView
(
child:
SafeArea
(
minimum:
const
EdgeInsets
.
all
(
0
)
,
child:
codeLogin
()
appBar:
CustomAppBar
(
systemOverlayStyle:
Theme
.
of
(
context
).
brightness
==
Brightness
.
light
?
SystemUiOverlayStyle
.
dark
:
SystemUiOverlayStyle
.
light
,
backgroundColor:
Colors
.
transparent
,
),
// extendBodyBehindAppBar: true,
body:
SafeArea
(
top:
false
,
minimum:
const
EdgeInsets
.
all
(
AppTheme
.
margin
).
copyWith
(
// top:Screen.statusBar,
left:
25
,
right:
25
,
bottom:
25
),
),
)
);
}
/// 验证码登录
Widget
codeLogin
(){
return
Container
(
margin:
EdgeInsets
.
only
(
left:
10
,
right:
10
),
child:
Form
(
key:
_formKey
,
child:
Container
(
// color: Colors.green,
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
stretch
,
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Column
(
// crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
const
SizedBox
(
height:
120
,),
Container
(
width:
180
,
height:
50
,
color:
Colors
.
cyan
,
),
const
SizedBox
(
height:
66
),
CustomFormInput
(
// label: 'Phone',
// required: true,
hintText:
'请输入手机号'
,
keyboardType:
TextInputType
.
number
,
controller:
controller
.
phoneInput
,
validator:
EmailValidator
(),
),
Gaps
.
vGaps13
,
ValueListenableBuilder
<
bool
>(
valueListenable:
controller
.
showPassword
,
builder:
(
context
,
value
,
child
)
=>
CustomFormInput
(
obscureText:
!
value
,
hintText:
'请输入密码'
,
iconData:
value
?
Icons
.
visibility
:
Icons
.
visibility_off
,
controller:
controller
.
passwordInput
,
validator:
EmailValidator
(),
onIcon:
controller
.
onShowPassword
,
),
),
Container
(
margin:
const
EdgeInsets
.
only
(
left:
10
,
right:
10
,
top:
8.5
),
child:
const
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
Text
(
'验证码登录'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
c6
),),
Text
(
'忘记密码'
,
style:
TextStyle
(
fontSize:
13
,
height:
1.3
,
color:
Colours
.
cBlue
),),
],
),
),
const
SizedBox
(
height:
30
,),
// 登录按钮
Container
(
height:
42
,
width:
double
.
infinity
,
decoration:
BoxDecoration
(
borderRadius:
BorderRadius
.
circular
(
50
),
// color: Colors.red,
border:
Border
.
all
(
width:
1
,
color:
Colors
.
red
),
gradient:
const
LinearGradient
(
colors:
[
Color
(
0xFFDE2E5E
),
Color
(
0xFFC31F4C
)],
begin:
Alignment
.
centerLeft
,
end:
Alignment
.
centerRight
),
child:
TextField
(
style:
TextStyle
(
color:
Colors
.
cyan
borderRadius:
BorderRadius
.
circular
(
21
),
),
decoration:
InputDecoration
(
hintText:
'请输入手机号'
,
prefixIcon:
Icon
(
Ionicons
.
phone_portrait
),
border:
InputBorder
.
none
,
enabledBorder:
InputBorder
.
none
,
focusedBorder:
InputBorder
.
none
// contentPadding: EdgeInsets.symmetric(vertical: 16.0),
child:
TextButton
(
onPressed:
()
async
{
FocusScope
.
of
(
context
).
requestFocus
(
FocusNode
());
final
result
=
await
controller
.
onLogin
(
_formKey
);
},
style:
TextButton
.
styleFrom
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
10.5
),
// textStyle: TextStyle(fontSize: 15.0,color: Colors.white),
),
child:
Text
(
'立即登录'
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
15.0
.
w
),),
),
),
SizedBox
(
height:
30
.
w
,),
TextField
(
decoration:
const
InputDecoration
(
hintText:
'获取验证码'
),
],
),
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Container
(
width:
10
.
w
,
height:
10
.
w
,
color:
AppTheme
.
primary
,
),
Gaps
.
hGaps10
,
const
Text
(
'我已阅读并同意'
,
style:
TextStyle
(
color:
Colours
.
c9
,
fontSize:
10
)),
const
Text
(
'《用户协议》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
const
Text
(
'《隐私政策》'
,
style:
TextStyle
(
color:
Colours
.
cBlue
,
fontSize:
10
)),
],
)
],
),
),
),
)
),
)
);
}
/// 密码登录
Widget
passwordLogin
(){
return
Container
();
}
}
lib/routes/routes.dart
浏览文件 @
e695958e
...
...
@@ -38,8 +38,8 @@ abstract class Routes {
static
final
GoRouter
config
=
GoRouter
(
// initialLocation: '/$splash
',
initialLocation:
'/'
,
initialLocation:
'/
$login
'
,
//
initialLocation: '/',
observers:
[
observer
],
routes:
[
GoRoute
(
...
...
lib/theme.dart
浏览文件 @
e695958e
...
...
@@ -80,7 +80,7 @@ abstract class AppTheme {
secondary:
const
Color
(
0xFFFFB800
),
onSecondary:
Colors
.
white
,
tertiary:
const
Color
(
0xFFF4F6F9
),
outline:
const
Color
(
0xFF
F4F6F9
),
outline:
const
Color
(
0xFF
D5D5D5
),
shadow:
const
Color
(
0xFFAB1941
).
withOpacity
(
0.08
),
error:
error
,
onError:
Colors
.
white
,
...
...
@@ -209,43 +209,43 @@ abstract class AppTheme {
isCollapsed:
true
,
isDense:
true
,
filled:
true
,
fillColor:
scheme
.
surface
,
fillColor:
scheme
.
background
,
labelStyle:
TextStyle
(
fontSize:
1
6
.
w
,
color:
scheme
.
onBackground
,
fontWeight:
FontWeight
.
w600
,
fontSize:
1
5
.
w
,
color:
Colours
.
c3
,
//
fontWeight: FontWeight.w600,
),
helperStyle:
TextStyle
(
fontSize:
1
4
.
w
,
fontSize:
1
5
.
w
,
color:
scheme
.
onBackground
.
withOpacity
(
0.7
),
),
contentPadding:
EdgeInsets
.
symmetric
(
horizontal:
2
0
.
w
,
vertical:
1
4
.
w
,
horizontal:
1
0
.
w
,
vertical:
1
0
.
w
,
),
border:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
25
.
w
)),
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
enabledBorder:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
25
.
w
)),
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
disabledBorder:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
25
.
w
)),
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
focusedBorder:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
scheme
.
primary
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
25
.
w
)),
borderSide:
BorderSide
(
color:
scheme
.
outline
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
errorBorder:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
error
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
25
.
w
)),
borderSide:
BorderSide
(
color:
error
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
focusedErrorBorder:
OutlineInputBorder
(
borderSide:
BorderSide
(
color:
error
,
width:
2
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
100
.
w
)),
borderSide:
BorderSide
(
color:
error
,
width:
0.5
.
w
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
6
.
w
)),
),
),
tabBarTheme:
TabBarTheme
(
...
...
lib/utils/index.dart
浏览文件 @
e695958e
...
...
@@ -20,3 +20,4 @@ part 'sign.dart';
part
'encrypt_util.dart'
;
part
'tools.dart'
;
part
'styles.dart'
;
part
'validator.dart'
;
\ No newline at end of file
lib/utils/styles.dart
浏览文件 @
e695958e
...
...
@@ -22,6 +22,7 @@ class Colours {
static
const
c3
=
Color
(
0xFF333333
);
static
const
c6
=
Color
(
0xFF666666
);
static
const
cLine
=
Color
(
0xFFF0F0F0
);
static
const
cBlue
=
Color
(
0xFF2A82D9
);
}
class
Gaps
{
...
...
@@ -32,6 +33,7 @@ class Gaps {
static
const
Widget
vGaps5
=
SizedBox
(
height:
5
,);
static
const
Widget
vGaps10
=
SizedBox
(
height:
10
,);
static
const
Widget
vGaps13
=
SizedBox
(
height:
13
,);
static
const
Widget
vGaps15
=
SizedBox
(
height:
15
,);
// static const Widget line = Padding(
// padding: EdgeInsets.symmetric(horizontal: 15.0),
...
...
lib/utils/validator.dart
0 → 100644
浏览文件 @
e695958e
part of
utils
;
abstract
class
Validator
<
T
>
{
final
String
error
;
Validator
(
this
.
error
);
bool
isValid
(
T
value
);
String
?
call
(
T
value
)
=>
isValid
(
value
)
?
null
:
error
;
bool
hasMatch
(
String
pattern
,
String
value
,
{
bool
caseSensitive
=
true
,
})
=>
RegExp
(
pattern
,
caseSensitive:
caseSensitive
,
).
hasMatch
(
value
);
}
class
RequiredValidator
extends
Validator
<
String
?>
{
RequiredValidator
()
:
super
(
'This field is required'
);
@override
bool
isValid
(
String
?
value
)
=>
(
value
??
''
).
isNotEmpty
;
}
class
EmailValidator
extends
Validator
<
String
?>
{
final
Pattern
_pattern
=
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
;
EmailValidator
()
:
super
(
'Email is invalid'
);
@override
bool
isValid
(
String
?
value
)
{
if
((
value
??
''
).
isEmpty
)
return
true
;
return
hasMatch
(
_pattern
.
toString
(),
value
!,
caseSensitive:
false
);
}
}
class
PasswordValidator
extends
Validator
<
String
?>
{
final
Pattern
_pattern
=
r'(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$'
;
PasswordValidator
()
:
super
(
'The password oil consists of 6 to 16 digits and letters'
);
@override
bool
isValid
(
String
?
value
)
{
if
((
value
??
''
).
isEmpty
)
return
true
;
return
hasMatch
(
_pattern
.
toString
(),
value
!,
caseSensitive:
false
);
}
}
class
EqualValidator
extends
Validator
<
String
?>
{
final
TextEditingController
input
;
EqualValidator
(
this
.
input
)
:
super
(
'Does not match the password'
);
@override
bool
isValid
(
String
?
value
)
{
if
((
value
??
''
).
isEmpty
)
return
true
;
return
input
.
value
.
text
==
value
;
}
}
class
AmountValidator
extends
Validator
<
String
?>
{
final
Pattern
_pattern
=
r'(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)'
;
AmountValidator
()
:
super
(
'Amount is invalid'
);
@override
bool
isValid
(
String
?
value
)
{
if
((
value
??
''
).
isEmpty
)
return
true
;
return
hasMatch
(
_pattern
.
toString
(),
value
!,
caseSensitive:
false
);
}
}
lib/widgets/input.dart
浏览文件 @
e695958e
part of
widgets
;
class
CustomFormInput
extends
FormField
<
String
>
{
final
TextEditingController
?
controller
;
final
String
?
label
;
final
String
?
helper
;
final
String
?
hintText
;
final
bool
required
;
final
bool
readOnly
;
final
bool
obscureText
;
final
bool
autofocus
;
final
IconData
?
iconData
;
final
int
?
maxLines
;
final
void
Function
()?
onTap
;
final
void
Function
()?
onIcon
;
final
ValueChanged
<
String
>?
onChanged
;
final
TextInputType
?
keyboardType
;
final
List
<
TextInputFormatter
>?
inputFormatters
;
CustomFormInput
({
Key
?
key
,
this
.
controller
,
this
.
label
,
this
.
helper
,
this
.
hintText
,
this
.
required
=
false
,
this
.
readOnly
=
false
,
this
.
obscureText
=
false
,
this
.
autofocus
=
false
,
this
.
maxLines
=
1
,
this
.
onTap
,
this
.
onIcon
,
this
.
iconData
,
this
.
onChanged
,
this
.
keyboardType
,
this
.
inputFormatters
,
Validator
<
String
?>?
validator
,
})
:
super
(
key:
key
,
validator:
(
value
)
{
if
(
required
)
{
final
call
=
RequiredValidator
().
call
(
value
);
if
(
validator
==
null
)
return
call
;
return
call
??
validator
.
call
(
value
);
}
return
validator
?.
call
(
value
);
},
builder:
(
field
)
{
final
state
=
field
as
_CustomFormInputState
;
final
decoration
=
const
InputDecoration
().
applyDefaults
(
Theme
.
of
(
field
.
context
).
inputDecorationTheme
,
);
return
UnmanagedRestorationScope
(
bucket:
field
.
bucket
,
child:
CustomInput
(
controller:
state
.
_effectiveController
,
label:
label
,
hintText:
hintText
,
required:
required
,
readOnly:
readOnly
,
obscureText:
obscureText
,
autofocus:
autofocus
,
onTap:
onTap
,
onIcon:
onIcon
,
iconData:
iconData
,
maxLines:
maxLines
,
error:
field
.
errorText
,
decoration:
decoration
,
inputFormatters:
inputFormatters
,
keyboardType:
keyboardType
,
onChanged:
(
value
)
{
field
.
didChange
(
value
);
onChanged
?.
call
(
value
);
},
),
);
},
);
@override
FormFieldState
<
String
>
createState
()
=>
_CustomFormInputState
();
}
class
_CustomFormInputState
extends
FormFieldState
<
String
>
{
RestorableTextEditingController
?
_controller
;
TextEditingController
get
_effectiveController
=>
widget
.
controller
??
_controller
!.
value
;
@override
CustomFormInput
get
widget
=>
super
.
widget
as
CustomFormInput
;
@override
void
restoreState
(
RestorationBucket
?
oldBucket
,
bool
initialRestore
)
{
super
.
restoreState
(
oldBucket
,
initialRestore
);
if
(
_controller
!=
null
)
_registerController
();
setValue
(
_effectiveController
.
text
);
}
void
_registerController
()
{
assert
(
_controller
!=
null
);
registerForRestoration
(
_controller
!,
'controller'
);
}
void
_createLocalController
([
TextEditingValue
?
value
])
{
assert
(
_controller
==
null
);
_controller
=
value
==
null
?
RestorableTextEditingController
()
:
RestorableTextEditingController
.
fromValue
(
value
);
if
(!
restorePending
)
_registerController
();
}
@override
void
initState
()
{
super
.
initState
();
if
(
widget
.
controller
==
null
)
{
final
editingValue
=
widget
.
initialValue
!=
null
?
TextEditingValue
(
text:
widget
.
initialValue
!)
:
null
;
_createLocalController
(
editingValue
);
}
else
{
widget
.
controller
!.
addListener
(
_onControllerChanged
);
}
}
@override
void
didUpdateWidget
(
CustomFormInput
oldWidget
)
{
super
.
didUpdateWidget
(
oldWidget
);
if
(
widget
.
controller
!=
oldWidget
.
controller
)
{
oldWidget
.
controller
?.
removeListener
(
_onControllerChanged
);
widget
.
controller
?.
addListener
(
_onControllerChanged
);
if
(
oldWidget
.
controller
!=
null
&&
widget
.
controller
==
null
)
{
_createLocalController
(
oldWidget
.
controller
!.
value
);
}
if
(
widget
.
controller
!=
null
)
{
setValue
(
widget
.
controller
!.
text
);
if
(
oldWidget
.
controller
==
null
)
{
unregisterFromRestoration
(
_controller
!);
_controller
!.
dispose
();
_controller
=
null
;
}
}
}
}
@override
void
dispose
()
{
widget
.
controller
?.
removeListener
(
_onControllerChanged
);
_controller
?.
dispose
();
super
.
dispose
();
}
@override
void
didChange
(
String
?
value
)
{
super
.
didChange
(
value
);
if
(
_effectiveController
.
text
!=
value
)
{
_effectiveController
.
text
=
value
??
''
;
}
}
@override
void
reset
()
{
_effectiveController
.
text
=
widget
.
initialValue
??
''
;
super
.
reset
();
}
void
_onControllerChanged
()
{
if
(
_effectiveController
.
text
!=
value
)
{
didChange
(
_effectiveController
.
text
);
}
}
}
class
CustomInput
extends
StatelessWidget
{
final
TextEditingController
?
controller
;
final
String
?
label
;
final
String
?
helper
;
final
String
?
hintText
;
final
String
?
error
;
final
bool
required
;
final
bool
readOnly
;
final
bool
obscureText
;
final
IconData
?
iconData
;
final
int
?
minLines
;
final
int
?
maxLines
;
final
void
Function
()?
onTap
;
final
void
Function
()?
onIcon
;
final
ValueChanged
<
String
>?
onChanged
;
final
InputDecoration
decoration
;
final
TextInputType
?
keyboardType
;
final
bool
autofocus
;
final
List
<
TextInputFormatter
>?
inputFormatters
;
const
CustomInput
({
Key
?
key
,
this
.
controller
,
this
.
label
,
this
.
helper
,
this
.
hintText
,
this
.
error
,
this
.
required
=
false
,
this
.
readOnly
=
false
,
this
.
obscureText
=
false
,
this
.
onTap
,
this
.
onIcon
,
this
.
iconData
,
this
.
onChanged
,
this
.
decoration
=
const
InputDecoration
(),
this
.
minLines
,
this
.
maxLines
=
1
,
this
.
keyboardType
,
this
.
autofocus
=
false
,
this
.
inputFormatters
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
final
theme
=
Theme
.
of
(
context
);
final
decorationTheme
=
theme
.
inputDecorationTheme
;
return
Column
(
mainAxisSize:
MainAxisSize
.
min
,
crossAxisAlignment:
CrossAxisAlignment
.
stretch
,
children:
[
if
(
label
!=
null
||
required
)
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
(
decorationTheme
.
contentPadding
?.
horizontal
??
0
)
/
2
,
vertical:
10
.
w
,
).
copyWith
(
top:
0
),
child:
RichText
(
text:
TextSpan
(
text:
label
,
style:
decorationTheme
.
labelStyle
,
children:
[
if
(
required
)
TextSpan
(
text:
label
!=
null
?
' *'
:
'*'
,
style:
const
TextStyle
(
color:
AppTheme
.
error
),
),
],
),
),
),
DecoratedBox
(
decoration:
const
BoxDecoration
(
boxShadow:
[
// BoxShadow(
// color: theme.colorScheme.shadow,
// offset: Offset(0, 20.w),
// blurRadius: 10.w,
// spreadRadius: -10.w,
// ),
],
),
child:
TextField
(
autofocus:
autofocus
,
controller:
controller
,
readOnly:
readOnly
,
onTap:
onTap
,
obscureText:
obscureText
,
onChanged:
onChanged
,
minLines:
minLines
,
maxLines:
maxLines
,
inputFormatters:
inputFormatters
,
keyboardType:
keyboardType
,
style:
TextStyle
(
// fontFamily: 'Sans',
fontSize:
15
.
w
,
height:
1.2
,
// fontWeight: FontWeight.w600,
),
decoration:
decoration
.
copyWith
(
hintText:
hintText
,
hintStyle:
const
TextStyle
(
fontWeight:
FontWeight
.
normal
,
color:
Colours
.
c9
),
suffixIconConstraints:
const
BoxConstraints
(),
suffixIcon:
_suffixIcon
(
decorationTheme
),
),
),
),
AnimatedSize
(
duration:
const
Duration
(
milliseconds:
180
),
alignment:
Alignment
.
topCenter
,
child:
error
!=
null
?
Padding
(
padding:
EdgeInsets
.
only
(
top:
10
.
w
),
// child: CustomAlert.error(
// size: CustomAlertSize.mini,
// text: Text(error!),
// ),
)
:
const
SizedBox
.
shrink
(),
),
if
(
helper
!=
null
)
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
(
decorationTheme
.
contentPadding
?.
horizontal
??
0
)
/
2
,
vertical:
10
.
w
,
).
copyWith
(
bottom:
0
),
child:
Text
(
helper
!,
style:
decorationTheme
.
helperStyle
,
),
)
],
);
}
Widget
?
_suffixIcon
(
InputDecorationTheme
decorationTheme
)
{
if
(
iconData
==
null
)
return
null
;
return
Padding
(
padding:
EdgeInsetsDirectional
.
only
(
end:
(
decorationTheme
.
contentPadding
?.
horizontal
??
0
)
/
2
,
),
child:
GestureDetector
(
onTap:
onIcon
,
child:
Icon
(
iconData
!,
size:
24
.
w
),
),
);
}
}
class
CustomInputSearch
extends
StatelessWidget
{
final
IconData
iconData
;
final
String
?
hintText
;
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论