自定义控件
在- (instancetype)initWithFrame:(CGRect)frame
里自定义控件
在- (void)layoutSubviews 里布局控件
名字叫attributes并且是NSDictionary *类型的参数,它的key一般都有以下规律
1.iOS7开始
1> 所有的key都来源于: NSAttributedString.h
2> 格式基本都是:NS***AttributeName
2.iOS7之前
1> 所有的key都来源于: UIStringDrawing.h
2> 格式基本都是:UITextAttribute***
NSString * title = [button currentTitle]; // 获取按钮当前title文字
CGSize size = [title sizeWithAttributes:@{NSFontAttributeName:button.titleLabel.font}];//根据字体计算大小
_titleUnderLine.backgroundColor = [titleButton titleColorForState:UIControlStateSelected]; //根据按钮title 颜色设置下划线颜色
cell分割线顶头操作
1.第一种方法,利用系统的属性去设置
项目中经常会有些需求是cell 的分割线顶头,而系统默认的是前面有一定的间距,其实这是由一个separatorInset 属性造成的(iOS7以后出的),通过打印:
- (void)viewDidAppear:(BOOL)animated
{
NXLog(@"margin:%@",NSStringFromUIEdgeInsets(self.tableView.separatorInset));
}
打印结果:
margin:{0, 15, 0, 0} //可以看出来系统默认有一个15的偏移量
将该属性设置为空,现在tableView里面设置:
self.tableView.separatorInset = UIEdgeInsetsZero; //分隔线顶头,这个只是设置tableView 顶头,还需要在cell里设置cell的顶头
通过这一步设置发现分割线比之前左移了不少,但是还没顶到头,这里就判断是cell自身的原因
同时在cell 里面进行设置:
self.separatorInset = UIEdgeInsetsZero;//cell分割线顶头
这时候运行再看结果,已经OK顶到头。
tableView底层实现
1.tableView 先把所有cell 的尺寸计算好,保存到一个数组里。
2.当cell 要显示的时候就拿到这个cell 去设置frame : cell.frame = frames[row]。
2.第二种方法,重写cell 的setFrame,可以随意设置cell 的间距,比较万能。
主要思路:主要就是利用了上面的tableView 的实现原理。
1.首先设置tableView的背景色为分割线的颜色。
2.禁掉系统的分割线
3.在cell类中重写setFrame 方法。
self.tableView.backgroundColor = NXColor(220, 220, 221);
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
//在自定义的cell类中:
- (void)setFrame:(CGRect)frame
{
NXLog(@"cellFrame:%@",NSStringFromCGRect(frame));
//因为之前的frame 都是计算好的,这是在要显示的时候去设置一下,所以这里只去将高度减1,不会影响到其他尺寸
frame.size.height -=1; // 如果想要间距更大的话可以 -=10 等,随意这种方法比较万能
//这个才是系统真正的设置frame。重写了这个方法会将系统的frame清空,所以需要调用这个
[super setFrame:frame];
}
屏幕适配
1.一个view从Xib 加载,需不需要重新固定一下尺寸? 这个是一定得需要的,比较保险。
2.一般添加xib view的时候是在viewDidLoad 里面加载,但是设置尺寸frame 最好在viewDidLayoutSubViews 里面去设置。因为viewDidLoad 并不会去布局frame ,只是拿到xib 设置的大小属性,只有在 viewDidLayoutSubViews 里才会去根据布局去确定控件的最终尺寸(不过添加view 的操作不能放在这里,因为这个方法会调用多次)
🌰:
- (void)viewDidLoad {
[super viewDidLoad];
UIView * loginView = [NXLoginRegistView loginView];
[self.middleView addSubview:loginView];
UIView * registView = [NXLoginRegistView registView];
[self.middleView addSubview:registView];
UIView * fastLogin = [NXFastLoginView fastLoginView];
[self.bottomView addSubview:fastLogin];
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
//在这里面设置尺寸
UIView * loginView = [self.middleView subviews][0];
loginView.frame = CGRectMake(0, 0, self.middleView.frame.size.width * 0.5, self.middleView.frame.size.height);
UIView * registView = [self.middleView subviews][1];
registView.frame = CGRectMake(self.middleView.frame.size.width * 0.5, 0, self.middleView.frame.size.width * 0.5, self.middleView.frame.size.height);
UIView * fastLogin = [self.bottomView subviews][0];
fastLogin.frame = CGRectMake(0, 0, self.bottomView.frame.size.width, self.bottomView.frame.size.height);
}
从Xib加载的view 设置动画
是通过操作约束去设置,比如要修改x值产生动画就找到x的约束拖线添到类文件中成为属性,然后对该属性进行操作,在设置动画时,必须加上这句 :
[self.view layoutIfNeeded]; //这句话很重要,只有重新布局才会产生动画效果,否则没有动画效果
例如
[UIView animateWithDuration:1 animations:^{
self.testViewWidthConstraint.constant = 200;
[self.view layoutIfNeeded]; //这句话很重要,只有重新布局才会产生动画效果,否则没有动画效果
}];
一个xib文件可以管理多个view
重写button 的布局
这个在项目中也很常见,默认的按钮布局是左右布局,即左边imageView + 右边label 。而好多项目中需要的是上下布局,所以需要自定义button,重新布局。这里在layoutSubViews 方法里面进行,因为在这个方法里面所有的控件尺寸都已经是计算好的,我们就不需要重新去计算,只要改一下布局就可以。
🌰:
- (void)layoutSubviews
{
[super layoutSubviews];
self.imageView.nx_y = 0;
self.imageView.nx_centerX = self.nx_centerX;
self.titleLabel.nx_y = self.nx_height - self.titleLabel.nx_height;
self.titleLabel.nx_centerX = self.nx_centerX;
}
自定义tabBar的问题
项目中需要定制tabBar 的时候需要用到自定义tabBar,这里需要注意的是不能直接通过如下的赋值语法进行替换:
🌰:
NXTabBar * nTabBar = [[NXTabBar alloc]init];
self.tabBar = nTabBar;
这样替换的话是没有效果的,需要用KVC 的形式进行替换:
[self setValue:nTabBar forKey:@"tabBar"];
iOS类私有属性的访问和修改
http://www.jianshu.com/p/a667f0ce9573
iOS 类别中添加属性(属性和实例变量的区别)
【转】iOS中属性与成员变量的区别
iOS Category中添加属性和成员变量的区别
通过category 和 runtime 设置textField 的 placehold 的颜色
项目中经常会用到textField ,比如登录注册等。默认的光标是蓝色,而且placeholder的文字颜色也是灰的,不会变化。有时候项目会需求点击后光标为白色,同时placeholder 的文字高亮为白色(或其他颜色)。通过头文件一级一级往上查找,找到了一个如下属性:
@property(nullable, nonatomic,copy) NSAttributedString *attributedPlaceholder
利用这个属性,用如下方法进行颜色修改:
//第一个参数: 需要被设置属性的字符串
//第二个参数: 需要设置的属性
self.attributedPlaceholder = [[NSAttributedString alloc]initWithString:self.placeholder attributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
这个方法虽然达到效果了,但是比较麻烦,通过如下图的方式,随便写一个textField ,然后打上短点,我们可以看到在textField 内部有placeholderLabel的属性,所以可以尝试通过对该属性进行操作,直接修改颜色。不过通过下面的调试框可以看到这是一个私有属性。想要对私有属性进行访问和修改可以使用kvc 或者 runtime ,这里使用kvc ,新建一个类别,添加属性placeholderColor,在set 方法里面去进行设置:
🌰:
h 文件
#import <UIKit/UIKit.h>
@interface UITextField (NXTextField)
@property (nonatomic ,strong)UIColor *placeholdColor;
@end
m 文件
- (void)setPlaceholdColor:(UIColor *)placeholdColor
{
//根据判断,textField 内部的 placehold 是一个label 的标签
UILabel * placeholderLabel = [self valueForKey:@"placeholderLabel"];
placeholderLabel.textColor = placeholdColor;
}
- (UIColor *)placeholdColor{
return nil; // 暂时先不用,返回一个nil ,去掉系统的警告⚠️
}
然后可以在需要设置的地方引入category 的头文件,通过如下方式即可设置颜色:
self.placeholdColor = [UIColor lightGrayColor];
通过上面category 的方式基本可以满足需求,但是如果textField 如下设置的时候就会出现无效:
// 这样设置是可以的:
self.placeholder = @"44444";
self.placeholdColor = [UIColor lightGrayColor];
//将上面的换个顺序执行,就会无效:
self.placeholdColor = [UIColor lightGrayColor];
self.placeholder = @"44444";
//这是因为之前没有设置placeholder文字,设置颜色的时候通过断点可以看到,此时获取不到placeholderLabel,所以导致设置颜色无效。
解决这个问题就需要用到runtime
1.先将 placeholderColor 保存起来
2.在设置placeholder 的时候再取出来设置颜色
- (void)setPlaceholdColor:(UIColor *)placeholdColor
{
//先将placeholdColor 存起来
//参数一:给哪个对象添加成员属性
//参数二:成员属性的名字
//参数三:成员属性的值
objc_setAssociatedObject(self, @"placeholdColor", placeholdColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//根据判断,textField 内部的 placehold 是一个label 的标签
UILabel * placeholderLabel = [self valueForKey:@"placeholderLabel"];
placeholderLabel.textColor = placeholdColor;
}
- (UIColor *)placeholdColor{
return objc_getAssociatedObject(self, @"placeholdColor");
}
//自顶一个setPlaceholder方法,在内部1.先设置文字。 2.设置颜色
- (void)setNX_Placeholder:(NSString *)placeholder
{
self.placeholder = placeholder;
self.placeholdColor = self.placeholdColor;
}
上面方法有个缺点就是每次设置placeholder文字还得去调用
[self setNX_Placeholder:@"hhhh"];
所以想要直接通过: ** self.placeholder = @"hhhh"; 去设置,就需要用到方法交换。因为交换只需要做一次操作,所以,放到+(void)load**方法里去操作,在category文件中加入:
+ (void)load{
Method setPlaceholder = class_getInstanceMethod(self, @selector(setPlaceholder:));
Method setNx_Placeholder = class_getInstanceMethod(self, @selector(setNX_Placeholder:));
method_exchangeImplementations(setPlaceholder, setNx_Placeholder);
}
计算总行数的万能公式
row = (count -1 ) / column +1;
#tableView 调整cell 间距
>用storyBoard 拖出来的cell 默认显示的是如下图的间距(因为要使用到静态单元格,所以用到storyBoard,一般情况下用xib最好)
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-1b72dbea6ce3c123.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这里用的是分组style,所以可以通过设置
self.tableView.sectionFooterHeight = 0;
self.tableView.sectionHeaderHeight = 0;
得到如下效果:
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-13edc8b059e545ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到每个分组之间的间距已经没了,但是第一个cell 距离顶部还是有好大一部分距离,这里判断可能是tableView 的间距,通过下面打印
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-ae86d387b8e4f8e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到tableView 距离顶部确实有64 的偏移量,但是这个刚好是空出导航栏的高度,所以排除是tableView 的问题,接下来就判断是cell 的问题,通过下面打印
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-bc281de06bbc0996.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
可以看到分组内部第一个cell 的Y 值默认是35 ,那么这里可以在viewDidLoad 方法里进行如下调整就可以(这里需要间隔为10)
self.tableView.sectionFooterHeight = 0;
self.tableView.sectionHeaderHeight = 10;
self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0);
#跳转到网页
>1.`Safari openURL` 自带很多功能:进度条,刷新,前进,倒退等功能。但是需要跳出到当前应用。
2.`UIWebView` 在当前应用打开网页,并且带有Safari(自己实现),不能实现进度条。
3.`SFSafariViewController` 专门用来显示网页,既可以在当前应用显示网页,又可以有Safari的功能。iOS9以后才可以用。
4.WKWebView
#判断view 是否被加载
随便一个都可以:
UIViewController * vc = self.childViewControllers[button.tag];
if (vc.isViewLoaded) {//如果已经被加载过就不重复加载(加载view 的时候会调用 viewDidLoad)
return ;
}
UIView * view = vc.view;
if (view.superview) { // 如果有父view ,说明已经被添加过
return;
}
if (view.window) { //如果有容器,说明已经被添加过
return;
}
# 一些全局常量,尽量使用extern来引用,其次再选择考虑Macro
>[iOS const的使用](http://www.cnblogs.com/oumygade/p/4316024.html)
[关于全局常量的定义](http://www.jianshu.com/p/ed2dfbca6e73)
#xib cell 拖线报错: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x8a4b500> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key
>如下图,我已开始在File`s Owner里也设置了class是NXTopicCell,所以一直出错,这里吧他清空,设置下面的Topic Cell 的class如下就可以
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-ab6ca235996cb993.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>xib拖的UILabel 没有自动换行:设置约束时不要给定高度就可以自动换行了。
#在heightForRowAtIndexPath获取cell 崩溃
http://www.jianshu.com/p/3da539540d21
>在网上看到有人是这么获取:
NXTopicCell * cell = (NXTopicCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
试了下好像是可以。
>好像xib 里设置的高度是定死的,不会根据不同屏幕去重新计算高度。
##退出键盘
>1.监听scrollView实时滚动代理方法调用[self.view endEditing:YES]或者[self.textField resignFirstResponse];
2.touchBegin方法里,调用[self.view endEditing:YES]或者[self.textField resignFirstResponse];
##父View添加手势,子View不要去响应父View点击事件
[iOS 点击子视图不让其响应父视图手势](http://www.it610.com/article/4821007.htm)
>在做这样一个界面的时候
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/972822-719483b12316733c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
>背景的蒙版层是一个UIView,按钮的列表View添加到背景的蒙版View上。在蒙版层添加一个手势,点击dismiss掉这个界面和蒙版。但是遇到问题就是在点击按钮列表的View的时候也出发了单击手势。这个好像是系统默认的,参考事件响应链。为了避免这种效果,在手势触发事件中可以判断当前点击事件是否在父View上,如果是子View上则不去做操作,点击在父View上才去做dismiss的操作。代码如下:
-
(void)dismissMoreActionView:(UITapGestureRecognizer *)tap
{
//根绝tag获取子view
UIView *subView = [self viewWithTag:100];/*
BOOL contains = CGRectContainsPoint(CGRect rect, CGPoint point);
判断一个CGRect是否包含再另一个CGRect里面,常用与测试给定的对象之间是否又重叠- (CGPoint)locationInView:(UIView *)view:
该函数返回一个CGPoint类型的值,表示触摸在view这个视图上的位置,这里返回的位置是针对view的坐标
*/
// 判断手势点击的位置是不是包含在子视图上
if (!CGRectContainsPoint(subView.frame, [tap locationInView:self])) {
[self removeFromSuperview];
}
}
- (CGPoint)locationInView:(UIView *)view:
----------------------
## 调整导航栏leftBarButtonItem 和 rightBarbuttonItem 的偏移量
[ 如何调整导航条上的leftBarButtonItem和rightBarButtonItem的位置](http://yikuwang.blog.51cto.com/6186082/1696156)
> ####重点:
这里需要提到BarButtonSystemItem的样式- UIBarButtonSystemItemFixedSpace
我不多说 请看官方解释:Blank space to add between other items. Only the [width](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIBarButtonItem_Class/index.html#//apple_ref/occ/instp/UIBarButtonItem/width) property is used when this value is set. 反正我是看不懂 。再来说说negativeSpacer.width = 0 表示leftBarButtonItem的x离屏幕的左边还有15像素 同样表示rightBarButtonItem的CGRectGetMaxX()离屏幕的右边还有15像素 那么好像我们就可以通过negativeSpacer.width来调整leftBarButtonItem的位置。搞了老半天原来就是得靠这家伙。但有一点:negativeSpacer.width赋值负数对于leftBarButtonItem来说是左移多少像素 对于rightBarButtonItem来说是右移多少像素 反之亦然.
我这里想要设置右边的item 右移一点,因为默认的太偏左了:
UIButton * buyBtn = [[UIButton alloc]init];
buyBtn.frame = CGRectMake(0, 0, 80, 40);
buyBtn.backgroundColor = [UIColor orangeColor];
[buyBtn setTitle:@"马上选购" forState:UIControlStateNormal];
buyBtn.titleLabel.font = [UIFont systemFontOfSize:15];
[buyBtn addTarget:self action:@selector(buyItemAction) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem * buyItem = [[UIBarButtonItem alloc]initWithCustomView:buyBtn];
UIBarButtonItem * space = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
space.width = -10;
self.navigationItem.rightBarButtonItems = @[space,buyItem];
##动态修改UIButton的title 的时候字体闪烁的问题:
[UIButton-system类型 动态改变title 显示文字时闪动(解决方案)](http://blog.csdn.net/a330416020/article/details/41648787)
*******************
##assign 修饰代理导致野指针的问题
>在下面方法中调用了代理,崩溃指向这里显示野指针的错误,猜测是由于代理被释放而去调用产生的问题。点进去看到之前代理修饰用的是assign 修饰的,改为weak 后好像是可以了。猜测原因是由于assign 修饰的话 assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针。
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([_delegate respondsToSelector:@selector(numberOfRowsInTableView:Insection:FromView:)])
{
NSInteger vRows = [_dataSource numberOfRowsInTableView:tableView Insection:section FromView:self];
mRowCount = vRows;
return vRows;
}
return 0;
}
##单例问题
>在使用单例的时候,经常性就是直接写出下面的代码。不过最近在使用的时候会遇到单例导致崩溃的问题。一开始在写 `dispatch_once_t once_token`的时候没有用static 来修饰,后来加上static来修饰就好了。
-
(instancetype)shareInstance
{
static DrawTextView * drawText = nil;static dispatch_once_t once_token;
dispatch_once(&once_token, ^{
drawText = [[DrawTextView alloc]initWithFrame:CGRectMake(kDeviceW * 0.5- TextLayerWidth * 0.5, kDeviceH * 0.5 - TextLayerHeight * 0.5, TextLayerWidth, TextLayerHeight)]; drawText.backgroundColor = [UIColor orangeColor];
});
return drawText;
}
##在iPhone5s (10.2系统)拨打电话没有弹框提示,其他手机(10.3)有弹框
// 用这种方法的话会出现上面的问题
// NSString * phonNum = [NSString stringWithFormat:@"tel://%@",self.footerModel.dav_phone];
NSString * phonNum = [NSString stringWithFormat:@"telprompt://%@", self.footerModel.dav_phone];
控制器切换从下往上,并且有导航栏:
可以用CATransition 动画,或者直接用presentModalViewController。
http://www.cocoachina.com/bbs/read.php?tid=7668
改变SearchBar 的取消按钮颜色,光标颜色
DBL_EPSILON和 FLT_EPSILON的用法
DBL_EPSILON和 FLT_EPSILON主要用于单精度和双精度的比较当中:
比较方式
double b = sin(M_PI / 6.0);
if (fabs(((double)valueint)-value)<=DBL_EPSILON)
(is int num);
else
(is double num)
EPSILON是最小误差。如果整数值减去浮点数值误差低于DBL_EPSILON,则说明该数可以近似看成整数,否则则是浮点数……
绘制渐变的UIImage
首先网上找到的是第一种的方法,
1.先生成一个渐变图层
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
CGFloat navigationBarHeight = statusBarRect.size.height + self.navigationController.navigationBar.frame.size.height;
gradientLayer.frame = CGRectMake(0, 400, [UIScreen mainScreen].bounds.size.width, navigationBarHeight);
gradientLayer.colors = @[(id)[UIColor colorWithRed:22/255.0 green:112/255.0 blue:188/255.0 alpha:1].CGColor,(id)[UIColor colorWithRed:30/255.0 green:26/255.0 blue:150/255.0 alpha:1].CGColor];
gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1, 0.5);
2.通过渐变图层绘制图片:
- (UIImage *)imageFromLayer:(CALayer *)layer
{
UIGraphicsBeginImageContextWithOptions(layer.frame.size, layer.opaque, [UIScreen mainScreen].scale);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * outImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outImage;
}
但是如上的方法好像并没有生成想要的图片。
网上找到第二种,可以生成想要的图片:
/**
* 获取矩形的渐变色的UIImage(此函数还不够完善)
*
* @param bounds UIImage的bounds
* @param colors 渐变色数组,可以设置两种颜色
* @param gradientType 渐变的方式:0--->从上到下 1--->从左到右
*
* @return 渐变色的UIImage
*/
- (UIImage*)gradientImageWithBounds:(CGRect)bounds andColors:(NSArray*)colors andGradientType:(int)gradientType{
NSMutableArray *ar = [NSMutableArray array];
for(UIColor *c in colors) {
[ar addObject:(id)c.CGColor];
}
UIGraphicsBeginImageContextWithOptions(bounds.size, YES, 1);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGColorSpaceRef colorSpace = CGColorGetColorSpace([[colors lastObject] CGColor]);
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)ar, NULL);
CGPoint start;
CGPoint end;
switch (gradientType) {
case 0:
start = CGPointMake(0.0, 0.0);
end = CGPointMake(0.0, bounds.size.height);
break;
case 1:
start = CGPointMake(0.0, 0.0);
end = CGPointMake(bounds.size.width, 0.0);
break;
}
// 线性渐变
CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGGradientRelease(gradient);
CGContextRestoreGState(context);
CGColorSpaceRelease(colorSpace);
UIGraphicsEndImageContext();
return image;
}
还有一些其他类似方法,参考如下:iOS实现颜色渐变
画线控件(支持xib和storyboard)
自定义一个控件,继承自UIView,.h文件声明属性
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface ADHouseSourceDottedLine : UIView
@property (nonatomic ,assign)IBInspectable CGFloat lineWidth;
@property (nonatomic ,strong)IBInspectable UIColor * lineColor;
@property (nonatomic ,assign)IBInspectable CGFloat paddingLeft;
@property (nonatomic ,assign)IBInspectable CGFloat paddingRight;
@property (nonatomic ,assign)IBInspectable CGFloat paddingTop;
@property (nonatomic ,assign)IBInspectable CGFloat paddingBottom;
@property (nonatomic ,assign)IBInspectable BOOL isHorizontal;
@property (nonatomic ,assign)IBInspectable BOOL isDash;
@property (nonatomic ,assign)IBInspectable CGFloat dashPointWidth;
@property (nonatomic ,assign)IBInspectable CGFloat dashSpace;
@end
NS_ASSUME_NONNULL_END
然后再.m文件里面,@implementation前面用IB_DESIGNABLE修饰。
#import "ADHouseSourceDottedLine.h"
IB_DESIGNABLE
@implementation ADHouseSourceDottedLine
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGFloat bx = 0,by = 0,ex = 0,ey = 0;
if (_isHorizontal) {
bx = _paddingLeft;
by = rect.size.height * 0.5;
ex = rect.size.width - _paddingRight;
ey = by;
}else
{
bx = rect.size.width * 0.5;
by = _paddingTop;
ex = bx;
ey = rect.size.height - _paddingBottom;
}
// 画中间虚线
// CGMutablePathRef path = CGPathCreateMutable();
// CGPathMoveToPoint(path, NULL, bx, by);
// CGPathAddLineToPoint(path, NULL, ex, ey);
CGContextMoveToPoint(currentContext, bx, by);
CGContextAddLineToPoint(currentContext, ex, ey);
// 2、 添加路径到图形上下文
// CGContextAddPath(currentContext, path);
CGContextSetLineWidth(currentContext, _lineWidth / [UIScreen mainScreen].scale);
CGContextSetStrokeColorWithColor(currentContext, _lineColor.CGColor);
if (_isDash) {
CGFloat lengths[] = {_dashPointWidth , _dashSpace};
CGContextSetLineDash(currentContext, 0, lengths, 2);
}
// 4、 绘制图像到指定图形上下文
// CGContextDrawPath(currentContext, kCGPathFill);
CGContextStrokePath(currentContext);
}
@end
参考:# 在OC和Swift中使用IBDesignable/IBInspectable
Swift 画线控件(支持xib和storyboard)