【问题标题】:Adjacent CAShapeLayer Antialiasing Issue相邻 CAShapeLayer 抗锯齿问题
【发布时间】:2013-12-10 18:24:02
【问题描述】:

我正在为饼图的每个切片使用 CAShapeLayer 绘制饼图。即使一个饼图切片的结束角度等于相邻切片的开始角度,如果切片之间的边界成一定角度,抗锯齿也会导致每个切片切片之间出现底层背景颜色。

我想在仍然使用抗锯齿的同时消除切片之间的微小间隙,这样生成的饼图仍然看起来很平滑。从概念上讲,似乎有一种方法可以对整个 CALayer 应用抗锯齿,并且在绘制所有饼片之后它是饼片子层,这样就可以解决问题......饼片将相互抗锯齿而不是背景。

我已经尝试过尽可能多的 CALayer 属性,但很难找到更多关于这方面的信息。有什么想法吗?

更新:请看下面我的回答。

【问题讨论】:

    标签: ios objective-c graphics core-animation quartz-graphics


    【解决方案1】:

    你可能无法让你的馅饼切片边缘完全没有裂缝地相遇。最简单的解决办法就是不要尝试。

    不要让你的饼图在边缘相遇,而是让它们重叠。将第一个切片绘制为完整的圆盘:

    然后将第二个切片绘制成一个完整的圆盘,除了第一个切片的适当区域:

    然后将第三个切片画成一个完整的圆盘,除了前两个切片的适当区域:

    等等:

    这是我的代码:

    #import "PieView.h"
    
    @implementation PieView {
        NSMutableArray *slices;
    }
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self) {
            // Initialization code
        }
        return self;
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        [self layoutSliceLayers];
    }
    
    - (void)layoutSliceLayers {
        if (slices == nil) {
            [self createSlices];
        }
        [slices enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            [self layoutSliceLayer:obj index:idx];
        }];
    }
    
    static const int kSliceCount = 5;
    
    - (void)createSlices {
        slices = [NSMutableArray arrayWithCapacity:kSliceCount];
        for (int i = 0; i < kSliceCount; ++i) {
            [slices addObject:[self newSliceLayerForIndex:i]];
        }
    }
    
    - (CAShapeLayer *)newSliceLayerForIndex:(int)i {
        CAShapeLayer *layer = [CAShapeLayer layer];
        layer.fillColor = [UIColor colorWithWhite:(CGFloat)i / kSliceCount alpha:1].CGColor;
        [self.layer addSublayer:layer];
        return layer;
    }
    
    - (void)layoutSliceLayer:(CAShapeLayer *)layer index:(int)index {
        layer.position = [self center];
        layer.path = [self pathForSliceIndex:index].CGPath;
    }
    
    - (CGPoint)center {
        CGRect bounds = self.bounds;
        return CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    }
    
    - (UIBezierPath *)pathForSliceIndex:(int)i {
        CGFloat radius = [self radius];
        CGFloat fudgeRadians = 5 / radius;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointZero
            radius:radius startAngle:2 * M_PI * i / kSliceCount
            endAngle:2 * M_PI clockwise:YES];
        [path addLineToPoint:CGPointZero];
        [path closePath];
        return path;
    }
    
    - (CGFloat)radius {
        CGSize size = self.bounds.size;
        return 0.9 * MIN(size.width, size.height) / 2;
    }
    
    @end
    

    【讨论】:

    • 非常感谢您的回复,罗布。我曾经尝试过这个解决方案,并且看到来自较暗的底层的抗锯齿伪影被抗锯齿到背景中。它在饼图周围显示为一个微妙的深色边缘,在浅色切片的外边缘特别明显。我描述的径向填充解决方案似乎效果很好。
    • @Aaron 当你抗锯齿时,你最终会在一个有效锯齿的纯色形状周围得到一圈颜色+alpha 像素。对具有相同轮廓的多个形状执行此操作,您的有效锯齿内部区域看起来不错,但您的抗锯齿区域将具有颜色(n)+alpha 叠加颜色(n-1)+alpha 叠加...颜色(0) +阿尔法。这解释了您所看到的效果。
    【解决方案2】:

    更新: Rob 的回答非常好,但可能会导致其他抗锯齿问题。我最终通过沿每个饼图切片的末端角度绘制 1pt 宽的径向线来“填充”间隙,每条线的颜色与相邻切片的颜色相同。这些线在比饼图切片低的 z 索引处绘制,因此它们位于下方。以下是没有在顶部绘制饼图时的样子:

    这是最终产品:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 2014-02-18
      • 2010-12-01
      • 2015-06-21
      • 2011-07-17
      相关资源
      最近更新 更多