第二天任務(wù):
項(xiàng)目主框架搭建完畢后,就可以從各個(gè)模塊入手完成項(xiàng)目从橘,這里從最簡(jiǎn)單的關(guān)注模塊開(kāi)始念赶。
- 關(guān)注頁(yè)面的搭建
- 登錄界面的搭建
- 方法抽取與知識(shí)點(diǎn)總結(jié)
一. 關(guān)注頁(yè)面的搭建
關(guān)注頁(yè)面我們這里只做未登錄的。因?yàn)榈顷懸院蟛趴梢钥吹疥P(guān)注了哪些用戶或者頻道恰力。
關(guān)注頁(yè)面比較簡(jiǎn)單叉谜,我們這里使用xib創(chuàng)建界面,比較好的方法是先設(shè)置好中間label的位置踩萎,然后根據(jù)中間label的位置來(lái)確定上面圖片和下面按鈕的位置停局,這里不在贅述了,只有一個(gè)注意點(diǎn)香府,當(dāng)我們?cè)趚ib中想要讓label的文字換行時(shí)董栽,需要使用option+enter組合鍵進(jìn)行換行,使用"\n"是不管用的企孩。
另外如果xib不是我們創(chuàng)建controller同時(shí)創(chuàng)建的锭碳,需要做兩步操作與之前創(chuàng)建好的controller創(chuàng)建關(guān)聯(lián)。
第一步:
第二步:
如果xib是在創(chuàng)建controller的同時(shí)就創(chuàng)建好了的勿璃,系統(tǒng)會(huì)自動(dòng)幫我們做這兩件事擒抛。
二. 登陸界面的搭建
首先涉及到登錄界面狀態(tài)欄顏色的問(wèn)題,我們需要將狀態(tài)欄顏色改為白色补疑,可以在控制器內(nèi)實(shí)現(xiàn)方法更改
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
關(guān)于修改狀態(tài)欄顏色更詳細(xì)的介紹可以去看狀態(tài)欄的管理
因?yàn)榈顷懡缑婧芏嗟胤蕉夹枰玫狡缁Γ绮榭搓P(guān)注時(shí)需要登陸,添加關(guān)注時(shí)也需要先登錄莲组,發(fā)表新帖時(shí)也要登陸诊胞,登錄界面不屬于任何一個(gè)模塊,同時(shí)很多地方也要用到它锹杈,所以將它寫在Other文件夾中撵孤,另外登錄界面一定是Mode出來(lái)的,一旦判斷需要登錄才可以進(jìn)行操作就Mode出登錄界面嬉橙。
通過(guò)觀察登錄界面早直,我們發(fā)現(xiàn)背景圖片是提供好的寥假,因此需要使用UIImageVIew設(shè)置背景圖片市框,另外可以將登陸界面分為三部分,每一部分用UIView當(dāng)載體存放糕韧,只要View內(nèi)部的控件布局好了枫振,只需要管理三個(gè)View的位置大小幾個(gè),方便于我們布局和管理萤彩。
1. 快速登錄按鈕的布局
首先快速登錄方便的兩條線都是圖片粪滤,只需要簡(jiǎn)單設(shè)置frame即可,下面的三個(gè)快速登錄明顯是按鈕雀扶,但是我們知道杖小,UIButton默認(rèn)的是UIImage在左邊肆汹,titleLabel在右邊,那么我們需要使默認(rèn)的布局改為UIImage在上面予权,titleLabel在下面昂勉。
方法一:可以通過(guò)設(shè)置UIImage和titleLabel的contentInset調(diào)整他們的位置,但是這種方法十分繁瑣扫腺,需要我們耗費(fèi)很長(zhǎng)時(shí)間去慢慢調(diào)整岗照,contentInset一般用在簡(jiǎn)單修改控件內(nèi)內(nèi)容位置。不建議在這里使用笆环。
方法二:自定義button 并且重寫layoutSubviews攒至。如果button是從storyboard或者xib加載會(huì)調(diào)用aweakfromnib方法,我們可以在aweakFromNib中對(duì)控件進(jìn)行一些統(tǒng)一的設(shè)置躁劣,在layoutSubviews中設(shè)置控件內(nèi)內(nèi)容的位置迫吐。
-(void)awakeFromNib
{
[super awakeFromNib];
// 可以在這里對(duì)button進(jìn)行一些統(tǒng)一的設(shè)置 文字居中
self.titleLabel.textAlignment = NSTextAlignmentCenter;
}
-(void)layoutSubviews
{
[super layoutSubviews];
// 修改imageView和titleLabel的位置
self.imageView.cl_y = 0;
self.imageView.cl_centerX = self.cl_width*0.5;
self.titleLabel.cl_x = 0;
self.titleLabel.cl_width = self.cl_width;
self.titleLabel.cl_y = self.imageView.cl_height;
self.titleLabel.cl_height = self.cl_height - self.imageView.cl_height;
}
注意:一定要記得調(diào)用父類的對(duì)應(yīng)的方法。
關(guān)于三個(gè)button添加約束的方法:可以先設(shè)置中間按鈕約束习绢,然后約束三個(gè)按鈕相互之間的間距為0渠抹。左邊按鈕與屏幕左邊間距為0,右邊按鈕與屏幕右邊為0闪萄,高度相同梧却。最后約束三個(gè)按鈕平分屏幕寬度。
關(guān)于添加約束的方法有很多種败去,只要確定控件位置寬高就可以約束成功放航,需要細(xì)心一步一步來(lái),即使約束失敗也沒(méi)有關(guān)系圆裕,刪了重新約束即可广鳍,只要多試幾次慢慢就會(huì)掌握。
2. ?號(hào)和注冊(cè)賬號(hào)布局
第一部分的布局非常簡(jiǎn)單吓妆,這里有一個(gè)注意點(diǎn):UIButton 當(dāng)只有一張圖片顯示的時(shí)候 赊时,建議使用image而不要設(shè)置背景圖片,因?yàn)楸尘皥D片的設(shè)置會(huì)看按鈕有多大就將圖片拉伸到大行拢,圖片會(huì)被拉伸祖秒。當(dāng)設(shè)置image時(shí)圖片不會(huì)變形,并且可以放大按鈕的點(diǎn)擊范圍舟奠。所以這里的?號(hào)選擇設(shè)置UIButton的image竭缝,而不是backgroundImage。
3. 賬號(hào)密碼輸入框登錄按鈕布局
這部分的布局也很簡(jiǎn)單沼瘫,這里圖片中提供了textfield的背景圖片抬纸,所以這里我們先用UIImageView將背景圖片顯示,然后在在圖片上添加一個(gè)透明的textfield耿戚,所以textfield的樣式需要選擇無(wú)邊框隱形的
另外登陸按鈕需要設(shè)置Type為Custom湿故,如果是System當(dāng)我們按下的時(shí)候會(huì)自動(dòng)做出處理如下圖阿趁,并且會(huì)自動(dòng)將字體渲染成藍(lán)色
設(shè)置為Custom就會(huì)在高亮?xí)r顯示我們?cè)O(shè)置的背景圖片,并且不會(huì)渲染字體顏色坛猪。
設(shè)置button按鈕的圓角
self.loginBtn.layer.cornerRadius = 5;
self.loginBtn.layer.masksToBounds = YES;
也可以通過(guò)KVC賦值來(lái)設(shè)置
[self.loginBtn setValue:@5 forKeyPath:@"layer.cornerRadius"];
[self.loginBtn setValue:@YES forKeyPath:@"layer.masksToBunds"];
當(dāng)然在xib中也可以通過(guò)KVC來(lái)賦值
因?yàn)樾枰延匈~號(hào)和注冊(cè)賬號(hào)兩個(gè)界面的切換的動(dòng)畫(huà)效果歌焦,所以將兩個(gè)兩個(gè)輸入界面拼接起來(lái),如圖所示
如果想點(diǎn)擊button實(shí)現(xiàn)動(dòng)畫(huà)砚哆,我們需要修改view左邊線與左邊屏幕的約束独撇,獲得約束屬性,將View左邊線與屏幕左邊的距離從0修改為負(fù)一個(gè)屏幕寬度躁锁,當(dāng)然也需要添加登陸View右邊線和注冊(cè)View左邊線距離為0纷铣。同時(shí)修改button的title。
- (IBAction)showLogionOrRegister:(UIButton *)sender {
[self.view endEditing:YES];
if (self.leftMargin.constant) {
self.leftMargin.constant = 0;
[sender setTitle:@"注冊(cè)賬號(hào)" forState:UIControlStateNormal];
}else{
self.leftMargin.constant = -self.view.cl_width;
[sender setTitle:@"已有賬號(hào)战转?" forState:UIControlStateNormal];
}
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
這里難點(diǎn)在于約束的添加和修改自己細(xì)心修改就會(huì)成功搜立,當(dāng)然也可以通過(guò)代碼修改兩個(gè)View的frame來(lái)達(dá)到動(dòng)畫(huà)替換效果。
4. textfield光標(biāo)顏色的改變和占位文字顏色改變
首先槐秧,這里有四個(gè)textfield啄踊,每一個(gè)都需要設(shè)置光標(biāo)顏色和占位文字顏色,所以我們通過(guò)自定義textfield來(lái)實(shí)現(xiàn)刁标,然后再awakeFromNib中設(shè)置一次就可以颠通。
textfield的光標(biāo)的顏色我們可以通過(guò)設(shè)置tintColor來(lái)設(shè)置
self.tintColor = [UIColor whiteColor];
占位文字的顏色修改
方法一:使用富文本修改占位文字顏色
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
attributes[NSForegroundColorAttributeName] = [UIColor whiteColor];
self.attributedPlaceholder = [[NSAttributedString alloc]initWithString:self.placeholder attributes:attributes];
方法二:通過(guò)重寫drawRect方法來(lái)重繪站位文字并修改站位文字顏色
-(void)drawPlaceholderInRect:(CGRect)rect
{
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
attributes[NSFontAttributeName] = self.font;
attributes[NSForegroundColorAttributeName] = [UIColor whiteColor];
// 從一個(gè)起點(diǎn)開(kāi)始繪畫(huà)
CGPoint placeholderPoint = CGPointMake(0, (self.cl_height - self.font.lineHeight)*0.5);
[self.placeholder drawAtPoint:placeholderPoint withAttributes:attributes];
// 畫(huà)到一個(gè)范圍
// self.placeholder drawInRect:<#(CGRect)#> withAttributes:<#(nullable NSDictionary<NSString *,id> *)#>
}
方法三:直接修改內(nèi)部占位文字Label的文字顏色
其實(shí)textfield內(nèi)部有一個(gè)placeholderLabel,用來(lái)顯示占位文字膀懈。我們可以通過(guò)圖形化調(diào)試工具中看到textfield內(nèi)部結(jié)構(gòu)
// UILabel *label = [self valueForKeyPath:@"placeholderLabel"];
// label.textColor = [UIColor whiteColor];
// 或者直接設(shè)置顏色
[self setValue:[UIColor grayColor] forKeyPath:@"placeholderLabel.textColor"];
我們可以通過(guò)RunTime找到textfield內(nèi)部有placeholderLabel私有屬性
//先使用運(yùn)行時(shí)找到私有屬性
unsigned int count;
Ivar *ivarList = class_copyIvarList([UITextField class], &count);
for (int i = 0; i < count; i ++) {
Ivar ivar = ivarList[i];
NSLog(@"%s",ivar_getName(ivar));
}
free(ivarList);
使用運(yùn)行時(shí)打印textfield的全部屬性顿锰,我們可以找到placeholderLabel
5. 切換占位文字顏色顏色
當(dāng)textfield處于未編輯狀態(tài)時(shí),占位文字顏色為灰色启搂,當(dāng)textfield處于編輯狀態(tài)時(shí)硼控,占位文字顏色為白色
方法一:addTarget
因?yàn)閠extfield繼承于UIControl,所以可以使用addTarget監(jiān)聽(tīng)textfield編輯狀態(tài)的改變
[self addTarget:self action:@selector(editingDidBegin) forControlEvents:UIControlEventEditingDidBegin];
[self addTarget:self action:@selector(editingDidEnd) forControlEvents:UIControlEventEditingDidEnd];
然后在方法中修改占位文字顏色
-(void)editingDidBegin
{
[self setValue:[UIColor whiteColor] forKeyPath:@"placeholderLabel.textColor"];
}
-(void)editingDidEnd
{
[self setValue:[UIColor grayColor] forKeyPath:@"placeholderLabel.textColor"];
}
方法二:使用代理
使用代理是有風(fēng)險(xiǎn)的,當(dāng)我們?cè)诳刂破髦性俅卧O(shè)置textfield的代理的時(shí)候就會(huì)發(fā)生錯(cuò)誤
textField.delegate = self;
#pragma mark - <UITextFieldDelegate>
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
//開(kāi)始編輯時(shí)
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// 結(jié)束編輯時(shí)
}
方法三:使用通知
// object:self對(duì)象發(fā)出UITextFieldTextDidBeginEditingNotification通知就調(diào)用 self(監(jiān)聽(tīng)器)的editingDidBegin方法
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(editingDidBegin) name:UITextFieldTextDidBeginEditingNotification object:self];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(editingDidEnd) name:UITextFieldTextDidEndEditingNotification object:self];
通知還有一種方法胳赌,可直接在block中寫要執(zhí)行的操作
// object:self對(duì)象發(fā)出名字為name的通知牢撼,就執(zhí)行block里面的代碼,可以修改block執(zhí)行的線程疑苫,需要保存返回值熏版,等不用的時(shí)候釋放
self.observer = [[NSNotificationCenter defaultCenter]addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
// 監(jiān)聽(tīng)到通知執(zhí)行操作
}];
通知需要移除
-(void)dealloc
{
[[NSNotificationCenter defaultCenter]removeObserver:self];
// 使用block處理監(jiān)聽(tīng)方法時(shí)移除監(jiān)聽(tīng)
[[NSNotificationCenter defaultCenter]removeObserver:self.observer];
}
方法四:重寫UITextField的 becomeFirstResponder 和 resignFirstResponder 方法
//調(diào)用時(shí)刻 : 成為第一響應(yīng)者(開(kāi)始編輯\彈出鍵盤\獲得焦點(diǎn))
- (BOOL)becomeFirstResponder
{
return [super becomeFirstResponder];
}
//調(diào)用時(shí)刻 : 不做第一響應(yīng)者(結(jié)束編輯\退出鍵盤\失去焦點(diǎn))
- (BOOL)resignFirstResponder
{
return [super resignFirstResponder];
}
6. 一些事件的添加和實(shí)現(xiàn)
至此,界面已經(jīng)基本布局完成缀匕,接下來(lái)就是給按鈕添加點(diǎn)擊事件纳决。
點(diǎn)擊?號(hào)按鈕dismiss登錄界面
// 關(guān)閉按鈕點(diǎn)擊事件
- (IBAction)closeBtn {
[self dismissViewControllerAnimated:YES completion:nil];
}
點(diǎn)擊空白區(qū)域使textfield退出第一響應(yīng)者
// 空白區(qū)域點(diǎn)擊也關(guān)閉
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
三. 方法的抽取和一些知識(shí)點(diǎn)總結(jié)
1. uitextfield添加分類碰逸,直接修改站位文字顏色乡小。
之前提到,為了避免重復(fù)多次的給textfield設(shè)置光標(biāo)顏色和占位文字顏色摘刑,我們使用自定義textfield糜俗,在awakeFromNib中統(tǒng)一設(shè)置即可。另外設(shè)置占位文字顏色寂纪,以后再其他模塊中或者其他項(xiàng)目中都有可能頻繁使用湃番,因此給textfield添加分類夭织,使占位文字的設(shè)置更加方便。
#import "UITextField+CLExtension.h"
static NSString * const CLPlaceholderColorKey = @"placeholderLabel.textColor";
@implementation UITextField (CLExtension)
-(void)setPlaceholderColor:(UIColor *)placeholderColor
{
// 提前設(shè)置占位文字吠撮,讓他提前創(chuàng)建placeholderLabel 需要有一個(gè)空格尊惰,不然起不到作用
// 防止我們?cè)谕饷媸褂玫臅r(shí)候 先設(shè)置占位文字圖片,在設(shè)置占位文字泥兰。導(dǎo)致占位文字顏色設(shè)置失敗
// 需要判斷placeholder是否有值弄屡,如果沒(méi)有我們才需要提前去創(chuàng)建
// 我們可以先保留現(xiàn)在的placeholder,當(dāng)現(xiàn)在的為空的時(shí)候,我們先將他保存起來(lái)鞋诗,然后設(shè)置為@" "膀捷,這時(shí)占位文字的顏色也會(huì)設(shè)置,然后在將占位文字的內(nèi)容修改回為空削彬,此時(shí)即使我們只設(shè)置了占位文字顏色全庸,沒(méi)有設(shè)置占位文字,打印占位文字為null
// NSString *oldplaceholder = self.placeholder;
// self.placeholder = @" ";
// self.placeholder = oldplaceholder;
// 只有一開(kāi)始為空的時(shí)候才需要先創(chuàng)建placeholderLabel
if (self.placeholder.length == 0) {
self.placeholder = @" ";
self.placeholder = nil;
}
// 恢復(fù)到默認(rèn)顏色
if (placeholderColor == nil) {
// 系統(tǒng)默認(rèn)顏色GRB值
placeholderColor = [UIColor colorWithRed:0 green:0 blue:0.0980392 alpha:0.22];
}
[self setValue:placeholderColor forKeyPath:CLPlaceholderColorKey];
}
-(UIColor *)placeholderColor
{
return [self valueForKeyPath:CLPlaceholderColorKey];
}
此時(shí)我們?cè)O(shè)置占位文字顏色的時(shí)候就非常簡(jiǎn)單了
//系統(tǒng)設(shè)置光標(biāo)顏色與我們的分類做對(duì)比
// textfield.tintColor = [UIColor whiteColor];
textfield.placeholderColor = [UIColor grayColor];
2.一些知識(shí)點(diǎn)補(bǔ)充
frame 和 bounds的區(qū)別
首先我們需要明白每一個(gè)控件都由矩形框和內(nèi)容組成融痛。默認(rèn)情況下矩形框和內(nèi)容是重合的
- frame
- 以
父控件
內(nèi)容
的左上角為坐標(biāo)原點(diǎn), 計(jì)算出的控件自己
矩形框
的位置和尺寸
- 以
- bounds
- 以
控件自己
內(nèi)容
的左上角為坐標(biāo)原點(diǎn), 計(jì)算出的控件自己
矩形框
的位置和尺寸
- 以
NSAttributensstring和NSMutableAttributensstring的簡(jiǎn)單實(shí)用
NSAttributensstring 帶有屬性的字符串 繼承 NSObject壶笼,由兩部分組成
文字內(nèi)容 : nsstring
-
文字屬性 :
- 文字顏色 NSForegroundColorAttributeName
- 字體大小 NSFontAttributeName
- 下劃線 NSUnderlineStyleAttributeName
- 背景顏色 NSBackgroundColorAttributeName
// 帶有屬性的文字內(nèi)容
@property(nullable, nonatomic,copy) NSAttributedString *attributedPlaceholder
// 字典初始化
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
attributes[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
// 初始化
textfield.attributedPlaceholder = [[NSAttributedString alloc]initWithString:self.placeholder attributes:attributes];
NSMutableAttributensstring 繼承自 NSAttributensstring
NSMutableAttributensstring常見(jiàn)方法
// 設(shè)置range范圍的屬性, 重復(fù)設(shè)置同一個(gè)范圍的屬性, 最后一次設(shè)置才是有效的(之前的設(shè)置會(huì)被覆蓋掉)
- (void)setAttributes:(nullable NSDictionary<NSString *, id> *)attrs range:(NSRange)range;
// 添加range范圍的屬性, 同一個(gè)范圍, 可以不斷累加屬性
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
- (void)addAttributes:(NSDictionary<NSString *, id> *)attrs range:(NSRange)range;
一般只要牽扯到顯示文字的地方都可以使用富文本來(lái)做一些顯示的優(yōu)化,下面我們來(lái)看一些使用的實(shí)例
- 圖文混排
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(100, 100, 200, 25);
label.backgroundColor = [UIColor redColor];
label.font = [UIFont systemFontOfSize:14];
[self.view addSubview:label];
// 圖文混排
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];
// 1 - 圖片前部分
NSAttributedString *first = [[NSAttributedString alloc] initWithString:@"你好"];
[attributedText appendAttributedString:first];
// 2 - 圖片
// 帶有圖片的附件對(duì)象
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:@"header_cry_icon"];
CGFloat lineH = label.font.lineHeight;
attachment.bounds = CGRectMake(0, - ((label.xmg_height - lineH) * 0.5 - 1), lineH, lineH);
// 將附件對(duì)象包裝成一個(gè)屬性文字
NSAttributedString *second = [NSAttributedString attributedStringWithAttachment:attachment];
[attributedText appendAttributedString:second];
// 3 - 圖片后部分
NSAttributedString *third = [[NSAttributedString alloc] initWithString:@"哈哈哈"];
[attributedText appendAttributedString:third];
label.attributedText = attributedText;
- 一個(gè)Label顯示多行不同字體的文字
UILabel *label = [[UILabel alloc] init];
// 設(shè)置屬性文字
NSString *text = @"你好\n哈哈哈";
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:13] range:NSMakeRange(3, 3)];
label.attributedText = attributedText;
// 其他設(shè)置
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
label.frame = CGRectMake(0, 0, 100, 40);
[self.view addSubview:label];
self.navigationItem.titleView = label;
四. 總結(jié)
今天的任務(wù)已經(jīng)完成雁刷,我們完成了關(guān)注和登陸界面的搭建拌消,對(duì)登錄界面做了一些細(xì)節(jié)處理,第二天效果如下
今天的主要內(nèi)容是對(duì)textfield的一些處理安券,關(guān)注textfield更多詳細(xì)的知識(shí)可以去看iOS-UITextField 全面解析
第二天代碼已經(jīng)上傳至github--源碼下載
文中如果有不對(duì)的地方歡迎指出墩崩。我是xx_cc,一只長(zhǎng)大很久但還沒(méi)有二夠的家伙侯勉。