项目开发中封装一个BarButtonItem类别-很实用
Encapsulates a TabBarItem--封装一个BarButtonItem类
- 在我们程序的导航栏的左边或右边一般都会有这样的BarButtonItem,用来界面之间的跳转
- 如果我们有很多的控制器,那么我们就会有很多的BarButtonItem要写
- 所以我们要对它进行封装,今后可以更方便的使用它,拿起来就可以用
有几个小点:
- 代码设置按钮尺寸和要设置的图片尺寸一样
第一种方式:
UIImage *image = [UIImage imageNamed:@"tupian"];
UIImage *image =[button backgroundImageForState:UIControlStateNormal];
button.frame = CGRectMake(0, 0, image.size.width, image.size.height);
第二种方式:
UIImage *image = [UIImage imageNamed:@"tupian"];
UIImage *image = button.currentbackgrundImage;
button.frame = CGRectMake(0, 0, image.size.width, image.size.height);
第三种方式:
UIImage *image = [UIImage imageNamed:@"tupian"];
UIImage *image =[button backgroundImageForState:UIControlStateNormal];
[button sizeToFit];
- 每一个导航控制器都可以设置对应的按钮
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:@"MainTagSubIcon"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:@"MainTagSubIconClick"] forState:UIControlStateHighlighted];
[button sizeToFit];
[button addTarget:self action:@selector(CYEssenceClick) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
- (void)CYEssenceClick
{
NSLog(@"%s",__func__);
}
- 如果设置的按钮一边有两个,就放在数组中,数组中的顺序和它显示的顺序有关
UIButton *moonButton = [UIButton buttonWithType:UIButtonTypeCustom];
[moonButton setBackgroundImage:[UIImage imageNamed:@"mine-moon-icon"] forState:UIControlStateNormal];
[moonButton setBackgroundImage:[UIImage imageNamed:@"mine-moon-icon-click"] forState:UIControlStateHighlighted];
[moonButton sizeToFit];
[moonButton addTarget:self action:@selector(moonClick) forControlEvents:UIControlEventTouchUpInside];
UIButton *settingButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settingButton setBackgroundImage:[UIImage imageNamed:@"mine-setting-icon"] forState:UIControlStateNormal];
[settingButton setBackgroundImage:[UIImage imageNamed:@"mine-setting-icon-click"] forState:UIControlStateHighlighted];
[settingButton sizeToFit];
[settingButton addTarget:self action:@selector(settingClick) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.rightBarButtonItems = @[
[[UIBarButtonItem alloc] initWithCustomView:settingButton],
[[UIBarButtonItem alloc] initWithCustomView:moonButton]
];
- (void)moonClick
{
NSLog(@"%s",__func__);
}
- (void)settingClick
{
NSLog(@"%s",__func__);
}
- 从上面也可以看出来:这样写的话,代码量就多了,所以要进行代码的封装
第一种方式
- 新建一个ItemTool类
- CYItemTool.h文件中
#import <UIKit/UIKit.h>
@interface CYItemTool : NSObject
+ (UIBarButtonItem *)itemWithImage:(NSString *)image highImage:(NSString *)highImage target:(id)target action:(SEL)action;
@end
- CYItemTool.m文件中
#import "CYItemTool.h"
@implementation CYItemTool
+ (UIBarButtonItem *)itemWithImage:(NSString *)image highImage:(NSString *)highImage target:(id)target action:(SEL)action
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:highImage] forState:UIControlStateHighlighted];
[button sizeToFit];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
return [[UIBarButtonItem alloc] initWithCustomView:button];
}
@end
- 因为这个抽取的工具类在项目中很多地方基本都能用到,所以写入到pch文件之中
- pch文件中
#ifndef ___________0901_PrefixHeader_pch
#define ___________0901_PrefixHeader_pch
#import <UIKit/UIKit.h>
#import "CYItemTool.h"
// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.
// 日志输出
#ifdef DEBUG // 开发阶段 -DEBUG阶段:使用Log
#define CYLog(...) NSLog(__VA_ARGS__)
#else // 发布阶段——上线阶段:移除Log
#define CYLog(...)
#endif
// 方法输出
#define CYLogFunc CYLog(@"%s",__func__)
#endif
第二种方式
新建一个扩展类(更推荐这种)
也就是对UIBarButtonItem这个类扩充方法
UIBarButtonItem+CYExtension.h文件中:
#import <UIKit/UIKit.h>
@interface UIBarButtonItem (CYExtension)
+ (instancetype)itemWithImage:(NSString *)image highImage:(NSString *)highImage target:(id)target action:(SEL)action;
@end
- UIBarButtonItem+CYExtension.m文件中
#import "UIBarButtonItem+CYExtension.h"
@implementation UIBarButtonItem (CYExtension)
+ (instancetype)itemWithImage:(NSString *)image highImage:(NSString *)highImage target:(id)target action:(SEL)action
{
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:highImage] forState:UIControlStateHighlighted];
[button sizeToFit];
[button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
return [[self alloc] initWithCustomView:button];
}
}
@end
- 同样将头文件导入到pch文件中去
#ifndef ___________0901_PrefixHeader_pch
#define ___________0901_PrefixHeader_pch
#import <UIKit/UIKit.h>
#import "UIBarButtonItem+CYExtension.h"
// Include any system framework and library headers here that should be included in all compilation units.
// You will also need to set the Prefix Header build setting of one or more of your targets to reference this file.
// 日志输出
#ifdef DEBUG // 开发阶段 -DEBUG阶段:使用Log
#define CYLog(...) NSLog(__VA_ARGS__)
#else // 发布阶段——上线阶段:移除Log
#define CYLog(...)
#endif
// 方法输出
#define CYLogFunc CYLog(@"%s",__func__)
#endif
- 那么在封装后我们在每个控制器去设置它们各自的BarButtonItem的时候,就可以这么去设置了
- 上面图中的例子
#import "CYMeViewController.h"
#import "CYSettingViewController.h"
@interface CYMeViewController ()
@end
@implementation CYMeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"我的";
// 我的导航栏右边的内容
UIBarButtonItem *moonButton = [UIBarButtonItem itemWithImage:@"mine-moon-icon" highImage:@"mine-moon-icon-click" target:self action:@selector(moonClick)];
UIBarButtonItem *settingButton = [UIBarButtonItem itemWithImage:@"mine-setting-icon" highImage:@"mine-setting-icon-click" target:self action:@selector(settingClick)];
self.navigationItem.rightBarButtonItems = @[settingButton,moonButton];
}
- (void)moonClick
{
CYLogFunc
}
- (void)settingClick
{
CYSettingViewController *setting = [[CYSettingViewController alloc] init];
[self.navigationController pushViewController:setting animated:YES];
}
@end
- 在另外一个控制器的设置,同样
#import "CYFocusViewController.h"
@interface CYFocusViewController ()
@end
@implementation CYFocusViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"我的关注";
// 设置导航栏左边的内容
self.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithImage:@"friendsRecommentIcon" highImage:@"friendsRecommentIcon-click" target:self action:@selector(CYFocusViewClick)];
}
- (void)CYFocusViewClick
{
CYLogFunc
UITableViewController *focus = [[UITableViewController alloc] init];
focus.navigationItem.title = @"百科不是全书";
[self.navigationController pushViewController:focus animated:YES];
}
这样就方便多了,直接调用方法,也不用担心会写错
个人愚见--不管是新建一个类还是扩展一个类,都是差不多的,也看个人喜好。但是实际开发中,类方法的扩展可能有成百上千个的时候,你一个个新建类的话,不太现实,所以为了追求最优化方案还是采用第二种方法吧!至少好记好用点吧!
稍后的时间,我会尽量将一些封装的东西都整理出来,敬请关注!
下面的内容,感兴趣的朋友可以研究一下!
扩充说明--类别
网上copy过来的,有助于大家理解为什么选用类别优于新建一个类
下面文字copy源于:http://www.2cto.com/kf/201502/376993.html
原文内容如下:
- 类别是一种为现有的类添加新方法的方式
- 利用Objective-C的动态运行时分配机制,可以为现有的类添加新方法,这种为现有的类添加新方法的方式称为类别catagory。
- 他可以为任何类添加新的方法,包括那些没有源代码的类。
- 类别使得无需创建对象类的子类就能完成同样的工作
创建类别
- 1、声明类别声明类别与声明类的形式很相似
@interface NSString(NumberConvenience)-(NSNumber *)lengthAsNumber;@end//NumberConvenience
- 这个声明有两个特点:
- (1)现有的类位于@interface关键字之后,其后是位于圆括号中的类别名称。
+ 类别名称是NumberConvenience
+ 而且该类别将向NSString类中添加方法
+ 换句话说:“我们向NSString类中添加一个名称为NumberConvenience的类别。
+ 同名类别有唯一性,但是可以添加任意多的不同名类别。 - (2)可以执行希望向其添加类别的类以及类别的名称,还可以列出添加的方法不可以添加新的实例变量,类别生命中没有实例变量部分。
- (1)现有的类位于@interface关键字之后,其后是位于圆括号中的类别名称。
- 2、实现类别
@implementation NSString(NumberConvenience)-(NSNumber *)lengthAsNumber{unsigned int length = [self length];return ([NSNumber numberWithUnsignedInt : length]);} **//lengthAsNumber**@end **//NumberConvenience
- 在实现部分也包括类名、类别名和新方法的实现代码
3、类别的局限性有两方面局限性:
- (1)无法向类中添加新的实例变量,类别没有位置容纳实例变量。
- (2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。无法添加实例变量的局限可以使用字典对象解决
4、类别的作用
- 类别主要有3个作用:
- (1)将类的实现分散到多个不同文件或多个不同框架中。
- (2)创建对私有方法的前向引用。
- (3)向对象添加非正式协议。 继承可以增加,修改或者删除方法,并且可以增加属性。
- 类别主要有3个作用:
另外一篇
类别
有时我们需要在一个已经定义好的类中增加一些方法,而不想去重写该类。比如,当工程已经很大,代码量比较多,或者类中已经包住很多方法,已经有其他代码调用了该类创建对象并使用该类的方法时,可以使用类别对该类扩充新的方法。
注意:类别只能扩充方法,而不能扩充成员变量。实例分析:
- 1、目的:在我的工程中,我需要对图片进行压缩,此时我想到类别,利用类别对UIImage类进行扩展,增加图片压缩方法。
- 2、类别定义:
类别.h声明文件
#import <Foundation/Foundation.h>
@interface UIImage (UIImageExt)
//这个方法就是我添加的图片压缩的方法
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize;
@end
- 类别.m实现文件
#import "UIImageExt.h"
@implementation UIImage (UIImageExt)
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
UIImage *sourceImage = self;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO)
{
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor > heightFactor)
scaleFactor = widthFactor; // scale to fit height
else
scaleFactor = heightFactor; // scale to fit width
scaledWidth= width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else if (widthFactor < heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
UIGraphicsBeginImageContext(targetSize); // this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width= scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil)
NSLog(@"could not scale image");
//pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
@end
- 3、如何使用类别
- 在上文我已经对UIImage进行了扩展,下面如何将演示在我的工程中如何调用该方法:
//根据图片tag显示图片
-(void)showPhotoBySerialNumber:(int)imageTag;
{
//这个largeImageArray是NSMutableArray类型的,存放图片存储路径,根据路径得到UIImage
UIImage *img = [UIImage imageWithContentsOfFile:[self.largeImageArray objectAtIndex:imageTag]];
//MyScrollView是我自定义的ScrollView,目的是使ScrollView响应点击事件,关于如何自定义的ScrollView在以后的博客中,我将会阐述
MyScrollView *scrView = [[MyScrollView alloc] initWithFrame:CGRectMake(340*imageTag, 0, 320, 480)];
scrView.host = self;
//这句就是调用了类别,通过UIImage实例对象,调用imageByScalingAndCroppingForSize:类别
scrView.image = [img imageByScalingAndCroppingForSize:CGSizeMake(320.0, 480.0)];
scrView.tag = imageTag+100;
//下面这句,就是把上面的scrView塞到imageScrollView上,imageScrollView是UIScrollView类型
[self.imageScrollView addSubview:scrView];
[scrView release];
}
二、协议
- 协议(protocol)类似于java语言里的接口(interface),定义了一组方法,而不提供具体实现, 只有那些“遵守”(conform to)或“采用”(adopt)了这些Protocol的类来给出自己的实现。
协议不是类本身,它们仅定义了其它对象有责任实现的接口。当在自己的类中实现协议的方法时,用户的类就是遵守这个协议的,协议声明的方法可以被任何一个类实现。
1、协议的语法结构如下:
@protocol ProtocolName //协议名
methodDeclaration; //方法名 @end
- 2、如何使用协议
- 而在类声明时,语法如下:
@interface ClassName : ParentClassName < ProtocolName>
- 然后在该类的实现文件中,实现该协议的方法methodDeclaration
实例分析
- 下面以在我的工程项目中协议的使用方法,这里只要讲我自己定义的协议。
- 1)该实例的目的:使在ScrollView上面的UIImageView响应点击事件
- 2)协议定义:
- 在类的.h声明文件中定义协议
#import <Foundation/Foundation.h>
//协议ImageTouchDelegate
@protocol ImageTouchDelegate
//协议中声明的方法
-(void)imageTouch:(NSSet *)touches withEvent:(UIEvent *)event whichView:(id)imageView;
@end
@interface ImageTouchView : UIImageView {
id<ImageTouchDelegate> delegate;
}
@property(nonatomic,assign)id<ImageTouchDelegate> delegate;
@end
- 该类的.m实现文件如下
#import "ImageTouchView.h"
@implementation ImageTouchView
@synthesize delegate;
-(id)initWithFrame:(CGRect)frame
{
if (self == [super initWithFrame:frame])
{
[self setUserInteractionEnabled:YES];
}
return self;
}
-(BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
return YES;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[delegate imageTouch:touches withEvent:event whichView:self];
}
@end
3)如何使用协议?
前面我已经定义了ImageTouchDelegate,那么如何使用该协议的方法呢?
当某个类要采用该协议时,在类的声明中列出协议的名称即可,如果要采用多个协议时,在后面的尖括号中以逗号分隔,加入即可。
- 当在类采用了该协议时,就要在除了.h文件中进行声明外,还必须在它的.m实现文件中对声明的协议中的方法进行实现。还以上述我们已经定义好的协议为例,演示在我的工程中如何实现该协议。
在我的类中,首先在.h声明文件中,采用协议ImageTouchDelegate
#import <UIKit/UIKit.h>
//引入定义协议ImageTouchDelegate的头文件
#import "ImageTouchView.h"
//把协议名放到父头后面的尖括号里面,如果有多个协议,用逗号分隔
@interface PhotoOnShotViewController : UIViewController<ImageTouchDelegate> {
}
@end
- 下面要在类的.m实现文件中实现该协议定义的方法
#import "PhotoOnShotViewController.h"
@implementation PhotoOnShotViewController
//实现协议中定义的方法,
-(void)imageTouch:(NSSet *)touches withEvent:(UIEvent *)event whichView:(id)imageView{
}
- 可以的话,Give me a star!
项目开发中封装一个BarButtonItem类别-很实用的更多相关文章
- MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得。
MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得. 之前的项目比较简单,多是用JSP .Servlet + JDBC 直接搞定,在项目中尝试用 Strut ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
- Java项目开发中实现分页的三种方式一篇包会
前言 Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...
- 《Maven在Java项目开发中的应用》论文笔记(十七)
标题:Maven在Java项目开发中的应用 一.基本信息 时间:2019 来源:山西农业大学 关键词:Maven:Java Web:仓库:开发人员:极限编程; 二.研究内容 1.Maven 基本原理概 ...
- 炼金术(1): 识别项目开发中的ProtoType、Demo、MVP
软件开发是很分裂的,只有不断使用原则和规律,才能带来质量. 只要不是玩具性质的项目,项目应该可以大概划分为0-1,1-10,10-100,100-1000四个种重要阶段.其中,0-1是原型验证性的:1 ...
- 如何在项目开发中应用好“Deadline 是第一生产力”?
我想也许你早就听说过"Deadline是第一生产力"这句话,哪怕以前没听说过,我相信看完本文后,再也不会忘记这句话,甚至时不时还要感慨一句:"Deadline是第一生产力 ...
- MyBatis 项目开发中是基于 XML 还是注解?
只要你对 MyBatis 有所认识和了解,想必知道 MyBatis 有两种 SQL 语句映射模式,一种是基于注解,一种是基于XML. 基于 XML <mapper namespace=" ...
- 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)
本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...
- iPhone开发中从一个视图跳到另一个视图有三种方法:
iPhone开发中从一个视图跳到另一个视图有三种方法: 1.self.view addSubView:view .self.window addSubView,需要注意的是,这个方法只是把页面加在 ...
随机推荐
- ionic 字体的导入方法
更换字体 这是第一个图标(蜜蜂推荐)是撸主原来的图标 这是UI给的效果图的图标,显然默认的图标不符合要求 查找图标所在的样式,在tabs.html文件中 <ion-tabs class=&quo ...
- html01基本标签
01. <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8 ...
- 嵌套repeater
通过外层repeater的值来进行内层repeater的数据绑定 前台代码部分: <asp:repeater runat="server" id="repeater ...
- Debugging Failed Because Integrated Windows Authentication Is Not Enabled
To enable integrated Windows authentication Log onto the Web server using an administrator account. ...
- android:http下载文件并保存到本地或SD卡
想把文件保存到SD卡中,一定要知道SD卡的路径,获取SD卡路径: Environment.getExternalStorageDirectory() 另外,在保存之前要判断SD卡是否已经安装好,并且可 ...
- DHCP租约时间工作原理
问题: 很多用户在使用路由器的DHCP服务器过程中都有一个疑问,DHCP有个设置项目是设置DHCP地址的租约时间,如果设置的比较短,是否会出现租约时间到了以后会重新去获取ip地址,造成用户断网? ...
- sql用户权限
登录 1)右键根目录属性 点下面的sql server 和 windows 身份验证模式 2)安全性右键新建,选择登陆 去掉 那个"用户下次登陆是必须改密码" ,下面默认数据库改为 ...
- EIGRP认证 配置 (仅仅是命令 原理自己去看书) 转自:http://blog.163.com/s_u/blog/static/13308367201111771831631/
EIGRP认证 目的:掌握EIGRP的MD5认证 拓扑:这里IP配置我就不写出来了,应该对大家来说是非常简单的事了,就要细心一点就可以了.首先我们在R1上启用MD5认证R1(config)#key c ...
- animation中的steps()逐帧动画
在我们平时做宽高确定,需要背景图片切换的效果时,我如果用的是一张大的png图片.而且恰好是所有小图都是从左向右排列的,那么 我们只需测量出某一个小图距左侧有多少像素(x),然后我们banckgroun ...
- 国内开源html5游戏引擎全收录
本文引自<国内开源html5游戏引擎全收录> 游戏开发这潭水太深,英文水平太差,不敢看国外的, 而且这几年国内技术水平也挺高了不少,特别是JS方面.(我个人感觉) 最近看了几个国产的js游 ...