在移动端产品的开发过程中,很多时候我们需要在某个View的top或者bottom的位置添加一条分割线。遇到这样的需求你是怎么解决的呢?欢迎各位简友们分享自己的做法。
我们通常的解决方式,就是添加一个subview,到相应的位置;然后把该subview.backgroundColor设置成我们想要的颜色。这样确实解决了,视觉效果上的问题。但是长期下来,我个人还是觉得有点低效...
今天分享的就是我目前所使用的为view添加分割线的方法。总体思路这样的:
(1).首先创建一个继承自UIView类的WHView类(该类名你可以自己指定),添加属性:
@property (nonatomic, retain) UIColor *separatorColor;
(2).接着我们创建一个枚举类型(标识View的哪些位置需要绘制分割线),并为WHView添加属性:
typedef NS_OPTIONS(NSUInteger, WHViewSeparatorMode){
KWHViewSeparatorModeNone = 1 << 0,
KWHViewSeparatorModeTop = 1 << 1,
KWHViewSeparatorModeBottom = 1 << 2,
KWHViewSeparatorModeLeft = 1 << 3,
KWHViewSeparatorModeRight = 1 << 4,
KWHViewSeparatorModeAll = KWHViewSeparatorModeTop |KWHViewSeparatorModeBottom |KWHViewSeparatorModeLeft |KWHViewSeparatorModeRight
};
@property (nonatomic, assign) WHViewSeparatorMode separatorMode;
(3).创建一个WHView的分类WHView (WHViewSeparator),利用runtime机制,替换drawRect:方法。在替换的方法中,绘制边缘线。
完整的代码如下:
WHView.h中代码如下:
#import <UIKit/UIKit.h> typedef NS_OPTIONS(NSUInteger, WHViewSeparatorMode){
KWHViewSeparatorModeNone = 1 << 0,
KWHViewSeparatorModeTop = 1 << 1,
KWHViewSeparatorModeBottom = 1 << 2,
KWHViewSeparatorModeLeft = 1 << 3,
KWHViewSeparatorModeRight = 1 << 4,
KWHViewSeparatorModeAll = KWHViewSeparatorModeTop|KWHViewSeparatorModeBottom|KWHViewSeparatorModeLeft|KWHViewSeparatorModeRight
}; @interface WHView : UIView @property (nonatomic, retain) UIColor *separatorColor; @property (nonatomic, assign) WHViewSeparatorMode separatorMode; @end @interface WHView(WHViewSeparator) @end
WHView.m中代码如下:
#import "WHView.h" #import <objc/runtime.h> @implementation WHView - (instancetype)initWithFrame:(CGRect)frame{ if(self = [super initWithFrame:frame]){ self.backgroundColor = [UIColor whiteColor]; self.separatorMode = KWHViewSeparatorModeNone;
} return self;
}
- (UIColor *)separatorColor{ if(_separatorColor != nil){ return _separatorColor;
} return [UIColor lightGrayColor];
}
- (void)setSeparatorMode:(WHViewSeparatorMode)separatorMode{
_separatorMode = separatorMode;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{ NSLog(@"______1:drawRect%@", self.class);
} @end #define KWHSeparatorWidth (1.0/[[UIScreen mainScreen] scale]) @implementation WHView(WHViewSeparator) + (void)load{
[super load]; //在这里替换view的drawRect方法 //替换的目的在于,我们需要在替换过的__drawRect:方法中绘制分割线,绘制完毕再调回原来的drawRect:方法。 static dispatch_once_t predicate; dispatch_once(&predicate, ^{
Method drawRect = class_getInstanceMethod(self, @selector(drawRect:));
Method __drawRect = class_getInstanceMethod(self, @selector(__drawRect:));
method_exchangeImplementations(drawRect, __drawRect);
});
}
- (void)__drawRect:(CGRect)rect{ NSLog(@"______0:drawRect%@", self.class); CGContextRef contextRef = UIGraphicsGetCurrentContext(); CGContextSetLineWidth(contextRef, KWHSeparatorWidth); CGContextSetStrokeColorWithColor(contextRef, [self.separatorColor CGColor]); CGRect rc = self.frame; //根据NS_OPTIONS枚举类型的特性,为外部设置的_separatorMode,分别绘制。 if(self.separatorMode & KWHViewSeparatorModeTop){ CGContextMoveToPoint(contextRef, 0, 0+KWHSeparatorWidth/2); CGContextAddLineToPoint(contextRef, rc.size.width, 0+KWHSeparatorWidth/2); CGContextDrawPath(contextRef, kCGPathStroke);
} if(self.separatorMode & KWHViewSeparatorModeBottom){ CGContextMoveToPoint(contextRef, 0, rc.size.height-KWHSeparatorWidth/2); CGContextAddLineToPoint(contextRef, rc.size.width, rc.size.height-KWHSeparatorWidth/2); CGContextDrawPath(contextRef, kCGPathStroke);
} if(self.separatorMode & KWHViewSeparatorModeLeft){ CGContextMoveToPoint(contextRef, 0+KWHSeparatorWidth/2, 0); CGContextAddLineToPoint(contextRef, 0+KWHSeparatorWidth/2, rc.size.height); CGContextDrawPath(contextRef, kCGPathStroke);
} if(self.separatorMode & KWHViewSeparatorModeRight){ CGContextMoveToPoint(contextRef, rc.size.width-KWHSeparatorWidth/2, 0); CGContextAddLineToPoint(contextRef, rc.size.width-KWHSeparatorWidth/2, rc.size.height); CGContextDrawPath(contextRef, kCGPathStroke);
}
[self __drawRect:rect];
} @end
核心代码截屏如下:
至此,我们完成了WHView类的封装。我们设置的默认的分割线的额颜色为[UIColor lightGrayColor];宽度为一个像素,默认类型为无分割线。在实际运用中,我们直接用WHView去初始化我们想要的view,然后设置separatorMode即可。
另外,学习了上边的方法后,我们最好能明白以下几个问题:
(1).为什么要用分类来实现绘制的机制?
(2).runtime是否是真的懂?
(3).在drawRect:方法的末尾为什么仍然调用drawRect:?(会不会循环调用?为啥不是直接调用drawRect:)
- 本文固定链接: https://zxbcw.cn/post/5023/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)