IOS中的导航控制器和表视图(实现一个字体浏览器)
—恢复内容开始—
这一章比较长,知识点也比较多,我自己也不在状态,所以等我看完,一块更新吧~>_<~
字体系列列表→字体列表视图:
首先创建一个空应用,添加一个storyBoard,把这个storyBoard设置为main interface。
从控件库中拖一个UINavigationController,这个controller包含两个场景,左侧的是UINavigationController,右侧相关联的是一个tableviewcontroller。
记得要设置左侧的controller为initial view controller。
字体系列列表
右侧的controller默认的title是”Root View Controller”,点击title,可以修改title的内容,这里设置为“Fonts”。
选中导航栏下方的cell样本,把style设置为subtitle,identifier设置为FamilName,Accessory设置为Disclosure Indicator。这样的设置可以是单元格有一个子标题,病体单元格最右边会出现一个小箭头的标志,提示用户这个单元格可以点击进入更深一层内容。
然后添加一个类,命名为rootviewcontroller,继承自tableviewcontroller。
在.m文件中声明两个属性,NSArray* familyNames 和 CGFloat cellPointSize,其中familyNames存储系统中所有字体系列的名字,cellPointSize存储字体大小。
在第一个子视图中要以列表形式显示系统中所有字体系列,所以在viewDidLoad中就要设置数据源的值,
self.familyNames = [[UIFont familyNames] sortedArrayUsingSelector:@selector(compare:)];
获取系统默认头部字体的style,并把pointSize赋给cellPointSize
UIFont* preferredTableViewFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
self.cellPointSize = preferredTableViewFont.pointSize;
实现3个数据源方法:
– (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section //每个组包含的行数
– (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView //tableview包含的组数量
– (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath //返回指定位置的cell实例
在列表中就要预览到这一系列字体中具有代表性的字体
//显示字体系列的名称 cell.textLabel.text = self.familyNames[indexPath.row]; //设置字体 cell.textLabel.font = [self fontForDisplayAtIndexPath:indexPath]; //详情内容使用正常字体显示字体系列名称 cell.detailTextLabel.text = self.familyNames[indexPath.row];
获取字体时我们使用了一个单独的方法,fontForDisplayAtIndexPath:(NSIndexPath*)indexPath
这个方法根据cell的位置返回对应的字体,所以他的实现是
//获取字体系列名 NSString* familyName = self.familyNames[indexPath.row]; //该系列中的第一种字体的名字 NSString* fontName = [[UIFont fontNamesForFamilyName:familyName] firstObject]; return [UIFont fontWithName:fontName size:self.cellPointSize];
这里我们使用字体系列中第一个字体作为代表字体,这可不能不具有代表性,不过这不是重点。
回到main.storyboard中,把class改为rootviewcontroller,tableview对应的dataSource和delegate关联到controller。
这样就实现了rootViewController,我们希望点击字体系列列表中的某一个cell的时候可以看到这个系列中所有的字体,这就是下一个子视图
字体列表视图
首先在main.storyboard中拖出一个table view controller,选中cell样本,把style设置为subtitle,identifier设置为FontName,Accessory设置为Detail,这样设置可以让cell对用户的点击做出不同反应,点击后面的扩展按钮触发一种响应,点击其他区域则触发另一种响应。
添加一个类,命名为FontListViewController,继承自UITableViewController。
在.h文件中声明一个nsarray类型的属性fontNames,用来作为数据源,存储的是某一个系列中的所有字体。
在.m文件中声明一个cgfloat类型的属性cellPointSize,并且在viewDidLoad方法中获取系统默认头部字体的style,把pointSize赋给cellPointSize。
这里同样用到了fontForDisplayAtIndexPath:(NSIndexPath*)indexPath方法,目的是相同的,内部实现要做相应修改。
这个controller同样需要实现几个数据源方法
– (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
– (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
最后别忘了,把class设置为FontListViewController。
到这里已经完成了字体列表的控制,一个简单的tableview而已,不过问题是我们还没有设置从字体系列列表跳转到字体列表。
转场(segue)
转场的触发实际是在rootview中,用自然语言描述就是用户点击某一个字体系列的时候要转场跳到对应的字体列表。
首先要把rootview和fontlistviewcontroller做关联,方式是:选择rootview中的单元格样本,右击并拖向fontview,在弹出的菜单中选择non-adaptive selection segue中的push。
然后要回到rootviewcontroller的.m文件中实现转场工作。
在头部引入”FontListViewController.h”,转场是通过- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender方法来完成的,在这个方法中可以设置一些必要数据传递给目的controller。
这个方法的实现,首先要获取点击cell的nsindexpath信息,实例化一个FontListViewController,不过这里是获取的segue的destinationViewController
FontListViewController* listVC = segue.destinationViewController;
获取字体系列的名字,并且根据字体系列的名字获取该系列包含的所有字体,赋值给listVC的fontNames属性
NSString* familyName = self.familyNames[indexPath.row];
listVC.fontNames = [[UIFont fontNamesForFamilyName:familyName] sortedArrayUsingSelector:@selector(compare:)];
最后设置转场之后的导航栏标题为字体系列的名字
listVC.navigationItem.title = familyName;
这样完成了从字体系列列表到字体列表的跳转。
之前说过我们希望实现用户点击字体列表中cell的不同位置时能够做出不同响应的功能。
当用户点击详情图标之外的区域时,能够显示不同尺寸的字体,不过这里的尺寸是确定的。
当点击详情图标时,能跳转到另外一个界面,可以自由调整字体大小,不过我们应该指定一个范围。
详情图标在每个cell的最右边。
字体列表的第一种响应:不同尺寸的字体列表
要实现第一种响应,可以展示一个列表,列表中是一种字体的不同尺寸的展现。
其实这也是一个列表界面,所以还是要从控件库拖一个table view controller,把cell样例的style设置为subtitle。
新建一个类,命名为FontSizesViewController,继承自UITableViewController,并在.h文件中定义属性UIFont *font,因为这个界面是显示的一种字体,只是尺寸不同,所以需要传第一个font告诉界面应该显示什么字体。
首先实现一个方法- (NSArray*)pointSizes,这个方法会返回一个nsarray,这个数组里存着我们要显示的字体尺寸,因为尺寸设置好之后就固定了,所以这里使用一个新方法dispatch_once,这个方法会保证只执行一次。
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ pointSizes = @[ @9, @10, @11, @12, @13, @14, @28, @24, @36, @48, @64, @72, @96, @144 ]; });
这里同样用到了fontForDisplayAtIndexPath:(NSIndexPath*)indexPath方法,目的是相同的,内部实现要做相应修改。
你可能会有一个疑问,不是只展示一种字体吗,怎么还要动态获取?这是因为font不只包含字体名字的信息,还包括字体大小信息,这个方法是在返回一种具体的font。
这个controller同样需要实现几个数据源方法
– (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
– (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
这个类里还要实现一个委托方法
– (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath //返回指定位置的cell的高度
UIFont* font = [self fontForDisplayAtIndexPath:indexPath]; //获取cell的font信息,font是包含尺寸信息的哦 return 25 + font.ascender - font.descender;
因为要显示的字体的尺寸不同,所以要根据不同尺寸让cell有不同height。其实在字体系列列表中也应该实现这个方法,因为不同的字体的默认尺寸也是不同的。
要记得设置controller的class为FontSizesViewController。
在字体列表中实现转场。首先在storyboard中做关联操作,选中font list view中的cell样例,右击并且拖向fontsizesview,在弹出的菜单中选择non-adaptive selection segue中的push,这和之前设置转场的时候是一样的。
在fontlistviewcontroller.m文件中实现转场方法- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender。
在这个方法中要做一些转场之前的准备工作,比如
要设置导航栏的标题,设置目标controller的font属性等,
//根据sender获取点击位置信息 NSIndexPath* indexPath = [self.tableView indexPathForCell:sender]; //根据位置信息获取font UIFont* font = [self fontForDisplayAtIndexPath:indexPath]; //设置导航栏标题为字体名字 [segue.destinationViewController navigationItem].title = font.fontName;
FontSizeViewController* sizeVC = segue.destinationViewController;
sizeVC.font = font;
这时候就可以运行程序看一下效果了,不过这是点击辅助图标是没效果的。
字体列表的另一种响应:自由尺寸的字体,包括收藏
这个界面终于不是tableview了,O(∩_∩)O哈哈~
这次从控件库拖一个view controller,然后就要做转场的关联操作。你应该注意到了,所有的有导航栏的界面在界面最上方会有一条灰色的区域,这就是导航栏要占用的位置,所以我们要先关联,然后在布局的时候才能更好的参考。关联的方法和之前一样,不过最后选择菜单的时候要选择non-adaptive accessory segue中的push。这样才能关联到辅助图标的点击。ok,继续布局