您的当前位置:首页正文

如何为你的UIView添加边缘分割线

来源:华佗小知识

在移动端产品的开发过程中,很多时候我们需要在某个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

核心代码截屏如下:

WHViewSeparator.png

至此,我们完成了WHView类的封装。我们设置的默认的分割线的额颜色为[UIColor lightGrayColor];宽度为一个像素,默认类型为无分割线。在实际运用中,我们直接用WHView去初始化我们想要的view,然后设置separatorMode即可。

另外,学习了上边的方法后,我们最好能明白以下几个问题:
(1).为什么要用分类来实现绘制的机制?
(2).runtime是否是真的懂?
(3).在__drawRect:方法的末尾为什么仍然调用__drawRect:?(会不会循环调用?为啥不是直接调用drawRect:)