如何绘制不同颜色的填充路径/形状

Posted

技术标签:

【中文标题】如何绘制不同颜色的填充路径/形状【英文标题】:How to draw a filled path/shape in different colors 【发布时间】:2013-07-02 00:42:19 【问题描述】:

我需要在我的屏幕上为一个形状上色,任何我想要的颜色。我目前正在尝试使用我想根据自己的愿望重新着色的 UIImage 来做到这一点。据我所知,做到这一点的唯一方法是获取 UIImage 的各个像素,这需要我想编写更多代码行来解决这个问题。除了我写的以外,还有什么方法可以改变 UIImage 颜色吗?在上下文中绘制形状并填充它会更容易吗?

TY.

更新: 六边形以正确的方式绘制自己,但它根本没有正确填充。代码如下:

self.Hexagon.lineWidth=10;
[self.Hexagon moveToPoint:CGPointMake(hexWidth/2, 0)];
[self.Hexagon addLineToPoint:CGPointMake(hexWidth, hexHeight/4)];
[self.Hexagon addLineToPoint:CGPointMake(hexWidth, hexHeight*0.75)];
[self.Hexagon addLineToPoint:CGPointMake(hexWidth/2, hexHeight)];
[self.Hexagon addLineToPoint:CGPointMake(0, hexHeight*0.75)];
[self.Hexagon addLineToPoint:CGPointMake(0, hexHeight/4)];
[self.Hexagon addLineToPoint:CGPointMake(hexWidth/2, 0)];

[self.Hexagon closePath];
[[UIColor blackColor] setStroke];
[self.Hexagon stroke];

[[UIColor whiteColor] setFill];
[self.Hexagon fill];

【问题讨论】:

与使用 CoreGraphics 为矢量化图像着色相比,以编程方式为位图中的形状(即 UIImage)着色要困难得多。也许您可以让我们更多地了解您在这里制作的产品? 我正在尝试布置一些六边形并按照我所说的填充它们。它们是平铺的,但由于形状的性质,一些 UIImageView 是重叠的。您能否链接到有关您提到的内容或在此处回答的教程? 【参考方案1】:

我建议使用CAShapeLayer。您甚至可以为填充颜色设置动画。你的表现会非常好,你的内存使用率会很低。

此函数创建一个包含六边形的 CGPath:(基于 OP 问题)

CGPathRef CGPathCreateHexagon( CGFloat hexWidth, CGFloat hexHeight )

    CGMutablePathRef p = CGPathCreateMutable() ;
    CGPathMoveToPoint( p, NULL,  hexWidth * 0.5, 0.0 ) ;
    CGPathAddLineToPoint( p, NULL,  hexWidth, hexHeight * 0.75 ) ;
    CGPathAddLineToPoint( p, NULL, hexWidth, hexHeight * 0.75 ) ;
    CGPathAddLineToPoint( p, NULL, hexWidth * 0.5, hexHeight ) ;
    CGPathAddLineToPoint( p, NULL, 0.0, hexHeight * 0.75 ) ;
    CGPathAddLineToPoint( p, NULL, hexWidth * 0.5, 0.0 ) ;
    CGPathAddLineToPoint( p, NULL, 0.0, hexHeight * 0.25 ) ;
    CGPathAddLineToPoint( p, NULL, hexWidth * 0.5, 0.0 ) ;
    CGPathCloseSubpath( p ) ;

    return p ;

设置UIView时使用的方法:

-(void)addHexagonLayer
        
    CAShapeLayer * layer = [ CAShapeLayer layer ] ;
    layer.lineWidth = 10.0 ;
    
        CGPathRef p = CGPathCreateHexagon( 100.0, 100.0 ) ;
        layer.path = p ;
        CGPathRelease( p ) ;
           
    layer.fillColor = [[ UIColor redColor ] CGColor ] ; // put your fill color here

    layer.position = (CGPoint) CGRectGetMidX( self.view.bounds ), CGRectGetMidY( self.view.bounds )  ; // position your hexagon layer appropriately.
    [ self.view.layer addSublayer:layer ] ; // add layer to your view and position appropriately        


编辑我创建了一个完整的演示只是为了好玩:

#import "AppDelegate.h"

static CGPathRef CGPathCreateHexagon( CGAffineTransform * t, CGFloat w, CGFloat h )

    CGFloat w_4 = w * 0.25 ;
    CGFloat w_2 = w * 0.5f ;
    CGFloat h_2 = h * 0.5f ;

    CGMutablePathRef p = CGPathCreateMutable() ;
    CGPathAddLines( p, t, (CGPoint[])
         -w_4, h_2 ,  w_4, h_2 ,  w_2, 0 ,  w_4, -h_2 ,  -w_4, -h_2 ,  -w_2, 0 
    , 6 ) ;
    CGPathCloseSubpath( p ) ;

    return p ;


@implementation CALayer (SetPositionPixelAligned)

-(CGPoint)pixelAlignedPositionForPoint:(CGPoint)p

    CGSize size = self.bounds.size ;
    CGPoint anchorPoint = self.anchorPoint ;

    CGPoint result = (CGPoint) roundf( p.x ) + anchorPoint.x * fmodf( size.width, 2.0f ), roundf( p.y ) + anchorPoint.y * fmodf( size.height, 2.0f )  ;
    return result;


@end

@interface HexagonsView : UIView
@property ( nonatomic ) CGFloat hexHeight ;
@property ( nonatomic ) CGFloat hexWidth ;
@property ( nonatomic, readonly ) CGPathRef hexagonPath ;
@end

@implementation HexagonsView
@synthesize hexagonPath = _hexagonPath ;

-(void)dealloc

    CGPathRelease( _hexagonPath ) ;
    _hexagonPath = NULL ;


-(CGPathRef)hexagonPath

    if ( !_hexagonPath )
    
        _hexagonPath = CGPathCreateHexagon( NULL, self.hexWidth, self.hexHeight ) ;
    

    return _hexagonPath ;


-(void)setHexWidth:(CGFloat)w

    _hexWidth = w ;
    CGPathRelease( _hexagonPath ) ;
    _hexagonPath = NULL ;


-(void)setHexHeight:(CGFloat)h

    _hexHeight = h ;
    CGPathRelease( _hexagonPath ) ;
    _hexagonPath = NULL ;


-(void)layoutSubviews

    [ super layoutSubviews ] ;
    CGRect bounds = self.bounds ;
    bounds.size.height += self.hexHeight * 0.5 ;    // make sure we cover last row ;

    CGPoint p ;
    p.x = CGRectGetMinY( bounds ) ;

    while( p.y < CGRectGetMaxY( bounds ) )
    
        p.x = CGRectGetMinX( bounds ) ;
        while( p.x < CGRectGetMaxX( bounds ) )
        
            
                CAShapeLayer * layer = [ CAShapeLayer layer ] ;
                layer.path = self.hexagonPath ;
                layer.fillColor = [[ UIColor colorWithHue:(CGFloat)arc4random_uniform( 100 ) / 256.0  saturation:1.0 brightness:1.0 alpha:1.0 ] CGColor ]  ;
                layer.position = [ layer pixelAlignedPositionForPoint:p ] ;
                [ self.layer addSublayer:layer ] ;
            

            CGPoint p2 =  p.x + self.hexWidth * 0.75f, p.y + self.hexHeight * 0.5f  ;

            if ( p2.y < CGRectGetMaxY( bounds ))    // no unnecessary hexagons
            
                CAShapeLayer * layer = [ CAShapeLayer layer ] ;
                layer.path = self.hexagonPath ;
                layer.fillColor = [[ UIColor colorWithHue:(CGFloat)arc4random_uniform( 256 ) / 256.0  saturation:1.0 brightness:1.0 alpha:1.0 ] CGColor ]  ;
                layer.position = [ layer pixelAlignedPositionForPoint:p2 ] ;
                [ self.layer addSublayer:layer ] ;
            

            p.x += self.hexWidth * 1.5 ;
        
        p.y += self.hexHeight ;
    


@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];

    HexagonsView * view = [[ HexagonsView alloc ] initWithFrame:self.window.bounds ] ;
    view.hexHeight = 100.0f ;
    view.hexWidth = 100.0f ;

    [ self.window addSubview:view ] ;

    [self.window makeKeyAndVisible];
    return YES;


@end

【讨论】:

有默认的六边形吗? 没有内置make hexagon函数。我修改了答案。 要用六边形填充您的视图,覆盖 -layoutSubviews 并在那里创建/定位您的六边形图层。 你介意我使用这些代码吗?你也是为 OSX 写的吗?我认识大部分语法,但其中一些与我习惯的略有不同。也许我只是一个新手。 当然——你可以使用它。它适用于 ios + ARC。您可以将UIColor 替换为NSColor,将UIView 替换为NSView,我认为它会起作用。【参考方案2】:

创建一个描述您的形状的 UIBezierPath,然后使用它的填充方法绘制您想要的颜色。

【讨论】:

您能解释一下这是如何工作的吗?我试过ctx.addPath(path.cgPath); ctx.setFillColor(color.cgColor); path.fill()没有成功【参考方案3】:

子类化 UIView 并添加以下代码:

- (void)drawRect:(CGRect)rect
 

        CGContextRef context = UIGraphicsGetCurrentContext(); 

//Set color of the border
        CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
//Set color of the fill
        CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);

        // Set width of border line
        CGContextSetLineWidth(context, 2.0);

//Pseudocode: Draw your hexagons with something like this
        for(int idx = 0; idx < self.points.count; idx++)
        

            point = [self.points objectAtIndex:idx];//Edited 
            if(idx == 0)
            
                // move to the first point
                CGContextMoveToPoint(context, point.x, point.y);
            
            else
            
//Add a point to the hexagon. The last point should be equal to the first point
                CGContextAddLineToPoint(context, point.x, point.y);
            
        
//Fill in the hexagon
        CGContextDrawPath(context, kCGPathFillStroke)

对您要绘制的每个六边形重复此操作。理想情况下,您会将六边形的所有点放在一个数组中以便于参考。

【讨论】:

不要忘记“并填写”部分;)你想要的是CGContextDrawPath(context, kCGPathFillStroke) 这个实现会对性能产生很大的负面影响吗?我会画一百多个六边形。 我不认为我会使用数组的想法,我只需要根据视图的位置来绘制它。感谢您的编码想法!

以上是关于如何绘制不同颜色的填充路径/形状的主要内容,如果未能解决你的问题,请参考以下文章

Android 按钮使用相同的 Drawable 形状但使用不同的颜色

绘制路径

如何填充画布上的“对面”形状?

如何自定义 MKPolyLineView 绘制不同风格的线条

PS绘制飘逸彩色丝带教程

当使用洪水填充算法填充颜色后绘制线条时,填充颜色消失