iOS登录界面和注册界面
一、登录和注册界面实现效果图:
二、实现原理
1、输入框的实现原理:把两个无边框的UITextField添加到一个作为背景的UIView上,然后重写UIView的 :
-(
void
)drawRect:(
CGRect
)rect 方法,用Quartz2D画出中间的那条分隔线。然后再设置背景UIView为带边框的圆角就可以实现上面的效果了。
注意:为了方便要把textField添加到背景view上,然后设置textField的frame值时根据View的frame值计算简单些。
三、直接上代码
注:由于代码是直接从自己的小项目中粘贴过来的,有些功能可能你用不到,可以自行删减。
1、我前面有一篇博客讲了如何设置textField的占位符和左边的图片,这里就不再赘述。
下面直接上代码:
新建一个BasicTextField类继承自UITextField
BasicTextField.h文件:
#import
@interface
BasicTextField :
UITextField
@end
BasicTextField.m文件:
#import
"BasicTextField.h"
@implementation
BasicTextField
//
重写
leftView
的
X
值
- (
CGRect
)leftViewRectForBounds:(
CGRect
)bounds{
CGRect
iconRect = [
super
leftViewRectForBounds
:bounds];
iconRect.
origin
.
x
+=
10
;
return
iconRect;
}
//
重写占位符的
x
值
- (
CGRect
)placeholderRectForBounds:(
CGRect
)bounds{
CGRect
placeholderRect = [
super
placeholderRectForBounds
:bounds];
placeholderRect.
origin
.
x
+=
1
;
return
placeholderRect;
}
//
重写文字输入时的
x
值
- (
CGRect
)editingRectForBounds:(
CGRect
)bounds{
CGRect
editingRect = [
super
editingRectForBounds
:bounds];
editingRect.
origin
.
x
+=
20
;
return
editingRect;
}
//
重写文字显示时的
x
值
- (
CGRect
)textRectForBounds:(
CGRect
)bounds{
CGRect
textRect = [
super
editingRectForBounds
:bounds];
textRect.origin.x += 20;
return textRect;
}
@end
2、新建
LoginBackgroundView类继承自UIView,作为textField的输入框的背景。
LoginBackgroundView.h文件:
#import
@interface
LoginBackgroundView :
UIView
@end
LoginBackgroundView.m文件:
#define mianBodyColor(r, g, b) [UIColor colorWithRed:r/
255.0f
green:g/
255.0f
blue:b/
255.0f
alpha:
1
]
#import "LoginBackgroundView.h"
@implementation
LoginBackgroundView
//
重写此方法,用
Quartz2D
画出中间分割线
-(
void
)drawRect:(
CGRect
)rect{
CGContextRef
context =
UIGraphicsGetCurrentContext
();
CGContextSetLineWidth
(context,
0.7
);
CGContextBeginPath
(context);
CGContextMoveToPoint
(context,
0
,
40
);
CGContextAddLineToPoint
(context,
self
.
frame
.
size
.
width
,
40
);
CGContextClosePath
(context);
[
mianBodyColor
(
207
,
207
,
207
)
setStroke
];
CGContextStrokePath
(context);
}
3、新建
LoginView类继承自UIView,把这个
LoginView设置为控制器的rootView即可。
LoginView.h文件:
#import
@protocol
LoginViewDelegate <
NSObject
>
@interface
LoginView :
UIView
@end
LoginView.m文件:
#define textFieldColor(r, g, b) [UIColor colorWithRed:r/
255.0f
green:g/
255.0f
blue:b/
255.0f
alpha:
1
]
#define mianBodyColor(r, g, b) [UIColor colorWithRed:r/
255.0f
green:g/
255.0f
blue:b/
255.0f
alpha:
1
]
#import
"LoginView.h"
#import
"BasicTextField.h"
#import
"LoginBackgroundView.h"
@interface
LoginView
()<
UITextFieldDelegate
>
@property
(
nonatomic
,
strong
)
LoginBackgroundView
*backgroundView;
@property
(
nonatomic
,
strong
)
BasicTextField
*userTextField;
@property
(
nonatomic
,
strong
)
BasicTextField
*passwordTextField;
@property
(
nonatomic
,
strong
)
UIButton
*loginButton;
@property
(
nonatomic
,
strong
)
UIActivityIndicatorView
*logioningActivityIndicatorView;
@property
(
nonatomic
,
assign
)
BOOL
isUserEmpty;
@property
(
nonatomic
,
assign
)
BOOL
isPasswordEmpty;
@end
@implementation
LoginView
- (
id
)initWithFrame:(
CGRect
)frame{
self
= [
super
initWithFrame
:frame];
if
(
self
) {
[
self
addLoginBackgroundView
:frame];
[
self
customAllButtons
:frame];
[
self
customUserTextField
:
self
.
backgroundView
.
frame
];
[
self
customPasswordTextField
:
self
.
backgroundView
.
frame
];
}
return
self
;
}
//添加textField的背景View
- (
void
)addLoginBackgroundView:(
CGRect
)frame{
CGFloat
backgroundX =
30
;
CGFloat
backgroundY =
160
;
CGFloat
backgroundW = frame.
size
.
width
-
60
;
CGFloat
backgroundH =
80
;
self
.
backgroundView
= [[
LoginBackgroundView
alloc
]
initWithFrame
:
CGRectMake
(backgroundX, backgroundY, backgroundW, backgroundH)];
[
self
.
backgroundView
setBackgroundColor
:[
UIColor
whiteColor
]];
[
self
.
backgroundView
.
layer
setCornerRadius
:
5.0
];
[
self
.
backgroundView
.
layer
setBorderWidth
:
1.0
];
[
self
.
backgroundView
.
layer
setBorderColor
:
textFieldColor
(
207
,
207
,
207
).
CGColor
];
[
self
addSubview
:
self
.
backgroundView
];
}
- (
void
)customAllButtons:(
CGRect
)frame{
//
返回
button
UIButton
*backButton = [[
UIButton
alloc
]
initWithFrame
:
CGRectMake
(
19
,
35
,
22
,
22
)];
[backButton
setBackgroundImage
:[
UIImage
imageNamed
:
@"back"
]
forState
:
UIControlStateNormal
];
[backButton
addTarget
:
self
action
:
@selector
(clickTheBackButton:)
forControlEvents
:
UIControlEventTouchDown
];
[
self
addSubview
:backButton];
//
登录
button
CGFloat
loginButtonX =
30
;
CGFloat
loginButtonY =
250
;
CGFloat
loginButtonW = frame.
size
.
width
-
60
;
self
.
loginButton
= [[
UIButton
alloc
]
initWithFrame
:
CGRectMake
(loginButtonX, loginButtonY, loginButtonW,
40
)];
[
self
.
loginButton
setEnabled
:
NO
];
self
.
loginButton
.
titleLabel
.
alpha
=
0.5
;
[
self
.
loginButton
.
layer
setCornerRadius
:
3.0
];
[
self
.
loginButton
setTitle
:
@"
登录
"
forState
:
UIControlStateNormal
];
[
self
.
loginButton
setTitleColor
:[
UIColor
whiteColor
]
forState
:
UIControlStateReserved
];
[
self
.
loginButton
setBackgroundColor
:
mianBodyColor
(
133
,
122
,
250
)];
[
self
.
loginButton
addTarget
:
self
action
:
@selector
(clickLoginButton:)
forControlEvents
:
UIControlEventTouchDown
];
[
self
addSubview
:
self
.
loginButton
];
//
忘记密码
CGFloat
forgetButtonW =
73
;
CGFloat
forgetButtonX = loginButtonX + loginButtonW - forgetButtonW;
CGFloat
forgetButtonY =
0.916
* (loginButtonY +
100
);
CGFloat
forgetButtonH =
20
;
UIButton
*forgetButton = [[
UIButton
alloc
]
initWithFrame
:
CGRectMake
(forgetButtonX, forgetButtonY, forgetButtonW, forgetButtonH)];
[forgetButton
addTarget
:
self
action
:
@selector
(clickForgetpasswordTextFieldButton:)
forControlEvents
:
UIControlEventTouchDown
];
[forgetButton
setTitle
:
@"
忘记密码
?"
forState
:
UIControlStateNormal
];
[forgetButton.
titleLabel
setFont
:[
UIFont
systemFontOfSize
:
14
]];
[forgetButton
setTitleColor
:
textFieldColor
(
74
,
74
,
74
)
forState
:
UIControlStateNormal
];
[
self
addSubview
:forgetButton];
}
- (
void
)customUserTextField:(
CGRect
)frame{
self
.
userTextField
= [[
BasicTextField
alloc
]
initWithFrame
:
CGRectMake
(
0
,
0
, frame.
size
.
width
,
40
)];
self
.
userTextField
.
keyboardType
=
UIKeyboardTypeNumberPad
;
self
.
userTextField
.
delegate
=
self
;
self
.
userTextField
.
tag
=
7
;
self
.
userTextField
.
placeholder
=
@"
请输入账号
"
;
[
self
.
userTextField
setFont
:[
UIFont
systemFontOfSize
:
14
]];
UIImageView
*userTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"userIcon"
]];
self
.
userTextField
.
leftView
= userTextFieldImage;
self
.
userTextField
.
leftViewMode
=
UITextFieldViewModeAlways
;
self
.
userTextField
.
clearButtonMode
=
UITextFieldViewModeAlways
;
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(userTextFieldDidChange)
name
:
UITextFieldTextDidChangeNotification
object
:
self
.
userTextField
];
self
.
isPasswordEmpty
=
YES
;
[
self
.
backgroundView
addSubview
:
self
.
userTextField
];
}
- (
void
)customPasswordTextField:(
CGRect
)frame{
self
.
passwordTextField
= [[
BasicTextField
alloc
]
initWithFrame
:
CGRectMake
(
0
,
40
, frame.
size
.
width
,
40
)];
self
.
passwordTextField
.
delegate
=
self
;
self
.
passwordTextField
.
tag
=
11
;
self
.
passwordTextField
.
placeholder
=
@"
请输入密码
"
;
[
self
.
passwordTextField
setFont
:[
UIFont
systemFontOfSize
:
14
]];
UIImageView
*passwordTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"passwordIcon"
]];
self
.
passwordTextField
.
leftView
= passwordTextFieldImage;
self
.
passwordTextField
.
leftViewMode
=
UITextFieldViewModeAlways
;
self
.
passwordTextField
.
clearButtonMode
=
UITextFieldViewModeAlways
;
self.passwordTextField.secureTextEntry = YES;
//设置监听
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(passwordTextFieldDidChange)
name
:
UITextFieldTextDidChangeNotification
object
:
self
.
passwordTextField
];
self
.
isUserEmpty
=
YES
;
[
self
.
backgroundView
addSubview
:
self
.
passwordTextField
];
}
- (
void
)addLogioningActivityIndicatorView{
CGFloat
logioningActivityIndicatorViewX =
self
.
loginButton
.
frame
.
origin
.
x
+
80
;
CGFloat
logioningActivityIndicatorViewY =
self
.
loginButton
.
frame
.
origin
.
y
;
CGFloat
logioningActivityIndicatorViewWH =
self
.
loginButton
.
frame
.
size
.
height
;
self
.
logioningActivityIndicatorView
= [[
UIActivityIndicatorView
alloc
]
initWithFrame
:
CGRectMake
(logioningActivityIndicatorViewX, logioningActivityIndicatorViewY, logioningActivityIndicatorViewWH, logioningActivityIndicatorViewWH)];
[
self
addSubview
:
self
.
logioningActivityIndicatorView
];
}
- (void)clickLoginButton:(id)sender{
[
self
.
loginButton
setTitle
:
@"
登录中
..."
forState
:
UIControlStateNormal
];
[
self
addLogioningActivityIndicatorView
];
[self.logioningActivityIndicatorView startAnimating];
//当点击登录按钮时,账号和密码输入框放弃第一响应者,此时键盘退出
[
self
.
userTextField
resignFirstResponder
];
[
self
.
passwordTextField
resignFirstResponder
];
}
- (void)clickForgetpasswordTextFieldButton:(id)sender{
//点击忘记密码button后需要执行的代码
}
- (void)clickTheBackButton:(id)sender{
//点击左上角圈叉按钮返回上一界面
}
#pragma makr --UITextFieldDelegate
//UITextField的代理方法,点击键盘return按钮退出键盘
- (
BOOL
)textFieldShouldReturn:(
UITextField
*)textField{
[
self
.
passwordTextField
resignFirstResponder
];
return
YES
;
}
//此处为userTextField的监听方法,后面会细讲,主要是实时监听textField值的变化
- (
void
)userTextFieldDidChange{
if
(
self
.
userTextField
.
text
.
length
>
0
) {
UIImageView
*loginTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"userIconEdited"
]];
self
.
userTextField
.
leftView
= loginTextFieldImage;
self
.
isUserEmpty
=
NO
;
if
(
self
.
isPasswordEmpty
==
NO
) {
self
.
loginButton
.
titleLabel
.
alpha
=
1
;
[
self
.
loginButton
setEnabled
:
YES
];
}
}
else
{
UIImageView
*loginTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"userIcon"
]];
self
.
userTextField
.
leftView
= loginTextFieldImage;
[
self
.
loginButton
setTitle
:
@"
登录
"
forState
:
UIControlStateNormal
];
self
.
loginButton
.
titleLabel
.
alpha
=
0.5
;
[
self
.
loginButton
setEnabled
:
NO
];
self
.
isUserEmpty
=
YES
;
[
self
.
logioningActivityIndicatorView
stopAnimating
];
}
}
//passwordTextField的监听方法
- (
void
)passwordTextFieldDidChange{
if
(
self
.
passwordTextField
.
text
.
length
>
0
) {
self
.
isPasswordEmpty
=
NO
;
UIImageView
*loginTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"passwordIconEdited"
]];
self
.
passwordTextField
.
leftView
= loginTextFieldImage;
if
(
self
.
isUserEmpty
==
NO
){
self
.
loginButton
.
titleLabel
.
alpha
=
1
;
[
self
.
loginButton
setEnabled
:
YES
];
}
}
else
{
self
.
isPasswordEmpty
=
YES
;
UIImageView
*loginTextFieldImage = [[
UIImageView
alloc
]
initWithImage
:[
UIImage
imageNamed
:
@"passwordIcon"
]];
self
.
passwordTextField
.
leftView
= loginTextFieldImage;
[
self
.
loginButton
setTitle
:
@"
登录
"
forState
:
UIControlStateNormal
];
self
.
loginButton
.
titleLabel
.
alpha
=
0.5
;
[
self
.
loginButton
setEnabled
:
NO
];
[
self
.
logioningActivityIndicatorView
stopAnimating
];
}
}
//点击界面空白处退出键盘
- (
void
)touchesBegan:(
NSSet
<
UITouch
*> *)touches withEvent:(
UIEvent
*)event{
[
self
.
userTextField
resignFirstResponder
];
[
self
.
passwordTextField
resignFirstResponder
];
}
@end
四、登录界面一些与用户交互的细节问题处理:
1、可以看到当选中账号输入框时,左边的图片没有变化;而输入字符时图片就会变为紫色。我开始是用UITextField的代理方法,但是都达不到预想的效果,最后用注册通知监听器的方式实现了实时监测textField的改变。即用下面的方法:
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(userTextFieldDidChange)
name
:
UITextFieldTextDidChangeNotification
object
:
self
.
userTextField
];
observer:监听器,即谁要接收这个通知。
Selector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入。
name:通知的名称,如果为nil,无论通知的名称是什么,监听器都能收到这个通知。
object:通知发布者,如果object和name都为nil,监听器收到所有的通知。
2、
- (
void
)userTextFieldDidChange:所以可以在这个方法能内写入当userTextField内的值被改变后,需要执行的代码。例如上面当userTextField的输入数字时右侧图片变为紫色的图片。
3、关于UItextField的代理方法,可以根据需求自行选择。
可以看到当账号和密码输入框都被输入后,登录按钮此时变成可以点击了。
这个就是在
- (
void
)userTextFieldDidChange:方法中设置的。
self
.
loginButton
.
titleLabel
.
alpha
=
1
;
//设置登录的titleLabel的透明度为1(初始值为0.5)
[self.loginButton setEnabled:YES];
//设置登录按钮可以被点击(初始值为NO)
登录界面看起来简单,但是很多不起眼的功能就可能影响到用户体验,所以做好登录和注册界面的重要性不言而喻。
4、退出键盘
//当点击空白处退出键盘
- (
void
)touchesBegan:(
NSSet
<
UITouch
*> *)touches withEvent:(
UIEvent
*)event{
[
self
.
userTextField
resignFirstResponder
];
[
self
.
passwordTextField
resignFirstResponder
];
}
resign这个单词有辞职的意思,这里就是某某放弃第一响应者的意思;如果个是点击userTextField调出的键盘,
userTextField就是键盘的第一响应者,当
userTextField放弃第一响应后,键盘退出。同理是谁叫出了键盘,就谁调用
resignFirstResponderl来退出键盘。而在哪何时退出键盘就看交互需要了。
四、注册界面的实现方式和登录界面一样,注册界面能的更多功能都可以根据这些来实现。这里就不再帖代码了。