drawRect 没有在 UI 元素上绘制
drawRect is not drawing over a UI element
TL/DR 版本:我试图在 UISlider
上方画一条线,而不是在它下方。
我正在覆盖 UISlider
的 drawRect
方法以便在其上画线。由于某些原因,滑块进度条与我画的线重叠,看起来像这样:
你几乎看不到标记,因此我需要以不同的方式绘制。这是我为绘制所述线条而编写的代码:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 20);
for (NSNumber *x in self.lines) {
CGContextMoveToPoint(context, x.floatValue + 175, 45);
CGContextAddLineToPoint(context, x.floatValue + 175, rect.size.height - 50);
CGContextStrokePath(context);
}
}
我认为这会很好,但不行。所以,我在这个网站上做了一些研究,我可以得出的结论是我需要覆盖 layoutSubViews
.
完美,所以我在方法的开头添加了 [super layoutSubviews];
;
像这样:
- (void)drawRect:(CGRect)rect {
[super layoutSubviews];
... // all other code
}
没有帮助。从代码中可以看出,我将线条颜色设置为 [UIColor whiteColor]
,但它看起来很难看,即使我覆盖了 layoutSubViews
。我希望它看起来像这样:
注意-对于任何试图这样做或类似的人,如下 rmaddy 所述:
"Overriding the drawRect: method of a control provided by Apple is a
really bad idea. It's fragile and likely to break in some iOS update."
我这样做是为了快速修补,如果您不需要,最好不要这样做。
UI 元素是您的视图的子视图。 drawRect
填充视图本身的内容,但其子视图绘制在视图之上。如果要在 over 视图及其子视图上绘制,则需要将自己的子视图添加到滑块,或者将整个滑块嵌入到单独的父视图中,该父视图有自己的子视图滑块顶部的子视图。
您可以在调试器中查看滑块的视图层次结构,使用 recursiveDescription 方法:
(lldb) po [slider recursiveDescription]
<UISlider: 0x7fd7e3e43b60; frame = (0 0; 100 100); opaque = NO; layer = <CALayer: 0x7fd7e3e42460>; value: 0.000000>
| <UIView: 0x7fd7e7077e20; frame = (16 49; 82 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e7077f30>>
| | <UIImageView: 0x7fd7e70765e0; frame = (-14 0; 96 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e7076310>>
| <UIImageView: 0x7fd7e7077b40; frame = (2 49; 14 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e70767d0>>
| <UIImageView: 0x7fd7e3d1d880; frame = (0 34; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e3d1d9c0>>
| | <UIImageView: 0x7fd7e3d1d400; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e3d1ba50>>
您可以在调试器中隐藏和取消隐藏视图,以查看哪些视图负责滑块中的哪些内容。两个点高的视图之一是滑块拇指后面的蓝色条。另一个将是滑块拇指前面的栏。 31x31 图像视图是拇指。您使用 drawRect:
绘制的任何内容都将进入顶级滑块视图 本身 (在示例中,地址为 0x7fd7e3e43b60
的视图)。然后所有的子视图都在上面绘制。
刚好你画的画在UISlider里面的最小和最大轨道图像视图后面。你可以这样做,这样你就可以创建一个单独的视图,假设是 LineView,然后将它添加到你的 UISlider,将这个子视图带到最顶部的 zIndex 并对该视图进行线条绘制。查看我已经完成的实现,以进一步了解如何实现。
@interface LineView: UIView
@property (nonatomic, strong) NSArray *lines;
@end
@implementation LineView
- (void)setLines:(NSArray *)lines
{
_lines = lines;
[self setNeedsDisplay];
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.opaque = YES;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
// disable the touch as UISlider has thumb view as a separate view which actually needs to handle touch events
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
const CGFloat lineWidth = 5;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, lineWidth);
for (NSNumber *x in self.lines) {
CGContextMoveToPoint(context, x.floatValue , self.bounds.size.height);
CGContextAddLineToPoint(context, x.floatValue + 20, self.bounds.size.height);
CGContextStrokePath(context);
}
}
@end
@interface MySlider : UISlider
@property (nonatomic, strong) UIView *lineView;
@property (nonatomic, strong) NSArray *lines;
@end
@implementation MySlider
- (void)setLines:(NSArray *)lines
{
self.lineView.lines = lines;
}
- (NSArray *)lines
{
return self.lineView.lines;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.lineView = [[LineView alloc] initWithFrame:self.bounds];
[self addSubview:self.lineView];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self bringSubviewToFront:self.lineView];
}
@end
并从外部接口设置。
mySlider.lines = @[@0, @50, @100, @160, @180, @250];
这是结果,
TL/DR 版本:我试图在 UISlider
上方画一条线,而不是在它下方。
我正在覆盖 UISlider
的 drawRect
方法以便在其上画线。由于某些原因,滑块进度条与我画的线重叠,看起来像这样:
你几乎看不到标记,因此我需要以不同的方式绘制。这是我为绘制所述线条而编写的代码:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextSetLineWidth(context, 20);
for (NSNumber *x in self.lines) {
CGContextMoveToPoint(context, x.floatValue + 175, 45);
CGContextAddLineToPoint(context, x.floatValue + 175, rect.size.height - 50);
CGContextStrokePath(context);
}
}
我认为这会很好,但不行。所以,我在这个网站上做了一些研究,我可以得出的结论是我需要覆盖 layoutSubViews
.
完美,所以我在方法的开头添加了 [super layoutSubviews];
;
像这样:
- (void)drawRect:(CGRect)rect {
[super layoutSubviews];
... // all other code
}
没有帮助。从代码中可以看出,我将线条颜色设置为 [UIColor whiteColor]
,但它看起来很难看,即使我覆盖了 layoutSubViews
。我希望它看起来像这样:
注意-对于任何试图这样做或类似的人,如下 rmaddy 所述:
"Overriding the drawRect: method of a control provided by Apple is a really bad idea. It's fragile and likely to break in some iOS update."
我这样做是为了快速修补,如果您不需要,最好不要这样做。
UI 元素是您的视图的子视图。 drawRect
填充视图本身的内容,但其子视图绘制在视图之上。如果要在 over 视图及其子视图上绘制,则需要将自己的子视图添加到滑块,或者将整个滑块嵌入到单独的父视图中,该父视图有自己的子视图滑块顶部的子视图。
您可以在调试器中查看滑块的视图层次结构,使用 recursiveDescription 方法:
(lldb) po [slider recursiveDescription]
<UISlider: 0x7fd7e3e43b60; frame = (0 0; 100 100); opaque = NO; layer = <CALayer: 0x7fd7e3e42460>; value: 0.000000>
| <UIView: 0x7fd7e7077e20; frame = (16 49; 82 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e7077f30>>
| | <UIImageView: 0x7fd7e70765e0; frame = (-14 0; 96 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e7076310>>
| <UIImageView: 0x7fd7e7077b40; frame = (2 49; 14 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e70767d0>>
| <UIImageView: 0x7fd7e3d1d880; frame = (0 34; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e3d1d9c0>>
| | <UIImageView: 0x7fd7e3d1d400; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fd7e3d1ba50>>
您可以在调试器中隐藏和取消隐藏视图,以查看哪些视图负责滑块中的哪些内容。两个点高的视图之一是滑块拇指后面的蓝色条。另一个将是滑块拇指前面的栏。 31x31 图像视图是拇指。您使用 drawRect:
绘制的任何内容都将进入顶级滑块视图 本身 (在示例中,地址为 0x7fd7e3e43b60
的视图)。然后所有的子视图都在上面绘制。
刚好你画的画在UISlider里面的最小和最大轨道图像视图后面。你可以这样做,这样你就可以创建一个单独的视图,假设是 LineView,然后将它添加到你的 UISlider,将这个子视图带到最顶部的 zIndex 并对该视图进行线条绘制。查看我已经完成的实现,以进一步了解如何实现。
@interface LineView: UIView
@property (nonatomic, strong) NSArray *lines;
@end
@implementation LineView
- (void)setLines:(NSArray *)lines
{
_lines = lines;
[self setNeedsDisplay];
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.opaque = YES;
self.backgroundColor = [UIColor clearColor];
}
return self;
}
// disable the touch as UISlider has thumb view as a separate view which actually needs to handle touch events
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
const CGFloat lineWidth = 5;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextSetLineWidth(context, lineWidth);
for (NSNumber *x in self.lines) {
CGContextMoveToPoint(context, x.floatValue , self.bounds.size.height);
CGContextAddLineToPoint(context, x.floatValue + 20, self.bounds.size.height);
CGContextStrokePath(context);
}
}
@end
@interface MySlider : UISlider
@property (nonatomic, strong) UIView *lineView;
@property (nonatomic, strong) NSArray *lines;
@end
@implementation MySlider
- (void)setLines:(NSArray *)lines
{
self.lineView.lines = lines;
}
- (NSArray *)lines
{
return self.lineView.lines;
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.lineView = [[LineView alloc] initWithFrame:self.bounds];
[self addSubview:self.lineView];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self bringSubviewToFront:self.lineView];
}
@end
并从外部接口设置。
mySlider.lines = @[@0, @50, @100, @160, @180, @250];
这是结果,