热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一个java程序员自学IOS开发之路(五)

20151024Day23我插入移动硬盘后,电脑右上角老是出现一个齿轮转啊转,然后弹出对话框说有新文件加入电脑什么文件夹,要不要去看,关还关不掉,于是乎,昨晚脑袋一抽就把那个弹出来

2015/10/24

Day 23

我插入移动硬盘后,电脑右上角老是出现一个齿轮转啊转,然后弹出对话框说有新文件加入电脑什么文件夹,要不要去看,关还关不掉,于是乎,昨晚脑袋一抽就把那个弹出来的文件夹移入废纸篓,然后发现不能这么干,就从废纸篓恢复,然而Finder就卡死了= =不管怎样都没响应,我烦的不行就强制按电源键重启电脑了(用Win系统的坏习惯,有事没事重启一下),然后!!!输入密码登陆,如下图:

 技术分享

然后就重启了= =,无限循环进不了系统,各种方法无果后,没办法去了售后店。解决方法,重装系统,花费300大洋,我去!真特么贵,唉~谁叫自己作呢,弄好后回家第一件事就是自制U盘启动盘。

其实很简单,先下好镜像文件,然后插入U盘,格式化它,再可以给它分区,这个随意我就没分,最后终端输入命令,等着就行了。

命令如下

安装包名称:Install OS X El Capitan.app

制作U盘启动盘指令

sudo /Applications/Install\ OS\ X\ El\ Capitan.app/Contents/Resources/createinstallmedia --volume /Volumes/u盘 --applicationpath /Applications/Install\ OS\ X\ El\ Capitan.app --nointeraction

第二件事就是开启TimeMachine备份。

之前写的代码都没了= =,唉,不说这事了,都是泪%>_<%

 

2015/10/25

Day 24

调试新系统,调整心情,再一次安装Xcode,继续学习啦~

今天开始学习UITableView

UITableView

在众多app中,能看到各式各样的表格数据,如下

 技术分享

iOS中,要实现表格数据展示,最常用的做法就是使用UITableView

UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳

UITableView的两种样式

技术分享


  1. UITableView需要一个数据源(dataSource)来显示数据

  2. UITableView会向数据源查询一共有多少行数据以及每一行显示什么数据等

  3. 没有设置数据源的UITableView只是个空壳

  4. 凡是遵守UITableViewDataSource协议的OC对象,都可以是UITableView的数据源

UITableViewDataSource协议

 技术分享

Cell简介

UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行

UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图。还可以通过cell的accessoryView属性来自定义辅助指示视图(比如往右边放一个开关)

UITableViewCellcontentView

contentView下默认有3个子视图

其中2个是UILabel(通过UITableViewCell的textLabel和detailTextLabel属性访问)

第3个是UIImageView(通过UITableViewCell的imageView属性访问)

UITableViewCell还有一个UITableViewCellStyle属性,用于决定使用contentView的哪些子视图,以及这些子视图在contentView中的位置

 技术分享

Cell的重用


  • iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象的话,那将会耗尽iOS设备的内存。要解决该问题,需要重用UITableViewCell对象

  • 重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象

  • 还有一个非常重要的问题:有时候需要自定义UITableViewCell(用一个子类继承UITableViewCell),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,对象池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell

  • 解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象

Cell的重用代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    // 1.定义一个cell的标识

      static NSString *yu3 = @“yu3”;

    // 2.从缓存池中取出cell

      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    // 3.如果缓存池中没有cell

      if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:yu3];

    }

    // 4.设置cell的属性...

    

      return cell;

}

上面的写法并不好,因为数据源不需要知道cell内部的标识为什么,cell的标识cell自己最清楚,应该把创建cell的代码封装在cell里面,如下(YUCell为我自定义的cell类名)

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *yu3 = @“yu3Cell";

    YUCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    if (cell == nil) {

        cell = [[YUCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:yu3];

    }

    return cell;

}

这样,数据源里的方法就很简单

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    //创建cell

    YUCell *cell = [YUCell cellWithTableView:tableView];

    //设置cell的属性...

    

    return cell;

}

这样的话,如果以后cell里面的东西要变化,只需要动cell里的代码,数据源里代码不需要改变。

2015/10/26

Day 25

今天做了一个UIScrollView和UITableView综合的小项目

技术分享    技术分享

仿造团购app的界面,上面的广告可以自动翻页,滑到下面有按钮点击后加载数据

 

上面的广告,每个cell还有下面的加载更多按钮都是用xib封装的

 技术分享

技术分享

技术分享

使用xib封装一个view的步骤:

1.新建一个xib文件描述一个view的内部结构

2.新建一个自定义的类(自定义类需要继承自系统自带的view, 继承自哪个类,  取决于xib根对象的Class)

3.新建类的类名最好跟xib的文件名保持一致

4.将xib中的控件 自定义类的.m文件 进行连线

5.提供一个类方法返回一个创建好的自定义view(屏蔽从xib加载的过程)

6.提供一个模型属性让外界传递模型数据

7.重写模型属性的setter方法,在这里将模型数据展示到对应的子控件上面

代理的使用

像上面的加载更多按钮,他是在xib里面的,如果想让用户点击它加载新数据,这件事得控制器ViewController来做。可以用代理模式实现,让ViewController成为YUTgFooterView(我封装该View的类名)的代理(delegate),这样ViewController就可以监听那个按钮点击做出反应了。

使用delegate的步骤


  • 先搞清楚谁是谁的代理(delegate)

  • 定义代理协议,协议名称的命名规范:控件类名 + Delegate

  • 定义代理方法


    • 代理方法一般都定义为@optional

    • 代理方法名都以控件名开头

    • 代理方法至少有1个参数,将控件本身传递出去


技术分享 


  • 设置代理(delegate)对象  (比如myView.delegate = xxxx;)

 技术分享


  • 代理对象遵守协议

技术分享 


  • 代理对象实现协议里面该实现的方法

 技术分享


  • 在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情(在调用之前判断代理是否实现了该代理方法)

 技术分享

 

2015/10/27

Day 26

昨天的项目中,cell是xib封装的,每个cell的内容都是类似的,高度也是一样的,这样太局限,比如微博页面,它的每个cell的内容是不一样的,这就需要用代码来自定义cell 

如图,每个cell最多可以有一个头像,一个名字,一个vip标识,一个文本,一张图片,plist文件结构如下 

技术分享  技术分享 

首先,把plist封装成模型

 技术分享

技术分享

创建自定义的cell类继承自UItableViewCell 

 技术分享

cell内部的控件属性要写在.m文件中的类扩展中 

 技术分享

实现cell的构造方法

/**

 *  构造方法(在初始化对象的时候会调用)

 *  一般在这个方法中添加需要显示的子控件

 */

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

        UIImageView *icOnView= [[UIImageView alloc] init];

        [self.contentView addSubview:iconView];

        self.icOnView= iconView;

        UILabel *nameView = [[UILabel alloc] init];

        nameView.fOnt= YUNameFont;

        nameView.backgroundColor = [UIColor orangeColor];

        [self.contentView addSubview:nameView];

        self.nameView = nameView;

        UIImageView *vipView = [[UIImageView alloc] init];

        [self.contentView addSubview:vipView];

        self.vipView = vipView;

        UILabel *textView = [[UILabel alloc] init];

        textView.fOnt= YUTextFont;

        textView.numberOfLines = 0;//自动换行!

        textView.backgroundColor = [UIColor blueColor];

        [self.contentView addSubview:textView];

        self.textView = textView;

        UIImageView *pictureView = [[UIImageView alloc] init];

        [self.contentView addSubview:pictureView];

        self.pictureView = pictureView;

    }

    return self;

}

再重写成员属性的setter方法,里面设置控件数据

/**设置子控件的大小和数据 */

-(void)setStatus:(YUStatus *)status {

    _status = status;

    //设置数据

    [self setData];

    //设置控件大小

    [self setFrame];

}

设置的代码冗长,我把他们封装了

别忘了实现.h中声明的类方法

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *yu3 = @"statusCell";

    YUStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    if (cell == nil) {

        cell = [[YUStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:yu3];

    }

    return cell;

}

最后到控制器,先让控制器继承自UITableViewController 

 技术分享 

设置成员属性 

 技术分享

重写getter方法加载数据

- (NSArray *)statuses {

    NSMutableArray *result = [[NSMutableArray alloc] init];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];

    NSArray *dics = [NSArray arrayWithContentsOfFile:path];

    for (NSDictionary *dic in dics) {

        YUStatus *status = [YUStatus statusWithDic:dic];

        [result addObject:status];

    }

    return result;

}

最后重写数据源方法

//默认就是1,可以不写这个方法

//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

//    return 1;

//}

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.statuses.count;

}

 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCell *cell = [YUStatusCell cellWithTableView:tableView];

    cell.status = self.statuses[indexPath.row];

    return cell;

}

这样运行出来是这个效果,很坑爹,因为个cell默认的高度是一样的,有个方法可以改变 

 技术分享

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //如何自定义cell高度?

    return 100;

}

这里插播一下,计算一个字符串所占的size,如图我文本的背景色

第一种方法,利用控件的一个方法

//根据内部文字以及参数中给的参考size计算自适应的size

    CGSize nameSize = [self.nameView sizeThatFits:CGSizeZero];

第二种方法,利用NSString一个类别(分类)中的方法 

//根据内部文字以及参数中给的参考的最大size计算自适应的size

    CGSize nameSize = [status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size;

第一个参数:参考的最大size,这里可以规定最大宽度和高度

第二个参数:一般写NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeading

第三个参数:是个字典,传入字体大小

 

那么问题来了,如何计算每个cell的高度?

cell的高度是根据里面的数据决定的,数据是由模型传过来的,因此cell的高度应该由模型来计算!

解决方法:

1.提供2个模型


  • 数据模型: 存放文字数据\图片数据

  • frame模型: 存放数据模型\所有子控件的frame\cell的高度 

 技术分享

2.cell拥有一个frame模型(frame模型已经包含数据模型了)

技术分享 

3.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame

- (void)setStatus:(YUStatus *)status {

    _status = status;

    CGFloat padding = 20;

    CGFloat icOnX= padding;

    CGFloat icOnY= padding;

    CGFloat icOnW= 30;

    CGFloat icOnH= 30;

    _icOnF= CGRectMake(iconX, iconY, iconW, iconH);

    //根据内部文字以及参数中给的参考的最大size计算自适应的size

    CGSize nameSize = [status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : YUNameFont} context:nil].size;

    CGFloat nameX = CGRectGetMaxX(_iconF) + padding;

    CGFloat nameY = iconY + (iconH - nameSize.height) / 2;

    _nameF = CGRectMake(nameX, nameY, nameSize.width, nameSize.height);

    

    CGFloat vipX = nameX + nameSize.width + padding;

    CGFloat vipY = nameY;

    CGFloat vipW = 14;

    CGFloat vipH = 14;

    _vipF = CGRectMake(vipX, vipY, vipW, vipH);

    

    CGFloat textX = iconX;

    CGFloat textY = CGRectGetMaxY(_iconF) + padding;

    CGSize textSize = [status.text boundingRectWithSize:CGSizeMake(345, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : YUTextFont} context:nil].size;

    _textF = CGRectMake(textX, textY, textSize.width, textSize.height);

    

    if (status.picture) {

        CGFloat picX = textX;

        CGFloat picY = CGRectGetMaxY(_textF) + padding;

        CGFloat picW = 200;

        CGFloat picH = 200;

        _picF = CGRectMake(picX, picY, picW, picH);

        _cellHight = CGRectGetMaxY(_picF) + padding;

    } else {

        _cellHight = CGRectGetMaxY(_textF) + padding;

    }

}

4.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCellFrame *frame = self.statusFrames[indexPath.row];

    return frame.cellHight;

}

最后这样返回每个cell的高度就可以啦

技术分享 

最后说一下弹窗事件,我做了个点击cell弹出对话框修改用户名的功能

 技术分享

iOS8以前,弹窗需要遵守协议还有实现按钮的点击处理,比较麻烦,而iOS8以后可以在一个方法里搞定,而且不用遵守协议

// cell点击事件监听

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCellFrame *statusFrame = self.statusFrames[indexPath.row];

    NSString *name = statusFrame.status.name;

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"博主" message:nil preferredStyle:UIAlertControllerStyleAlert];

    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {

        textField.text = name;

    }];

    UIAlertAction *modify = [UIAlertAction actionWithTitle:@"修改" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {

        statusFrame.status.name = alert.textFields[0].text;

        //修改后计算出新的name所占frame的大小

        CGSize newSize = [statusFrame.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : YUTextFont} context:nil].size;

        statusFrame.nameF = CGRectMake(CGRectGetMinX(statusFrame.nameF) , CGRectGetMinY(statusFrame.nameF), newSize.width, newSize.height);

        //重新加载该行数据

        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];

    }];

    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

    }];

    [alert addAction:modify];

    [alert addAction:cancel];

    [self presentViewController:alert animated:YES completion:nil];

}


推荐阅读
  • 解决Parallels Desktop错误15265的方法
    本文详细介绍了在使用Parallels Desktop时遇到错误15265的多种解决方案,包括检查网络连接、关闭代理服务器和修改主机文件等步骤。 ... [详细]
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 第二十五天接口、多态
    1.java是面向对象的语言。设计模式:接口接口类是从java里衍生出来的,不是python原生支持的主要用于继承里多继承抽象类是python原生支持的主要用于继承里的单继承但是接 ... [详细]
  • 解决 Windows Server 2016 网络连接问题
    本文详细介绍了如何解决 Windows Server 2016 在使用无线网络 (WLAN) 和有线网络 (以太网) 时遇到的连接问题。包括添加必要的功能和安装正确的驱动程序。 ... [详细]
  • 在使用Eclipse进行调试时,如果遇到未解析的断点(unresolved breakpoint)并显示“未加载符号表,请使用‘file’命令加载目标文件以进行调试”的错误提示,这通常是因为调试器未能正确加载符号表。解决此问题的方法是通过GDB的`file`命令手动加载目标文件,以便调试器能够识别和解析断点。具体操作为在GDB命令行中输入 `(gdb) file `。这一步骤确保了调试环境能够正确访问和解析程序中的符号信息,从而实现有效的调试。 ... [详细]
  • 在 LeetCode 的“有效回文串 II”问题中,给定一个非空字符串 `s`,允许删除最多一个字符。本篇深入解析了如何判断删除一个字符后,字符串是否能成为回文串,并提出了高效的优化算法。通过详细的分析和代码实现,本文提供了多种解决方案,帮助读者更好地理解和应用这一算法。 ... [详细]
  • LDAP服务器配置与管理
    本文介绍如何通过安装和配置SSSD服务来统一管理用户账户信息,并实现其他系统的登录调用。通过图形化交互界面配置LDAP服务器,确保用户账户信息的集中管理和安全访问。 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • [c++基础]STL
    cppfig15_10.cppincludeincludeusingnamespacestd;templatevoidprintVector(constvector&integer ... [详细]
  • 自定义滚动条美化页面内容
    当页面内容超出显示范围时,为了提升用户体验和页面美观,通常会添加滚动条。如果默认的浏览器滚动条无法满足设计需求,我们可以自定义一个符合要求的滚动条。本文将详细介绍自定义滚动条的实现过程。 ... [详细]
  • 微软推出Windows Terminal Preview v0.10
    微软近期发布了Windows Terminal Preview v0.10,用户可以在微软商店或GitHub上获取这一更新。该版本在2月份发布的v0.9基础上,新增了鼠标输入和复制Pane等功能。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 使用Jsoup解析并遍历HTML文档时,该库能够高效地生成一个清晰、规范的解析树,即使源HTML文档存在格式问题。Jsoup具备强大的容错能力,能够处理多种异常情况,如未闭合的标签等,确保解析结果的准确性和完整性。 ... [详细]
  • 系统数据实体验证异常:多个实体验证失败的错误处理与分析
    在使用MVC和EF框架进行数据保存时,遇到了 `System.Data.Entity.Validation.DbEntityValidationException` 错误,表明存在一个或多个实体验证失败的情况。本文详细分析了该错误的成因,并提出了有效的处理方法,包括检查实体属性的约束条件、调试日志的使用以及优化数据验证逻辑,以确保数据的一致性和完整性。 ... [详细]
author-avatar
手机用户2502925587
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有