前言
网易云音乐的仿写较为简单,为3G share的仿写打下基础。在这次仿写中,学到了很多新的东西。
登陆注册
给出效果图:
该界面的细节还是很多的。如弹出键盘时界面的移动,保存每次注册的账号密码,当注册界面pop弹出时,保存界面数据。
弹出键盘时界面移动可以采用当键盘弹出时,控制视图的transform属性。
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
if (textField == self.tf_account) {
[UIView animateWithDuration:0.2 animations:^{
self.view.transform = CGAffineTransformMakeTranslation(0, -180);
}];
} else if (textField == self.tf_password) {
[UIView animateWithDuration:0.2 animations:^{
self.view.transform = CGAffineTransformMakeTranslation(0, -230);
}];
}
}
保存账号密码则有两种方式。
- 每次点进注册时,都将储存账号密码都字典通过属性传值回传给注册页面
- 将注册视图设置为属性,并且使用strong修饰。
而登陆跳转到新的视图控制器,则可以采用协议传值,当正确登陆后,创建一个分栏控制器,并通过协议传值传到SceneDelegate.m文件进行赋值。
首页
该界面使用两个自定义cell。需要注意从该页面点击进入详情时,主页的点赞数等需与详情中的同步。
采用在application文件中定义一个全局变量来保存是否点赞的状态。再通过属性和协议传值,实现主页与详情页点赞的同步。
点击返回时响应协议
-(void) press:(UIButton*)btn
{
if ([self.delegate respondsToSelector:@selector(numberOfdianzan:numberOffenxiang:numberOfGuankan:)]) {
[self.delegate numberOfdianzan:self.dianZan_in numberOffenxiang:self.fenXiang_in numberOfGuankan:self.guankan_in];
}
self.tabBarController.tabBar.hidden = NO;
[self.navigationController popViewControllerAnimated:YES];
}
对于tableView的刷新,我们可以采取单独刷新某一行或某一列。因为刷新而产生的复用等问题还没找到非常有效的解决办法。
-(void)numberOfdianzan:(NSInteger)dianZan_in numberOffenxiang:(NSInteger)fenXiang_in numberOfGuankan:(NSInteger)guankan_in
{ AppDelegate* mydelegate = (AppDelegate*)[UIApplication sharedApplication].delegate ;
if (fenXiang_in == 21) {
mydelegate.isLiked1_3 = YES;
} else if (fenXiang_in == 20) {
mydelegate.isLiked1_3 = NO;
}
if (guankan_in == 27) {
mydelegate.isLiked1_2 = YES;
} else if (guankan_in == 26) {
mydelegate.isLiked1_2 = NO;
}
if (dianZan_in == 103) {
mydelegate.isLiked1_1 = YES;
} else if (dianZan_in == 102) {
mydelegate.isLiked1_1 = NO;
}
[self.tableView0 reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
}
搜索
该界面的细节比较多,协议传值更换头像,折叠cell,搜索跳转,还有TextView的简单使用。
更换头像与网易云音乐中的类似,但是可以选入多个照片。出现一个问题,显示一开始点击的照片还是最后点击的,取消了首次或最后一次点击的照片,该如何定位到第二次或倒数第二次点击的照片。此处采用数组储存解决这个问题。每次点击都将按钮的tag值存入数组,再确定按钮中获取数组的最后一个元素,即末次点击图片。
-(void) pressButton:(UIButton *) button{
button.selected = !button.selected;
NSInteger tag = button.tag - 100;
if (button.selected) {
self.selectPhotoCount++;
[self.array0 addObject:@(tag)];
} else {
self.selectPhotoCount--;
[self.array0 removeObject:@(tag)];
}
}
-(void) press{
if (self.selectPhotoCount != 0 && self.array0.count != 0) {
UIAlertController *alertVier = [UIAlertController alertControllerWithTitle:nil message:@"确定上传的内容" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* action01 = [UIAlertAction actionWithTitle:@"返回" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){/* 在这里编写执行该选项的代码*/}];
UIAlertAction* action02 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){
NSInteger recenttag = [self.array0.lastObject integerValue];
self->_strImageSend = [NSString stringWithFormat:@"头像%ld.jpg",(long)recenttag];
if ([self.delegate respondsToSelector:@selector(didSelectImageWithNameAgain:ThenumberOfImage:)]) {
[self.delegate didSelectImageWithNameAgain:self->_strImageSend ThenumberOfImage:self.selectPhotoCount];
UIAlertController *alertVier1 = [UIAlertController alertControllerWithTitle:nil message:@"成功上传!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* action0 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){/* 在这里编写执行该选项的代码*/
[self.navigationController popViewControllerAnimated:YES];
}];
[alertVier1 addAction:action0];
[self presentViewController:alertVier1 animated:YES completion:nil];
}}];
[alertVier addAction:action01];
[alertVier addAction:action02];
[self presentViewController:alertVier animated:YES completion:nil];
} else {
_alertVier = [UIAlertController alertControllerWithTitle:@"警告" message:@"请选择一张图片" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* action01 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){/* 在这里编写执行该选项的代码*/}];
[_alertVier addAction:action01];
[self presentViewController:_alertVier animated:YES completion:nil];
}
[self.navigationController popViewControllerAnimated:YES];
}
折叠cell:简而言之就是将tableView的高度设置为只能呈现一个cell,当点击cell时或点击按钮时,tableView的高度改变为呈现整个cell的高度,再次点击后改变回原状态。给出关键代码:
-(void) pressbtn_switch:(UIButton *)btn
{
btn.selected = !btn.selected;
if (btn.selected == YES) {
self.tableView0.frame = CGRectMake(250, 200, 120, 40*4);
} else {
self.tableView0.frame = CGRectMake(250, 200, 120, 40);
}
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *str = @"VCUpload_foldCell";
VCUpload_foldCell *cell = [self.tableView0 dequeueReusableCellWithIdentifier:str];
cell.label.text = self.nsarray[indexPath.row];
cell.label.backgroundColor = [UIColor whiteColor];
return cell;
}
同时,当点击cell后,要保存此cell的内容,此处采取的方法是更换数组的内容,再次重新更新数据
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
VCUpload_foldCell* cell = [self.tableView0 cellForRowAtIndexPath:indexPath];
NSString* str = [NSString stringWithString:cell.label.text];
for (int i = 0; i < 4; i++) {
if ([str isEqualToString:self.nsarray[i]]) {
self.nsarray[i] = self.nsarray[0];
break;
}
}
self.nsarray[0] = str;
self.btn_switch.selected = !self.btn_switch;
if (self.btn_switch.selected == YES) {
self.tableView0.frame = CGRectMake(250, 200, 120, 40*4);
} else {
self.tableView0.frame = CGRectMake(250, 200, 120, 40);
}
[self.tableView0 reloadData];
}
搜索跳转功能只需要在键盘弹回时,判断文本是否与目标字符相同即可
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if (self.tf_serch == textField) {
[self.tf_serch resignFirstResponder];
}
if ([self.tf_serch.text isEqual: @"大白"]) {
VCBigWhite *vcBigWhite = [[VCBigWhite alloc] init];
[self.navigationController pushViewController:vcBigWhite animated:YES];
}
return YES;
}
文章
该页面较为简单,就是分栏控件与tableView和滚动视图结合,需要注意的是,分栏控件与自定义cell中的滚动视图如何互相响应在网易云中已经详细给出过代码,此处不再赘述。该页面仅需注意tableView的尺寸要与滚动视图对齐,这样就不会出现在水平滑动时竖直方向也可以滑动。
推荐
该页面就是一个简单的自定义cell,控件的摆放和堆叠。
个人信息
先给出简单展示:
该页面是3G share仿写的重点,包括对聊天室的学习,控件的保存,以及自定义cell之间的嵌套,都需要学习。
当有属性需要保存时,采用将页面设置为属性,同时用strong来修饰,即可保存界面。
修改密码效果:
此处对字符的限制采用新学习的一个方法:
- shouldChangeCharactersInRange:这个方法告诉文本框将要发生的文本更改,并允许接受或拒绝这个更改。
- replacementString:这个参数是将要替换选定文本范围的新文本。代表用户即将输入的字符串。
- NSCharacterSet:用来表示 Unicode 字符集合的类。 characterSetFromTextField 则是从 string 中获取的字符集合。
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *allowCharacters = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string];
return [allowCharacters isSupersetOfSet:characterSetFromTextField];
}
最后给出聊天室的效果:
聊天室的代码还是比较复杂,学习到了很多新的东西。包括自适应高度,计算字符串大小高度,动态创建cell。
总结
3G share刚开始写的时候非常困难,繁琐,但随着一步步的把问题解决,收获也非常大。