创建UINavigationBarButton中找到的缩进外观 - 以编程方式 [英] Create the indented look found in UINavigationBarButton - programmatically

查看:95
本文介绍了创建UINavigationBarButton中找到的缩进外观 - 以编程方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图以编程方式重新创建缩进的按钮外观,可以在UINavigationBarButton上看到。不是闪亮的双色调外观或渐变,只是周边阴影:





它看起来像是围绕整个视图周边的内部黑暗阴影,在顶部稍微更暗?然后一个外部突出阴影周围的下方视图。



我使用Core Graphics播放了一些,并且使用view.layer.shadowRadius和.shadowOffset实验了QuartzCore和阴影,但是甚至不能获得低亮度看起来不错。我也不知道在哪里开始实现内部偏移的黑暗阴影和外部偏移的光阴影。

解决方案

看起来好像你想要一个看起来像阴影的边框。由于阴影呈现为某种梯度,因此将边框设置为渐变不可能一瞥。但是,可以创建一个表示边框的路径,然后使用渐变填充该路径。 Apple提供了一个似乎是一个名为。



我也在这里解释代码和我的方法:核心图形中的斜面 - 形状


I'm trying to programmatically recreate the indented button look that can be seen on a UINavigationBarButton. Not the shiny two tone look or the gradient, just the perimeter shading:

It looks like an internal dark shadowing around the entire view perimeter, slightly darker at the top? And then an external highlighting shadow around the lower view perimeter.

I've played a bit with Core Graphics, and experimented with QuartzCore and shadowing with view.layer.shadowRadius and .shadowOffset, but can't even get the lower highlighting to look right. I'm also not sure where to start to achieve both a dark shadowing with internal offset and a light shadowing with external offset.

解决方案

It seems as though you want a border that looks looks like a shadow. Since the shadow appears to some sort of gradient, setting a border as a gradient won't be possible at first glance. However, it is possible to create a path that represents the border and then fill that with a gradient. Apple provides what seems to be a little known function called CGPathCreateCopyByStrokingPath. This takes a path (say, a rounded rect, for example) and creates a new path that would be the stroke of the old path given the settings you pass into the function (like line width, join/cap setting, miter limit, etc). So lets say you define a path (this isn't exactly what Apple provides, but's it's similar):

+ (UIBezierPath *) bezierPathForBackButtonInRect:(CGRect)rect withRoundingRadius:(CGFloat)radius{
    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint mPoint = CGPointMake(CGRectGetMaxX(rect) - radius, rect.origin.y);
    CGPoint ctrlPoint = mPoint;
    [path moveToPoint:mPoint];

    ctrlPoint.y += radius;
    mPoint.x += radius;
    mPoint.y += radius;
    if (radius > 0) [path addArcWithCenter:ctrlPoint radius:radius startAngle:M_PI + M_PI_2 endAngle:0 clockwise:YES];

    mPoint.y = CGRectGetMaxY(rect) - radius;
    [path addLineToPoint:mPoint];

    ctrlPoint = mPoint;
    mPoint.y += radius;
    mPoint.x -= radius;
    ctrlPoint.x -= radius;
    if (radius > 0) [path addArcWithCenter:ctrlPoint radius:radius startAngle:0 endAngle:M_PI_2 clockwise:YES];

    mPoint.x = rect.origin.x + (10.0f);
    [path addLineToPoint:mPoint];

    [path addLineToPoint:CGPointMake(rect.origin.x, CGRectGetMidY(rect))];

    mPoint.y = rect.origin.y;
    [path addLineToPoint:mPoint];

    [path closePath];
    return path;
}

This returns a path similar to Apple's back button (I use this in my app). I have added this method (along with dozens more) as a category to UIBezierPath.

Now lets add that inner shadow in a drawing routine:

- (void) drawRect:(CGRect)rect{
    UIBezierPath *path = [UIBezierPath bezierPathForBackButtonInRect:rect withRoundingRadius:5.0f];
    //Just fill with blue color, do what you want here for the button
    [[UIColor blueColor] setFill]; 
    [path fill];

    [path addClip]; //Not completely necessary, but borders are actually drawn 'around' the path edge, so that half is inside your path, half is outside adding this will ensure the shadow only fills inside the path

    //This strokes the standard path, however you might want to might want to  inset the rect, create a new 'back button path' off the inset rect and create the inner shadow path off that.  
    //The line width of 2.0f will actually show up as 1.0f with the above clip: [path addClip];, due to the fact that borders are drawn around the edge 
    UIBezierPath *innerShadow = [UIBezierPath bezierPathWithCGPath: CGPathCreateCopyByStrokingPath(path.CGPath, NULL, 2.0f, path.lineCapStyle, path.lineJoinStyle, path.miterLimit)];
    //You need this, otherwise the center (inside your path) will also be filled with the gradient, which you don't want
    innerShadow.usesEvenOddFillRule = YES;
    [innerShadow addClip];

    //Now lets fill it with a vertical gradient
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGPoint start = CGPointMake(0, 0);
    CGPoint end = CGPointMake(0, CGRectGetMaxY(rect));
    CGFloat locations[2] = { 0.0f, 1.0f};
    NSArray *colors =  [NSArray arrayWithObjects:(id)[UIColor colorWithWhite:.7f alpha:.5f].CGColor, (id)[UIColor colorWithWhite:.3f alpha:.5f].CGColor, nil];
    CGGradientRef gradRef = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), (__bridge CFArrayRef)colors, locations);
    CGContextDrawLinearGradient(context, gradRef, start, end, 0);
    CGGradientRelease(gradRef);
}

Now this is just a simple example. I don't save/restore contexts or anything, which you'll probably want to do. There are things you might still want to do to make it better, like maybe inset the 'shadow' path if you want to use a normal border. You might want to use more/different colors and locations. But this should get you started.

UPDATE

There is another method you can use to create this effect. I wrote an algorithm to bevel arbitrary bezier paths in core graphics. This can be used to create the effect you're looking for. This is an example of how I use it in my app:

You pass to the routine the CGContextRef, CGPathRef, size of the bevel and what colors you want it to use for the highlight/shadow.

The code I used for this can be found here:Github - Beveling Algorithm.

I also explain the code and my methodology here: Beveling-Shapes in Core Graphics

这篇关于创建UINavigationBarButton中找到的缩进外观 - 以编程方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆