color buttons ios cocoa-touch uiview core-graphics quartz-graphics

ios - buttons - ionic text



Cree el aspecto sangrado que se encuentra en UINavigationBarButton-programáticamente (2)

Estoy tratando de recrear de forma programática el aspecto del botón sangrado que se puede ver en un UINavigationBarButton. No el brillante aspecto de dos tonos o el degradado, solo el sombreado del perímetro:

Parece un sombreado oscuro interno alrededor de todo el perímetro de la vista, un poco más oscuro en la parte superior. Y luego una sombra externa que resalta alrededor del perímetro de la vista inferior.

He jugado un poco con Core Graphics, y experimenté con QuartzCore y sombreando con view.layer.shadowRadius y .shadowOffset, pero ni siquiera puedo obtener el resaltado más bajo para que se vea bien. Tampoco estoy seguro de por dónde empezar para lograr un sombreado oscuro con compensación interna y un sombreado claro con compensación externa.


Usar la sombra de la capa no lo hará. Necesitas una sombra exterior ligera y una sombra interior oscura para obtener ese efecto. Una capa solo puede tener una sombra (externa). (Además, las sombras de las capas se vuelven a dibujar de forma dinámica y obligan a la renderización basada en la CPU que mata el rendimiento).

Tendrá que hacer su propio dibujo con CoreGraphics, ya sea en el método drawRect: una vista o en el método drawInContext: una capa. (O dibuja en un contexto de imagen y luego reutiliza la imagen.) Dicho dibujo usará principalmente las CGContext functions . (Voy a nombrar algunos a continuación, pero este enlace tiene documentación para todos ellos).

Para un botón rect redondo, puede resultar tedioso crear el CGPath apropiado; en su lugar, puede usar +[UIBezierPath bezierPathWithRoundedRect:cornerRadius:] y luego la propiedad CGPath la ruta para establecer la ruta actual del contexto con CGContextAddPath .

Puede crear una sombra interior configurando un trazado de recorte (vea CGContextClip y funciones relacionadas) a la forma del botón, configurando una sombra (vea CGContextSetShadowWithColor y funciones relacionadas), y luego dibujando alrededor de la forma que desea sombrear. Para la sombra interior, trazo ( CGContextStrokePath ), una CGContextStrokePath redonda que es un poco más grande que tu botón, usando un grosor de trazo grueso ( CGContextSetLineWidth ) por lo que hay mucha "tinta" para generar una sombra (recuerda, este trazo no será visible debido a la ruta de recorte).

Puede crear una sombra exterior de la misma manera: no use un trazado de recorte esta vez, porque desea que la sombra quede fuera de la forma y complete ( CGContextFillPath ) la forma de su botón en lugar de acariciarlo. Tenga en cuenta que dibujar una sombra es una especie de "modo": guarda el estado de los gráficos ( CGContextSaveGState ), configura una sombra y luego dibuja la forma de la que desea ver una sombra (la forma en sí no se dibuja cuando está en este modo), y finalmente restaurar el estado ( CGContextRestoreGState ) para salir del "modo sombra". Como ese modo no dibuja la forma, solo la sombra, tendrás que dibujar la forma por separado.

También hay una orden para hacer todo esto. Debería ser obvio si piensas en el orden en que pintarías estas cosas con medios físicos: Primero dibuja la sombra exterior, luego el relleno del botón y luego la sombra interna. Puede agregar un trazo después de eso si la sombra interna no le da un contorno suficientemente pronunciado.

Hay algunas herramientas de dibujo que pueden generar código fuente para CoreGraphics: Opacidad es la que uso. Tenga cuidado con estos, sin embargo, ya que el código que generan puede no ser eficiente.


Parece que quieres un borde que se vea como una sombra. Como la sombra aparece en una especie de gradiente, establecer un borde como un degradado no será posible a primera vista. Sin embargo, es posible crear una ruta que represente el borde y luego llenarlo con un degradado. Apple proporciona lo que parece ser una función poco conocida llamada CGPathCreateCopyByStrokingPath . Esto toma un camino (por ejemplo, un rectángulo redondeado, por ejemplo) y crea una nueva ruta que sería el trazo de la ruta anterior, dada la configuración que pasas a la función (como ancho de línea, configuración de unión / tapa, límite de inglete, etc. ) Así que digamos que defines una ruta (esto no es exactamente lo que proporciona Apple, pero es 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; }

Esto devuelve una ruta similar al botón Atrás de Apple (uso esto en mi aplicación). He agregado este método (junto con docenas más) como una categoría a UIBezierPath.

Ahora agreguemos esa sombra interna en una rutina de dibujo:

- (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); }

Ahora esto es solo un simple ejemplo. No guardo / restauro contextos ni nada, lo cual probablemente querrás hacer. Hay cosas que aún puede querer hacer para mejorarlo, como por ejemplo insertar la ruta ''sombra'' si desea usar un borde normal. Es posible que desee utilizar más / diferentes colores y ubicaciones. Pero esto debería hacerte comenzar.

ACTUALIZAR

Hay otro método que puede usar para crear este efecto. Escribí un algoritmo para biselar caminos bezier arbitrarios en gráficos centrales. Esto se puede usar para crear el efecto que estás buscando. Este es un ejemplo de cómo lo uso en mi aplicación:

Pasas a la rutina el CGContextRef, CGPathRef, el tamaño del bisel y los colores que quieres que use para resaltar / sombrear.

El código que utilicé para esto se puede encontrar aquí: Github - Beveling Algorithm .

También explico el código y mi metodología aquí: Beveling-Shapes en Core Graphics