最近看到很多人问一个问题,就是自定义了一个视图,视图测试的时候是可以正常使用的,但是加到工程里面去不响应点击。
其实这个问题的本质就是响应者链,你的视图控件没有被加进响应者链里,那是必然不会响应的。
至于不会被加进响应者链的情况通常是以下的情况:
1.视图本身的userInteractionEnabled为NO。这个属性是view的一个基本属性,你自定义的视图都会继承这个属性,如果你设置了这个属性为NO,或者你的父视图这个属性为NO(比如UIImage,默认情况下userInteractionEnabled=NO)。那么你的视图不会被加进响应者链也是必然的现象了。
2.你可能会说我设置了userInteractionEnabled=YES啊,这就是第二个经常出现的错误了,你确认那一句执行了么?
通常对于一个自定义的view,载入的方式有两种:
1.alloc-init的方式,这个是通过调用视图的initWithFrame函数或者init函数获得一个视图实例。
2.loadNibNamed或者xib的方式,这个方式并不会调用init和initWithFrame函数,而是调用awakeFromNib函数,换句话说,你如果在init函数中设置了userInteractionEnabled=YES,但是你是通过xib的方式来加载视图的时候,那么这句是不会执行的,是无效的。你的视图依然不会响应。
关于awakeFromNib只是增加的一个类目,让你在使用loadNibNamed的过程中可以做一些事情,和viewdidload是不同的。详细如下:
awakeFromNib
当.nib文件被加载的时候,会发送一个awakeFromNib的消息到.nib文件中的每个对象,每个对象都可以定义自己的awakeFromNib函数来响应这个消息,执行一些必要的操作。
也就是说只有通过.nib文件创建view对象时才会执行awakeFromNib 。
一般的,当IB加载的时候,我们会通过调用自定义对象的awakeFromNib函数,来对界面进行补充。
选择的时机:当你需要写一个UIView的子类并且想在load nib的时候做一些初始化工作的时候很有用。bundle在load nib后会给每个view对象发送一个awakeFromNib消息。
viewDidLoad
当view对象被加载到内存时就会执行viewDidLoad,所以不管是通过.nib文件还是以代码的方式创建对象都会执行viewDidLoad。
UI设计给出了设计图,界面却是不错,看着霸气十足,可是里面的控件,都需要自定义,没有一个不需要折腾的,也罢,就一直在折腾了。折腾中遇到一个问题,UISlder的完全自定义,完全摒弃原生态的东西,开始有点无厘头,慢慢页折腾出来了,今天给出一些关键代码和demo,只是简单的实现,很多功能有待发掘。
首先看一下UI给出的效果图:
网上有一种自定义UISlider的方法,但是最后放弃了,因为依然没有达到所需,也是比人才疏学浅。
下面就是我自定义的类UISlider的部分代码:
1、首先我声明了一个继承子UIView的类,因为我觉的使用UIView页绘制更加快捷。
//
// Slider.h
// SliderPro
//
// Created by Yongchao Zhang on 12-9-13.
// Copyright (c) 2012年 Yongchao Zhang. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol SliderDelegate;
@interface Slider : UIView{
//放置时间
UIImageView *popView;
//箭头
UIImageView *tagView;
UILabel *currentLabel;
UILabel *totalLabel;
NSString *currentStr;
NSString *totalStr;
float minValue, maxValue;
float currentValue;
float percent;
UIImageView *bottomView;
UIImageView *topView;
}
@property (nonatomic,readwrite) float minValue, maxValue, currentValue;
@property (nonatomic,strong) UILabel *currentLabel,*totalLabel;
@property (nonatomic,strong) NSString *currentStr,*totalStr;
@property (nonatomic,unsafe_unretained)id<SliderDelegate> delegate;
@end
@protocol SliderDelegate <NSObject>
-(void)scrollBegin:(Slider *)sender;
-(void)scroll:(Slider *)sender;
-(void)scrollDone:(Slider*)sender;
@end
2、在实现的时候,需要掌握三种情况的计算,最左边、最右边、中间位置。因为那个小箭头是需要实时的移动的,不同的位置小箭头的上面所谓的时间view移动的不同。
//
// Slider.m
// SliderPro
//
// Created by Yongchao Zhang on 12-9-13.
// Copyright (c) 2012年 Yongchao Zhang. All rights reserved.
//
#import "Slider.h"
#import <QuartzCore/QuartzCore.h>
@implementation Slider
@synthesize currentValue,maxValue,minValue;
@synthesize currentLabel,totalLabel;
@synthesize currentStr,totalStr;
@synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
minValue = 0;
maxValue = 1;
currentValue = 0;
self.backgroundColor = [UIColor redColor];
self.userInteractionEnabled = YES;
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
//上半部分整体
popView= [[UIImageView alloc] init];
popView.userInteractionEnabled = NO;
// [popView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"timeBack.png"]]];
[popView setImage:[UIImage imageNamed:@"timeBack.png"]];
[self addSubview:popView];
//时间部分
UIView *timeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, popView.frame.size.width, self.frame.size.height/2 - 20)];
[timeView setBackgroundColor:[UIColor greenColor]];
currentLabel = [[UILabel alloc]init];
[currentLabel setBackgroundColor:[UIColor blackColor]];
[currentLabel setTextColor:[UIColor whiteColor]];
[currentLabel setTextAlignment:UITextAlignmentLeft];
[timeView addSubview:currentLabel];
totalLabel = [[UILabel alloc]init];
[totalLabel setBackgroundColor:[UIColor greenColor]];
// [totalLabel setTextColor:UIColorFromRGB(0x73736f)];
[totalLabel setTextColor:[UIColor redColor]];
[totalLabel setTextAlignment:UITextAlignmentLeft];
[timeView addSubview:totalLabel];
[popView addSubview:timeView];
//箭头部分
tagView = [[UIImageView alloc] init];
tagView.userInteractionEnabled = NO;
// [tagView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"tag.png"]]];
[tagView setImage:[UIImage imageNamed:@"tag.png"]];
[self addSubview:tagView];
//下半部分
UIImage *stetchLeftTrack = [UIImage imageNamed:@"done.png"] ;
UIImage *stetchRightTrack = [UIImage imageNamed:@"max.png"] ;
bottomView= [[UIImageView alloc] initWithImage:stetchRightTrack];
[bottomView setFrame:CGRectMake(5, popView.frame.origin.y + popView.frame.size.height + tagView.frame.size.height+20 , self.frame.size.width-10, 6)];
CALayer *layers = [bottomView layer];
[layers setMasksToBounds:YES];
[layers setCornerRadius:4.0];
topView= [[UIImageView alloc] initWithImage:stetchLeftTrack];
[topView setFrame:CGRectMake(0, 0 , self.frame.size.width-10, 6)];
[bottomView addSubview:topView];
[self addSubview:bottomView];
}
-(void)layoutSubviews{
[popView setFrame:CGRectMake(0, 0, 72, self.frame.size.height/2-18)];
[tagView setFrame:CGRectMake(0, popView.frame.origin.y + popView.frame.size.height-1, 6, 3)];
[currentLabel setFrame:CGRectMake(4, 2.0f, 30, 10)];
currentLabel.font=[UIFont systemFontOfSize:7.0f];
[totalLabel setFrame:CGRectMake(38, 2.0f, 30, 10)];
totalLabel.font=[UIFont systemFontOfSize:7.0f];
currentLabel.text = currentStr;
totalLabel.text = totalStr;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
CGPoint xy = [touch locationInView:self];
float pointX = xy.x-bottomView.frame.origin.x;
if(pointX<0)
pointX =0;
if(pointX > bottomView.frame.size.width)
pointX = bottomView.frame.size.width;
percent = pointX / bottomView.frame.size.width;
currentValue = percent *maxValue;
[self updateProView:pointX];
[self.delegate scrollBegin:self];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
CGPoint xy = [touch locationInView:self];
float pointX = xy.x-bottomView.frame.origin.x;
if(pointX<0)
pointX =0;
if(pointX > bottomView.frame.size.width)
pointX = bottomView.frame.size.width;
percent = pointX / bottomView.frame.size.width;
currentValue = percent *maxValue;
[self updateProView:pointX];
[self.delegate scroll:self];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
CGPoint xy = [touch locationInView:self];
float pointX = xy.x-bottomView.frame.origin.x;
if(pointX<0)
pointX =0;
if(pointX > bottomView.frame.size.width)
pointX = bottomView.frame.size.width;
percent = pointX / bottomView.frame.size.width;
currentValue = percent *maxValue;
[self updateProView:pointX];
[self.delegate scrollDone:self];
}
-(void)updateProView:(float)_pointx{
CGRect rect = topView.frame;
rect.size.width = _pointx;
topView.frame = rect;
float realX = _pointx + bottomView.frame.origin.x;
CGRect popRect = popView.frame;
popRect.origin.x = realX-popRect.size.width/2;
if(realX < popRect.size.width/2){
popRect.origin.x = 0;
}
if(realX >self.frame.size.width - popRect.size.width/2){
popRect.origin.x = self .frame.size.width - popRect.size.width;
}
CGRect sanRect = tagView.frame;
sanRect.origin.x = realX - sanRect.size.width/2;
if(sanRect.origin.x < (bottomView.frame.origin.x - sanRect.size.width/2) )
sanRect.origin.x = bottomView.frame.origin.x - sanRect.size.width/2;
if(sanRect.origin.x > (bottomView.frame.origin.x +bottomView.frame.size.width - sanRect.size.width/2))
sanRect.origin.x = bottomView.frame.origin.x +bottomView.frame.size.width - sanRect.size.width/2;
tagView.frame = sanRect;
popView.frame = popRect;
}
-(void)setMinValue:(float)_minValue{
minValue = _minValue;
}
-(void)setMaxValue:(float)_maxValue{
maxValue = _maxValue;
}
-(void)setCurrentValue:(float)_value{
currentValue = _value;
percent = currentValue /maxValue;
float pointX = percent * bottomView.frame.size.width;
[self updateProView:pointX];
}
@end
注:代码比较乱,也难免有错误,毕竟只是为了验证思路而已。最近项目中经常有文字放光效果的UI,特意在网路上找了下,开始是在code4app中找到一个,但是是不是的会出现不出现光晕的bug,在寻找找到了cocoachina会员hxy060799分享的GlowLabel,效果不错,特意写了注释贴出来,以防他日忘记。
1、新建一个基于UILabel的子类
2、在这个子类中定义red、green、blue三个颜色值变量和一个发光光晕范围变量size。
3、复写UILable的drawTextInRect方法,并使用CGContextRef来进行光晕效果绘制。
基本思路就是这样子了,下面是部分主要代码:
.h文件
//创建UILable的子类 GlowLable @interface GlowLabel : UILabel //定义颜色值全局变量和放大值全局变量 @property(assign,nonatomic)float redValue; @property(assign,nonatomic)float greenValue; @property(assign,nonatomic)float blueValue; @property(assign,nonatomic)float size; @end
.m文件
@implementation GlowLabel
@synthesize redValue;
@synthesize greenValue;
@synthesize blueValue;
@synthesize size;
-(id) initWithFrame: (CGRect)frame {
if ((self = [super initWithFrame:frame])) {
//变量初始化
redValue = 0.0f;
greenValue = 0.50f;
blueValue = 1.0f;
size=20.0f;
}
return self;
}
//重写UILable类的drawTextInRect方法
-(void) drawTextInRect: (CGRect)rect {
//定义阴影区域
CGSize textShadowOffest = CGSizeMake(0, 0);
//定义RGB颜色值
float textColorValues[] = {redValue, greenValue, blueValue, 1.0};
//获取绘制上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//保存上下文状态
CGContextSaveGState(ctx);
//为上下文设置阴影
CGContextSetShadow(ctx, textShadowOffest, size);
//设置颜色类型
CGColorSpaceRef textColorSpace = CGColorSpaceCreateDeviceRGB();
//根据颜色类型和颜色值创建CGColorRef颜色
CGColorRef textColor = CGColorCreate(textColorSpace, textColorValues);
//为上下文阴影设置颜色,阴影颜色,阴影大小
CGContextSetShadowWithColor(ctx, textShadowOffest, size, textColor);
[super drawTextInRect:rect];
//释放
CGColorRelease(textColor);
CGColorSpaceRelease(textColorSpace);
//重启上下文
CGContextRestoreGState(ctx);
}
@end最终效果: