我需要绘制一条半透明颜色的曲线。但如果曲线包含很多点,那么你会得到奇怪的效果。如何摆脱它?
UIBezierPath * bezierPath = [ UIBezierPath bezierPath ];
bezierPath.lineCapStyle = kCGLineCapRound;
bezierPath.lineJoinStyle = kCGLineJoinRound;
bezierPath.lineWidth = 80.0;
[ bezierPath moveToPoint:CGPointMake(50.0, 50.0) ];
for (int i = 0; i < 900; i++)
{
[ bezierPath addLineToPoint:CGPointMake(50.0 + i, 50.0) ];
}
UIGraphicsImageRendererFormat * format = [ UIGraphicsImageRendererFormat defaultFormat ];
format.scale = 1.0;
format.opaque = NO;
format.preferredRange = UIGraphicsImageRendererFormatRangeStandard;
CGSize size = CGSizeMake(1000.0, 100.0);
UIGraphicsImageRenderer * renderer = [ [ UIGraphicsImageRenderer alloc ] initWithSize:size format:format ];
UIImage * image = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[ [ UIColor clearColor ] setFill ];
[ [ UIColor colorWithWhite:0.0 alpha:0.5 ] setStroke ];
[ bezierPath stroke ];
} ];
好奇...
根据经验,
UIBezierPath
可能相当古怪。在这种情况下,我猜测这个特殊的怪癖是由内部优化引起的。
我之所以相信这种情况,是因为如果我们生成一条包含 256 个点的路径——1 个 moveTo + 255 个 addLineTo 命令——我们就看不到问题:
但是,一旦我们使用 1 moveTo + 256 addLineTo 命令——总共 257 点,我们就会得到:
解决这个问题的一个选择是渲染一个具有清晰背景和 100% 不透明描边的临时图像,然后使用 50% Alpha 渲染that图像:
// create image with solid stroke
UIImage * tmpImage = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[ [ UIColor clearColor ] setFill ];
[ [ UIColor colorWithWhite:0.0 alpha:1.0 ] setStroke ];
[ bezierPath stroke ];
} ];
// create image2 by rendering tmpImage at 50% alpha
UIImage * image2 = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[tmpImage drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:0.5];
} ];
这是一个完整的、可运行的示例——以 250 个 addLineTo 命令开始...每次点击任意位置都会使该命令增加 1:
#import <UIKit/UIKit.h>
@interface AlphaPathVC : UIViewController
@end
@interface AlphaPathVC ()
{
NSInteger nPoints;
UIImageView *imgView1;
UIImageView *imgView2;
UILabel *infoLabel;
}
@end
@implementation AlphaPathVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.systemYellowColor;
imgView1 = [UIImageView new];
imgView2 = [UIImageView new];
imgView1.backgroundColor = UIColor.whiteColor;
imgView2.backgroundColor = UIColor.whiteColor;
infoLabel = [UILabel new];
infoLabel.backgroundColor = UIColor.whiteColor;
infoLabel.numberOfLines = 0;
infoLabel.text = @"Tap anywhere to increase number of points and re-generate images...";
[self.view addSubview:imgView1];
[self.view addSubview:imgView2];
[self.view addSubview:infoLabel];
nPoints = 250;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIEdgeInsets i = self.view.safeAreaInsets;
imgView1.frame = CGRectMake(i.left + 20.0, i.top + 20.0 , 1000.0, 100.0);
imgView2.frame = CGRectMake(i.left + 20.0, i.top + 20.0 + 120.0, 1000.0, 100.0);
infoLabel.frame = CGRectMake(i.left + 20.0, i.top + 20.0 + 240.0, 200.0, 80.0);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UIBezierPath * bezierPath = [ UIBezierPath new ];
bezierPath.lineCapStyle = kCGLineCapRound;
bezierPath.lineJoinStyle = kCGLineJoinRound;
bezierPath.lineWidth = 80.0;
[ bezierPath moveToPoint:CGPointMake(50.0, 50.0) ];
infoLabel.text = [NSString stringWithFormat:@" moveTo plus\n %ld addLineTo", (long)nPoints];
for (int i = 0; i < nPoints; i++)
{
[ bezierPath addLineToPoint:CGPointMake(50.0 + i, 50.0) ];
}
UIGraphicsImageRendererFormat * format = [ UIGraphicsImageRendererFormat defaultFormat ];
format.scale = 1.0;
format.opaque = NO;
format.preferredRange = UIGraphicsImageRendererFormatRangeStandard;
CGSize size = CGSizeMake(1000.0, 100.0);
UIGraphicsImageRenderer * renderer = [ [ UIGraphicsImageRenderer alloc ] initWithSize:size format:format ];
// create image with alpha stroke
UIImage * image1 = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[ [ UIColor clearColor ] setFill ];
[ [ UIColor colorWithWhite:0.0 alpha:0.5 ] setStroke ];
[ bezierPath stroke ];
} ];
// create image with solid stroke
UIImage * tmpImage = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[ [ UIColor clearColor ] setFill ];
[ [ UIColor colorWithWhite:0.0 alpha:1.0 ] setStroke ];
[ bezierPath stroke ];
} ];
// create image2 by rendering tmpImage at 50% alpha
UIImage * image2 = [ renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext)
{
[tmpImage drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:0.5];
} ];
imgView1.image = image1;
imgView2.image = image2;
++nPoints;
}
@end
点击 7 次后看起来像这样: