iOS开发之封装水平菜单栏

一,封装
封装就是对类中的一些字段,方法进行保护,不被外界所访问到
程序书在进行书写的过程中,进行封装,重构有很多好处:
1>代码的逻辑结构会变得很清晰,降低了代码的冗余量.
2>后期维护方便,响应了"对扩展开放,对修改关闭的"思想.
....
二,自定义类
当开发iOS应用程序时,你会发现在许多场景下,你需要编写自己的自定义类。
当你需要数据和自定义行为一起打包时,自定义类就很有用了。自定义类可以使您更方便的存储一些您需要的存储的特定数据,由于自定义类是您自定义的集合,所以您可以自定义类中的属性和方法,更方便您在其他类中使用,而且自定义类的方法可以设定多个,方便您调用
一般情况下,自己定义的类类型,可分为两部分。
1.Model类,跟服务器字段,和程序字段相统一。
2.Server类(也可以叫Helper类),该Model类的操作类,来满足响应的数据操作。
类的声明与实现
规范的Objective-C类由两部分组成:接口(interface)与实现(implementation)。
接口(Interface
用于声明一个类接口的Objective-C语法如下:
@interface Test : NSObject
@end
实现(Implemenation)  
@implementation Test
@end
如果在类接口中声明任何方法,你需要在这个文件中去实现它们。
用属性存储对象的数据
考虑一下待办事项需要持有什么样的信息。你可能需要知道它的名称,创建时间,以及是否已经完成。在你的自定义XYZToDoItem类中,你将会用properties来存储这些信息。
在所在的接口文件(XYZToDoItem.h)内声明这些属性。如下面所示:
@interface Test : NSObject
@property NSString *itemName;
@property BOOL completed;
@property NSDate *creationDate;
@end
 用方法定义对象的行为
方法定义了一个对象的行为。方法是用来定义在一个类中执行任务或子程序的一段代码。方法可以访问存储在类中的数据,并且可以使用该信息来执行某种操作。
例如,为让一个待办事项(Test)有能力被标记为已完成,你可以在类的接口中添加一个markAsCompleted方法。稍后,你将在类实现中实现此方法的行为,即Implementing Methods中的描述。
@interface Test : NSObject
@property NSString *itemName;
@property BOOL completed;
@property (readonly) NSDate *creationDate;
- (void)markAsCompleted;
@end
方法参数
有参数的方法声明可以在你调用一个方法时传递一些必要信息。
举例来说,你可以从上面的代码片段修改markAsCompleted方法使之拥有一个单一的参数,它将决定该项目是否被标记为完成或者未完成。通过这种方式,你可以完成状态的项目,而不是将它设置为只完成了该项目的状态。
@interface XYZToDoItem : NSObject
@property NSString *itemName;
@property BOOL completed;
@property (readonly) NSDate *creationDate;
- (void)markAsCompleted:(BOOL)isComplete;
@end
现在,你声明的方法中有了一个BOOL类型的参数:isComplete。
三,封装水平状态栏
HorizontalMenuView.h
#import <UIKit/UIKit.h>
//创建代理协议(实现对触发选项Button按钮的监控)
@protocol HorizontalMenuProtocol <NSObject>
@optional //可选方法
@required //必须实现的
-(void)getTag:(NSInteger)tag;//获取当前选中下标值
@end
@interface HorizontalMenuView : UIView
{
    NSArray * _menuArray;  //菜单名数组(第一步:预留给外界创建菜单名接口)
}
-(void)setNameWithArray:(NSArray *)menuArray;//设置菜单名的方法(第二步:预留给外界创建菜单栏的方法)
//协议代理
@property (nonatomic,assign)id <HorizontalMenuProtocol> myDelegate;
@end</span>
HorizontalMenuView.m
#import "HorizontalMenuView.h"
@implementation HorizontalMenuView
-(void)setNameWithArray:(NSArray *)menuArray{
    _menuArray = menuArray;//接收外界传进来的菜单栏数组
 //一个间隔
    CGFloat SPACE =(self.frame.size.width)/[_menuArraycount];
    for(int i =0; i<[_menuArraycount];i++){
        UIButton * btn = [UIButtonbuttonWithType:UIButtonTypeCustom];
        btn.frame = CGRectMake(SPACE * i, 0, SPACE, self.frame.size.height);
        btn.tag = i;
        if (btn.tag==0) {
            btn.enabled = NO;
        }     
 //设置字体的颜色和状态 (用NSMutableAttributedString类实现对字符串的,颜色,状态的设置) .
         NSMutableAttributedString的使用方法请浏览下面
        //正常状态
        NSMutableAttributedString * str = [[NSMutableAttributedStringalloc]initWithString:[menuArrayobjectAtIndex:i]];
        [str addAttributes:@{NSFontAttributeName:[UIFontsystemFontOfSize:18],NSForegroundColorAttributeName:[UIColorgrayColor]}range:NSMakeRange(0,[strlength])];
        
        [btn setAttributedTitle:strforState:UIControlStateNormal];     
        //选中状态
        NSMutableAttributedString *seleStr = [[NSMutableAttributedStringalloc]initWithString:[_menuArrayobjectAtIndex:i]];
        [str addAttributes:@{NSFontAttributeName:[UIFontsystemFontOfSize:18],NSForegroundColorAttributeName:[UIColorgreenColor]}range:NSMakeRange(0, [seleStrlength])];
        [btn setAttributedTitle:seleStrforState:UIControlStateDisabled];//UIControlStateDisabled仅在button禁用时有效
         [btn addTarget:selfaction:@selector(bthTouchAction:)forControlEvents:UIControlEventTouchUpInside];
         [self addSubview:btn];
        
       //分割线
        if(i>0 &&self.frame.size.height>16){
            UIView * line = [[UIViewalloc]initWithFrame:CGRectMake(SPACE * i,8,1,self.frame.size.height-16)];
            [self addSubview:line];
        }
    }
    //底部画线
    UIView * line =[[UIViewalloc]initWithFrame:CGRectMake(0,self.frame.size.height-2.5,self.frame.size.width,1.5)];
    line.backgroundColor = [UIColorgrayColor];
    [self addSubview:line];
    
    //标识当选被选中下划线
    UIView * markLine = [[UIViewalloc]initWithFrame:CGRectMake(0,self.frame.size.height-4, SPACE+1,3)];
    markLine.tag = 999;
    markLine.backgroundColor =[UIColororangeColor];
    [self addSubview:markLine];
}
//button的触发方法
-(void)bthTouchAction:(UIButton *)sender{
    for(UIView * subViewinself.subviews){
        if([subView isKindOfClass:[UIButton class]]){
            UIButton * subBtn = (UIButton*)subView;
            if(subBtn.tag == sender.tag){
                [subBtn setEnabled:NO];
            }else{
                [subBtn setEnabled:YES];
            }
        }
    }

  //计算每个按钮间隔
    CGFloat SPACE =(self.frame.size.width)/[_menuArraycount];
    
    UIView *markView = [selfviewWithTag:999];//取到下划线markView
    
    [UIViewanimateWithDuration:0.2fanimations:^{//对下划线进行跟随触发button进行操作
        CGRect markFrame = markView.frame;
        markFrame.origin.x =sender.tag * SPACE;
        markView.frame = markFrame;
    }];
    
    if([self.myDelegaterespondsToSelector:@selector(getTag:)]){
        [self.myDelegate getTag:sender.tag];
    }
}
@end
DEMO:下载地址http://download.csdn.net/detail/lxl_815520/9450568
四,拓展
1.NSMutableAttributedString

实例化方法和使用方法
实例化方法:
1>使用字符串初始化
- (id)initWithString:(NSString *)str;
例:
NSMutableAttributedString *AttributedStr = [[NSMutableAttributedStringalloc]initWithString:@"今天天气不错呀"];
- (id)initWithString:(NSString *)str attributes:(NSDictionary *)attrs;
字典中存放一些属性名和属性值,如:
NSDictionary *attributeDict = [NSDictionarydictionaryWithObjectsAndKeys:
                               [UIFontsystemFontOfSize:15.0],NSFontAttributeName,
                                 [UIColorredColor],NSForegroundColorAttributeName,
                      NSUnderlineStyleAttributeName,NSUnderlineStyleSingle,nil];
NSMutableAttributedString *AttributedStr = [[NSMutableAttributedStringalloc]initWithString:@"今天天气不错呀" attributes:attributeDict];
- (id)initWithAttributedString:(NSAttributedString *)attester;
使用NSAttributedString初始化,跟NSMutableString,NSString类似
使用方法
为某一范围内文字设置多个属性
- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range;
为某一范围内文字添加某个属性
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
为某一范围内文字添加多个属性
- (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;
移除某范围内的某个属性
- (void)removeAttribute:(NSString *)name range:(NSRange)range;
常见的属性及说明
NSFontAttributeName  字体
NSParagraphStyleAttributeName       段落格式
NSForegroundColorAttributeName     字体颜色
NSBackgroundColorAttributeName    背景颜色
NSStrikethroughStyleAttributeName  删除线格式
NSUnderlineStyleAttributeName       下划线格式
NSStrokeColorAttributeName            删除线颜色
NSStrokeWidthAttributeName           删除线宽度
NSShadowAttributeName                 阴影
  2>实例设置文本的属性
//从网络获取的数组中拿到字典
 
NSDictionary *dataDic = @{@"Position":@"苏州",
                                              @"TrueName":@"苏州***信息科技有限公司"};
//变换字体大小及颜色positionstr拼接设置一定的格式如(),{},[]…… 
NSString *positionStr = [NSString stringWithFormat:@"(%@)",dataDic[@"Position"]];
  NSString *str = [NSString stringWithFormat:@"%@%@",dataDic[@"TrueName"],positionStr];
//初始化
 
NSMutableAttributedString *mutableStr = [[NSMutableAttributedString alloc]initWithString:str];
//限定范围
 
NSRange trueNameRange = [str rangeOfString:dataDic[@"TrueName"]];
  NSRange positionRange = [str rangeOfString:positionStr];
//设置范围属性
   
[mutableStr addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:trueNameRange];
    [mutableStr addAttribute:NSForegroundColorAttributeName value:[UIColor lightGrayColor] range:positionRange];
    [mutableStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Bold" size:16] range:trueNameRange];
    [mutableStr addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Bold" size:13] range:positionRange];

2.UIButton的用法
这段代码动态的创建了一个UIButton,并且把相关常用的属性都列举了.希望对大家有用.
1>能够定义的button类型有以下6种,
   typedef enum {
    UIButtonTypeCustom = 0, 自定义风格
    UIButtonTypeRoundedRect, 圆角矩形
    UIButtonTypeDetailDisclosure, 蓝色小箭头按钮,主要做详细说明用
    UIButtonTypeInfoLight, 亮色感叹号
    UIButtonTypeInfoDark, 暗色感叹号
    UIButtonTypeContactAdd, 十字加号按钮
 } UIButtonType;
2>forState: 这个参数的作用是定义按钮的文字或图片在何种状态下才会显现*/
    以下是几种状态
  enum {
     UIControlStateNormal = 0, 常规状态显现
     UIControlStateHighlighted = 1 << 0, 高亮状态显现
     UIControlStateDisabled = 1 << 1, 禁用的状态才会显现
     UIControlStateSelected = 1 << 2, 选中状态
     UIControlStateApplication = 0x00FF0000, 当应用程序标志时
     UIControlStateReserved = 0xFF000000 为内部框架预留,可以不管他
  };

   注释:高亮状态和选中状态的区别

           其实做要在用法上,比如你只是点击按钮,不让他一直变,就设置他的高亮状态的图片, 如果点击过后,要求按钮发生变化,松手的时候不在是普通状态的

就设置选中状态。
3>UIButton选中状态下的点击(点赞效果)

在类似点赞或切换浏览模式等功能的时候,需要用到button的选中状态:即点击后按钮切换图片,并保持这个状态,直到下一次点击.
如:

接下来我们就以这两个图片为例子.
已知点击前那张图片名字是like.png,简称"like",
嫩绿色那张图片名字是like_selected.png,简称为"like_selected"
一般做法
    分别设置按钮在normal和selected状态下的图片,点击按钮时切换按钮的选中状态:
// 省略了部分非关键代码
    [button setImage:[UIImage imageNamed:@"like"] forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected];
    [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
- (void)buttonClick:(UIButton *)button {
    button.selected = !button.selected;
}
看起来好多了,代码似乎也更加合理.
但是使用过这种方法的人应该都会遇到这样一个问题:不管按钮从normal状态转为selected状态,还是反过来,中间都会经历一个highLighted状态,这就导致在状态切换的过程中有一次图片的跳变.如图:


  • 改进
    我们可能想到给button的highted状态也设置图片:
[button setImage:[UIImage imageNamed:@"like"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"like"] forState: UIControlStateHighlighted];
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected];
这样设置后,按钮从normal变为selected的过程看起来似乎行得通了,但是,从selected再变回normal的过程还是会出现那个该死的hightLighted状态.

感到奇怪吧?我们明明已经设置了hightLighted状态下的图片,怎么回来的路行不通呢? 有没有可能从selected状态变回normal状态这个过程经历的并不是hightLighted状态,而是其他什么状态呢?

没错,这个状态就是UIControlStateSelected | UIControlStateHighlighted,我们可以理解成选中时候的高亮状态.

初学的时候对这个状态不理解,还以为是同时设置选中状态高亮状态下的图片,学习过程中发现真谛后大彻大悟.

  • 再改进
[button setImage:[UIImage imageNamed:@"like"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"like"] forState: UIControlStateHighlighted];
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected];
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected | UIControlStateHighlighted];

这样就完全达可以了,不管如何点击按钮,按钮的图片只显示两种,而且都是手指抬起来的时候改变.

更先进一点的做法

  • 重写button的setHighted:方法

我们需要自定义一个继承自UIButton的子类,并将刚才创建的button类型改为我们创建的类型.

接着在自定义button的内部重写setHighted:方法

- (void)setHighlighted:(BOOL)highlighted {

}

当然你不需要在方法里面做任何事情,这表示我们阻止了系统按钮默认的做法,屏蔽了它的高亮效果.按钮也只需简单地设置为:

[button setImage:[UIImage imageNamed:@"like"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"like_selected"] forState:UIControlStateSelected];
4.iOS中多个按钮切换选中状态
在触发方法中,进行一下的操作设置:
第一,将当前按钮的选中状态置为NO;
第二,将传入按钮的选中状态置为YES;
第三,设置当前按钮为传入按钮.

5.下面两个方法需要交给子类去重写,然后用于重新布局button。

// 返回内部UILabel的frame(位置和尺寸)
- (CGRect)titleRectForContentRect:(CGRect)contentRect;
// 返回内部UIImageView的frame(位置和尺寸)
- (CGRect)imageRectForContentRect:(CGRect)contentRect;
注意:
只要文字变动,这两个方法就会自动调用,而且最后调用的那次,可以拿到UIButton的文字内容,这样我们就可以在这里计算,然后返回最终的布局contentRect
#import <UIKit/UIKit.h>
typedef void(^tapHandler)(UIButton *sender);
@interface LxButton : UIButton
@property(nonatomic,strong)tapHandler handler;
+(id)buttonwithtype:(UIButtonType)buttonType frame:(CGRect)frame
                                             title:(NSString *)title
                                             image:(UIImage *)image
                                           handler:(tapHandler)handler;
@end

#import "LxButton.h"
#define kTitleRatio 0.2
@implementation LxButton
+(id)buttonwithtype:(UIButtonType)buttonType frame:(CGRect)frame title:(NSString *)title image:(UIImage *)image handler:(tapHandler)handler{
    LxButton * button =[super buttonWithType:buttonType];
    button.frame = frame;
    button.handler = handler;
    button.titleLabel.textAlignment =NSTextAlignmentCenter;
    button.titleLabel.font =[UIFont systemFontOfSize:12];
    [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    button.imageView.contentMode =UIViewContentModeCenter;
    [button setImage:image forState:UIControlStateNormal];
    [button setTitle:title forState:UIControlStateNormal];
    [button addTarget:button action:@selector(btnTapped:) forControlEvents:UIControlEventTouchUpInside];
    return button;
}
#pragma mark --触发方法
-(void)btnTapped:(UIButton *)sender{
    if(self.handler){
        self.handler(sender);
    }
}
pragma mark --调整内部ImageView的frame
-(CGRect)imageRectForContentRect:(CGRect)contentRect{
    CGFloat imageX =0;
    CGFloat imageY =0;
    CGFloat imageWidth =contentRect.size.width;
    CGFloat imageHeight =contentRect.size.height*(1-kTitleRatio);
    return CGRectMake(imageX, imageY, imageWidth, imageHeight);
}
#pragma mark --调整内容UILabel的frame;
-(CGRect)titleRectForContentRect:(CGRect)contentRect{
    CGFloat titleX = 0;
    CGFloat titleHeight=contentRect.size.height*kTitleRatio;
    CGFloat titleY =contentRect.size.height-titleHeight-3;
    CGFloat titleWidth =contentRect.size.width;
    return CGRectMake(titleX, titleY, titleWidth, titleHeight);
}
@end

6.其它设置

/*
* 默认情况下,当按钮高亮的情况下,图像的颜色会被画深一点,如果这下面的这个属性设置为no,
* 那么可以去掉这个功能
*/

button1.adjustsImageWhenHighlighted = NO;

/*跟上面的情况一样,默认情况下,当按钮禁用的时候,图像会被画得深一点,设置NO可以取消设置*/
button1.adjustsImageWhenDisabled = NO;

/* 下面的这个属性设置为yes的状态下,按钮按下会发光*/
button1.showsTouchWhenHighlighted = Y

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值