一、今天的任务

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. Implement Trie (Prefix Tree)实现字典树

    [抄题]: Implement a trie with insert, search, and startsWith methods. Note:You may assume that all inp ...

  2. centos7 搭建svn服务

    linux(centos)下SVN服务器如何搭建?说到SVN服务器,想必大家都知道,可以是在LINUX下如何搭建SVN服务器呢?那么今天给大家分享一下linux(centos)搭建SVN服务器的思路! ...

  3. update-alternatives命令详解

    转载:http://blog.csdn.net/maixia24/article/details/11707289 update-alternatives是ubuntu系统中专门维护系统命令链接符的工 ...

  4. Golang笔记之变量

    哈哈 package main // 关键字var 声明变量 类型信息放在变量名后 //声明一个int型变量 var v1 int //声明一个string类型 var v2 string //声明多 ...

  5. Alpha冲刺 - (6/10)

    Part.1 开篇 队名:彳艮彳亍团队 组长博客:戳我进入 作业博客:班级博客本次作业的链接 Part.2 成员汇报 组员1(组长)柯奇豪 过去两天完成了哪些任务 基于ssm框架的前后端交互测试,结合 ...

  6. 6、Docker Image

    6.1 什么是image 文件和meta data的集合(root filesystem) 分层的,并且每一层都可以添加.改变.删除文件,成为一个新的image 不同的image可以共享相同的laye ...

  7. Concurrent Request:Inactive phase,No Manager status

    Symptom 随便submit一个request,发现几乎所有的Concurrent Manager都为No Manager状态,Phase为Inactive. Solution 一个Concurr ...

  8. devexpress停靠菜单

    dxDockSite1.Width := 27; dxDockPanel1.DockTo(dxDockSite1, dtLeft, 0); dxDockPanel2.DockTo(dxDockPane ...

  9. GlusterFS 三

    性能监控 Displaying the I/0 Information $gluster volume profile gv0 startStarting volume profile on gv0 ...

  10. docker容器怎么设置开机启动

    https://my.oschina.net/lwenhao/blog/1923003 docker服务器.以及容器设置自动启动 一.docker服务设置自动启动 说明:适用于yum安装的各种服务 查 ...