一、今天的任务

1)自定义标签栏控制器

2)自定义导航栏控制器

3)在新特性界面播放音频

1、第一个任务:自定义标签栏控制器

原因:默认的TabbarViewController不能满足项目的需求。

1)自定义TabBarButton

button的内部构造是由一个label和imageView组成,所以自定义TabBarButton就是自定义label和ImageView的位置。

代码如下:

#pragma mark - 覆盖父类的2个方法
#pragma mark - 设置按钮标题的frame
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
CGFloat titleY = contentRect.size.height * FZHTabBarImageRatio;
CGFloat titleH = contentRect.size.height - titleY;
CGFloat titleW = contentRect.size.width;
return CGRectMake(, titleY, titleW, titleH);
}
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
CGFloat imageH = contentRect.size.height * FZHTabBarImageRatio;
CGFloat imageW = contentRect.size.width;
return CGRectMake(, , imageW, imageH);
}

因为使我们自定义的button所以他并没有系统的点击方法,所以我们要给button添加观察者来监听他的点击事件来做切换视图的操作。

代码如下:

- (void)setItem:(UITabBarItem *)item
{
_item = item;
//1.利用kvo监听item属性的改变
[item addObserver:self forKeyPath:@"title" options: context:nil];
[item addObserver:self forKeyPath:@"image" options: context:nil];
[item addObserver:self forKeyPath:@"selectedImage" options: context:nil];
//2.属性赋值
[self observeValueForKeyPath:nil ofObject:nil change:nil context:nil];
}

KVO监听必须在监听器释放的时候,移除监听操作, 通知也得在释放的时候移除监听

代码如下:

-(void)dealloc
{
[self.item removeObserver:self forKeyPath:@"title"];
[self.item removeObserver:self forKeyPath:@"image"];
[self.item removeObserver:self forKeyPath:@"selectedImage"];
}

监听方法如下:

/**
* 监听item的属性值改变
*
* @param keyPath 哪个属性改变了
* @param object 哪个对象的属性改变了
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
//1.设置文字
[self setTitle:self.item.title forState:UIControlStateSelected];
[self setTitle:self.item.title forState:UIControlStateNormal];
//2.设置图片
[self setImage:self.item.image forState:UIControlStateNormal];
[self setImage:self.item.selectedImage forState:UIControlStateSelected]; }

至此完成自定义TabBarButton。

2)自定义tabbar

因为tabbar是添加在controller上面的,我们的点击事件也是发生在controller上面,那我们如何知道点击了那个按钮呢?我们可以通过代理模式来完成这一功能,让控制器做tabbar的代理,当用户点击控制器的tabbar上面的按钮时,它会通过代理的方式来告诉tabbar点击了那个按钮,这样我们就可以做相应的操作了。

.h文件代码如下:

 #import <UIKit/UIKit.h>
#import "FZHTabbarButton.h"
@class FZHTabbar;
@protocol FZHTabbarDelegate <NSObject> @optional
- (void)tabBar:(FZHTabbar *)tabBar didSelectedButtonFrom:(int)from to:(int)to;
- (void)tabBardidPlusButton:(FZHTabbar *)tabBar; @end
@interface FZHTabbar : UIView
@property (nonatomic,strong)NSMutableArray * tabbarButtons;
@property (weak,nonatomic)FZHTabbarButton * selectedButton;
- (void)addTabbarButtonWithItem:(UITabBarItem *)item;
@property (nonatomic,weak)id<FZHTabbarDelegate>delegate;
@end

.m文件代码如下:

 #import "FZHTabbar.h"
#import "FZHTabbarButton.h"
@implementation FZHTabbar - (NSMutableArray *)tabbarButtons
{
if (_tabbarButtons == nil) {
_tabbarButtons = [NSMutableArray array];
}
return _tabbarButtons; }
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) { }
return self;
}
- (void)addTabbarButtonWithItem:(UITabBarItem *)item
{
//1.创建按钮
FZHTabbarButton * button=[[FZHTabbarButton alloc]init];
[self.tabbarButtons addObject:button];
//2.设置数据
button.item=item; //3.添加按钮
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown];
[self addSubview:button];
//4.默认选中
if (self.tabbarButtons.count==) { [self buttonClick:button];
}
}
-(void)buttonClick:(FZHTabbarButton *)button
{
//1.通知代理
if ([self.delegate respondsToSelector:@selector(tabBar:didSelectedButtonFrom:to:)]) {
[self.delegate tabBar:self didSelectedButtonFrom:(int)self.selectedButton.tag to:(int)button.tag];
}
//2.控制器选中按钮
self.selectedButton.selected=NO;
button.selected=YES;
self.selectedButton=button;
}
- (void)layoutSubviews
{
[super layoutSubviews]; //1. 3个按钮
CGFloat buttonW=self.frame.size.width/self.subviews.count;
CGFloat buttonH=self.frame.size.height;
CGFloat buttonY = ; for (int index=; index<self.tabbarButtons.count; index++) { //1.取出按钮
FZHTabbarButton * button=self.tabbarButtons[index];
//2.设置按钮的frame
CGFloat buttonX=index * buttonW; button.frame=CGRectMake(buttonX, buttonY, buttonW, buttonH);
//3.绑定tag
button.tag=index;
} }

至此,自定义tabbar部分完成,做到这自定义TabBarViewController也已完成,只剩下在控制器中的初始化操作。

代码如下:

 /**
* 初始化tabbar
*/
- (void)setupTabbar
{
FZHTabbar * customTabBar = [[FZHTabbar alloc] init];
customTabBar.frame = self.tabBar.bounds;
customTabBar.delegate = self;
[self.tabBar addSubview:customTabBar];
self.customTabBar = customTabBar;
}
/**
* 监听tabbar按钮的改变
* @param from 原来选中的位置
* @param to 最新选中的位置
*/
- (void)tabBar:(FZHTabbar *)tabBar didSelectedButtonFrom:(int)from to:(int)to
{
self.selectedIndex = to;
} -(void)initSubVC
{
FZHHomeViewController * home=[[FZHHomeViewController alloc]init];
[self setupChildVC:home Title:@"英雄" imageName:@"hero" selectedImageName:@"hero_selected"]; FZHVideoViewController * video=[[FZHVideoViewController alloc]init];
[self setupChildVC:video Title:@"视频" imageName:@"video" selectedImageName:@"video_selected"]; FZHAboutMeViewController * aboutMe = [[FZHAboutMeViewController alloc]init];
[self setupChildVC:aboutMe Title:@"个人" imageName:@"me" selectedImageName:@"me_selected"]; }
//初始化所有子控制器
-(void)setupChildVC:(UIViewController *)childVC Title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName
{
//1.设置标题
childVC.title=title;
//2.设置图片
childVC.tabBarItem.image=[UIImage imageNamed:imageName];
//3.设置选中图片
childVC.tabBarItem.selectedImage=[UIImage imageNamed:selectedImageName];
//不在渲染图片
childVC.tabBarItem.selectedImage=[[UIImage imageNamed:selectedImageName]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
//4.添加导航控制器
FZHNaviViewController * Nav=[[FZHNaviViewController alloc]initWithRootViewController:childVC];
[self addChildViewController:Nav];
//5.添加tabbar内部的按钮
[self.customTabBar addTabbarButtonWithItem:childVC.tabBarItem];
}

注意点:一定要先删除系统自带的tabbar代码如下:

-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//删除系统自动生成的UITabBarButton
for (UIView * child in self.tabBar.subviews) {
if ([child isKindOfClass:[UIControl class]]) {
[child removeFromSuperview];
}
}
}

2、自定义导航栏控制器

代码如下:

 + (void)initialize
{
//1.设置导航栏主题
[self setupNavBarTheme]; //2.设置导航栏按钮的主题
[self setupBarButtonItemTheme];
}
/**
* 设置导航栏按钮主题
*/
+(void)setupBarButtonItemTheme
{
UIBarButtonItem * item=[UIBarButtonItem appearance];
//设置文字属性
NSMutableDictionary * textAttrs=[NSMutableDictionary dictionary]; //字体颜色
textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
//阴影大小
// textAttrs[NSShadowAttributeName] = [NSValue valueWithUIOffset:UIOffsetZero];
textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:];
//不能点击的状态
NSMutableDictionary * DisableTextAttrs=[NSMutableDictionary dictionary];
DisableTextAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
[item setTitleTextAttributes:DisableTextAttrs forState:UIControlStateDisabled];
//普通和高亮的状态
[item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
[item setTitleTextAttributes:DisableTextAttrs forState:UIControlStateHighlighted]; }
/**
* 设置导航栏主题
*/
+(void)setupNavBarTheme
{
//取出appearance对象
UINavigationBar * navBar=[UINavigationBar appearance];
navBar.tintColor = [UIColor blackColor];
// 设置标题属性
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
//字体颜色
textAttrs[NSForegroundColorAttributeName] = [UIColor blackColor];
//阴影大小
#warning 设置阴影
//textAttrs[NSShadowAttributeName] = [NSValue valueWithUIOffset:UIOffsetZero];
textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:];
[navBar setTitleTextAttributes:textAttrs]; }
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (self.viewControllers.count>) {
viewController.hidesBottomBarWhenPushed = YES;
}
[super pushViewController:viewController animated:animated];
}

至此完成了自定义导航栏和标签栏。

3、播放音频

1)导入AVFoundation/AVFoundation框架

2)编写代码如下:

    NSURL * mp3Url = [[NSBundle mainBundle] URLForResource:@"Dota2.mp3" withExtension:nil];
AVAudioPlayer * player = [[AVAudioPlayer alloc]initWithContentsOfURL:mp3Url error:nil]; [player prepareToPlay]; player.delegate = self; self.player = player; [self.player play];

到这,以上的三个部分全部实现。

代码下载地址:https://github.com/fengzhihao123/FZHDota2

Dota2APP--第二天的更多相关文章

  1. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  2. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  3. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  4. 从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群) 第一篇http://www.cnblogs.com/lyhabc/p/4678330.html第二篇http://www ...

  5. Entity Framework教程(第二版)

    源起 很多年前刚毕业那阵写过一篇关于Entity Framework的文章,没发首页却得到100+的推荐.可能是当时Entity Framework刚刚发布介绍EF的文章比较少.一晃这么多年过去了,E ...

  6. [C#] 软硬结合第二篇——酷我音乐盒的逆天玩法

    1.灵感来源: LZ是纯宅男,一天从早上8:00起一直要呆在电脑旁到晚上12:00左右吧~平时也没人来闲聊几句,刷空间暑假也没啥动态,听音乐吧...~有些确实不好听,于是就不得不打断手头的工作去点击下 ...

  7. 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...

  8. 菜鸟Python学习笔记第二天:关于Python黑客。

    2016年1月5日 星期四 天气:还好 一直不知道自己为什么要去学Python,其实Python能做到的Java都可以做到,Python有的有点Java也有,而且Java还是必修课,可是就是不愿意去学 ...

  9. (转)从0开始搭建SQL Server AlwaysOn 第二篇(配置故障转移集群)

    原文地址:  http://www.cnblogs.com/lyhabc/p/4682028.html 这一篇是从0开始搭建SQL Server AlwaysOn 的第二篇,主要讲述如何搭建故障转移集 ...

  10. Linux基础介绍【第二篇】

    远程连接Linux的原理 SHH远程连接介绍 当前,在几乎所有的互联网企业环境中,最常用的Linux提供远程连接服务的工具就是SSH软件,SSH分为SSH客户端和SSH服务端两部分.其中,SSH服务端 ...

随机推荐

  1. svn版本分支及冲突解决笔记

    转载:http://blog.csdn.net/xuguiyi100/article/details/51966557 分支合并主干示例 1.主干工程右键选择merge合并下一步 2.选中merge ...

  2. Java 设计模式系列(九)组合模式

    Java 设计模式系列(九)组合模式 将对象组合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象的使用具有一致性. 一.组合模式结构 Component: 抽象 ...

  3. DataStage 错误集(持续更新)

    DataStage 错误集(持续更新) DataStage序列文章 DataStage 一.安装 DataStage 二.InfoSphere Information Server进程的启动和停止 D ...

  4. 不要怂,就是GAN (生成式对抗网络) (一): GAN 简介

    前面我们用 TensorFlow 写了简单的 cifar10 分类的代码,得到还不错的结果,下面我们来研究一下生成式对抗网络 GAN,并且用 TensorFlow 代码实现. 自从 Ian Goodf ...

  5. Basic4android v3.50 发布

    这次发布的主要是debug 的增强.说实话,在这一方面B4a 比delphi做的要好.希望delphi 在新的版本里面 能进一步加强. I'm happy to release Basic4andro ...

  6. .NET基础 (13)IFormattable和IformatProvider的使用

    IFormattable和IformatProvider的使用1 如何使用IFormattable接口实现格式化输出2 如何告诉类型格式化输出的方式 IFormattable和IformatProvi ...

  7. 20145233计算机病毒实践九之IDA的使用

    20145233计算机病毒实践之IDA的使用 PSLIST导出函数做了什么 这个函数是一个export函数,所以在view中选择export 查到后,双击打开这个函数的位置 仔细看这个函数可以发现这个 ...

  8. 【C++】C++中的操作符重载

    C++中的操作符重载使得对于类对象的操作更加方便和直观,但是对于各种操作符重载的规则以及语法形式,一直以来都是用到哪一个上stackoverflow上查找,在查找了四五次之后,觉得每次麻烦小总结一下. ...

  9. ubuntu16.04 安装jdk 错误解决

    错误 $ apt-get install openjdk-9-jdk Errors were encountered while processing: /var/cache/apt/archives ...

  10. Linux带有时间控制的多进程bash脚本

    目标 以可控制的多进程执行,达到最大执行时长后停止脚本. 思路 1.产生fifo管道,并预填充n个值(与并发数相等) 2.记录脚本本身PID并启动计时器进程(计时终止后杀脚本本身PID) 3.并发执行 ...