Hice esto usando CAShapeLayer, CABasicAnimation y un UIBezierPath:
1.) Aquí está el controlador de vista:
Este es el archivo de encabezado de stock, nada que hacer aquí.
- ¿Quién es el proveedor de mapas de Apple?
- ¿Qué se necesita para optimizar una aplicación de iPhone para iPads?
- ¿Podría la red publicitaria que uso en mi aplicación hacer una diferencia significativa en mis ingresos?
- ¿Los desarrolladores serios y centrados en el diseño usan Interface Builder? ¿Interface Builder se considera una herramienta novata o es lo suficientemente potente como para ser utilizada para el desarrollo serio de aplicaciones, donde el diseño centrado en los detalles es crítico?
- ¿Debo usar la arquitectura Viper para mi próxima aplicación iOS, o todavía es muy nueva?
// ViewController.h
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
#import
@interface ViewController: UIViewController
@fin
En la implementación, estamos utilizando un método llamado drawCircle para configurar el UIBezierPath y dibujarlo en una vista subclasificada de UIView.
//
// ViewController.m
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
#import “ViewController.h”
#import “CircleView.h”
#import
#definir grados ToRadians (grados) ((grados) / 180.0 * M_PI)
@interface ViewController ()
{
CGRect drawbox;
}
@property (no atómico, fuerte) IBOutlet CircleView * cv;
@property (no atómico, fuerte) UIBezierPath * circlePath;
@fin
@implementation ViewController
– (nulo) viewDidLoad {
[super viewDidLoad];
// Realice cualquier configuración adicional después de cargar la vista, generalmente desde una punta.
[self drawCircle];
[self.cv drawLineWithPath: self.circlePath];
}
– (nulo) drawCircle {
CGFloat start = degreesToRadians (270);
CGFloat end = degreesToRadians (630);
Origen de CGPoint = CGPointMake (self.cv.frame.origin.x + 4, self.cv.frame.origin.y + 4);
drawbox = CGRectMake (origin.x, origin.y, self.cv.frame.size.width-2, self.cv.frame.size.height-2);
CGPoint midPoint = CGPointMake (CGRectGetWidth (drawbox) / 2, CGRectGetWidth (drawbox) / 2);
CGFloat lineWidth = (CGRectGetWidth (drawbox) / 2) * 0.25;
CGFloat radio = (CGRectGetWidth (drawbox) / 2) -lineWidth / 2-2;
self.circlePath = [UIBezierPath bezierPathWithArcCenter: radio del punto medio: radio startAngle: start endAngle: end clockwise: true];
self.circlePath.lineWidth = lineWidth;
}
@fin
2. En mi Vista personalizada, estoy dibujando la ruta y actualizando y mostrando el progreso. Aquí se puede hacer más al anotar el progreso en el tiempo que lleva animar. El crédito donde corresponde se anota en el archivo.
Primero, aquí está el encabezado. Nada sofisticado…
//
// CircleView.h
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
#import
@interface CircleView: UIView
– (vacío) drawLineWithPath: (UIBezierPath *) ruta;
@fin
A continuación, aquí está la implementación. Desglosaré esto por método.
Primero definimos un método auxiliar para convertir grados a radianes.
//
// CircleView.m
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
// basado en tecnología móvil y de redes sociales
#import “CircleView.h”
#import “LayerWithProgress.h”
#definir grados ToRadians (grados) ((grados) / 180.0 * M_PI)
Luego, configure los bordes para el indicador de progreso y una etiqueta para el porcentaje.
@interface CircleView ()
@property (no atómico, fuerte) UIBezierPath * externalPath;
@property (no atómico, fuerte) UIBezierPath * innerPath;
@property (no atómico, fuerte) UILabel * lblProgress;
@fin
@implementation CircleView
El siguiente es un método que agrega la etiqueta, dimensionada correctamente.
– (nulo) addProgressLabelForPath: (UIBezierPath *) ruta {
NSString * lblProgressTxt = @ “100%”;
UIFont * myFont = [UIFont fontWithName: @ tamaño “HelveticaNeue-Thin”: 60.0];
Tamaño de CGSize = [lblProgressTxt sizeWithAttributes: @ {NSFontAttributeName: myFont}];
CGRect oldRect = path.bounds;
self.lblProgress = [[UILabel alloc] initWithFrame: CGRectMake (CGRectGetMidX (oldRect) -size.width / 2, CGRectGetMidY (oldRect) -size.height / 2, size.width, size.height)];
[self addSubview: self.lblProgress];
self.lblProgress.text = lblProgressTxt;
self.lblProgress.font = myFont;
self.lblProgress.backgroundColor = [UIColor clearColor];
self.lblProgress.textAlignment = NSTextAlignmentCenter;
}
Ahora, dibuja las rutas de los bordes exterior e interior. Luego dibuje la línea correspondiente a la ruta que configuramos en el controlador de vista. Finalmente, anime el dibujo del círculo.
– (nulo) drawLineWithPath: (UIBezierPath *) ruta {
[self drawOuterPathForPath: ruta];
[self drawInnerPathForPath: ruta];
[self addProgressLabelForPath: ruta];
CAShapeLayer * pathLayer = [capa CAShapeLayer];
pathLayer.frame = CGRectMake (path.bounds.origin.x-path.lineWidth / 2-1, path.bounds.origin.y-path.lineWidth / 2-1, path.bounds.size.width, path.bounds. tamaño.Altura);
pathLayer.path = path.CGPath;
pathLayer.strokeColor = [UIColor greenColor] .CGColor;
pathLayer.fillColor = nil;
pathLayer.lineWidth = path.lineWidth;
pathLayer.lineJoin = kCALineJoinBevel;
[self.layer addSublayer: pathLayer];
CABasicAnimation * pathAnimation = [animación de CABasicAnimationWithKeyPath: @ “strokeEnd”];
pathAnimation.duration = 10.0;
pathAnimation.fromValue = @ 0;
pathAnimation.toValue = @ 1;
[pathLayer addAnimation: pathAnimation forKey: @ “strokeEnd”];
Continuando con este método, tenemos que utilizar una subclase personalizada para obtener el progreso a medida que se dibuja la línea. Hacemos esto subclasificando CAShapeLayer y agregando un método de devolución de llamada. Luego solo agregue la animación con los mismos atributos que el círculo dibujando uno.
LayerWithProgress * progressLayer = [capa LayerWithProgress];
progressLayer.frame = CGRectMake (0, -1, 1, 1);
progressLayer.progressdelegate = self;
[self.layer addSublayer: progressLayer];
CABasicAnimation * progressAnimation = [CABasicAnimation animationWithKeyPath: @ “progress”];
progressAnimation.duration = 10.0;
progressAnimation.beginTime = 0;
progressAnimation.fromValue = @ 0;
progressAnimation.toValue = @ 1;
progressAnimation.fillMode = kCAFillModeForwards;
progressAnimation.removedOnCompletion = NO;
[progressLayer addAnimation: progressAnimation forKey: @ “progress”];
self.lblProgress.text = @ “0%”;
}
El siguiente bit solo actualiza la etiqueta, manteniendo todo centrado.
– (nulo) progressUpdatedTo: (CGFloat) progress {
NSLog (@ “Progreso:% f”, progreso);
// [self bringSubviewToFront: self.lblProgress];
NSString * padStr = @ “”;
NSInteger num = progreso * 100 + 1;
si (num <10) {
padStr = @ “”;
}
if (num == 100) {
padStr = @ “”;
}
self.lblProgress.text = [NSString stringWithFormat: @ “% @% ld %%”, padStr, (long) num];
}
Finalmente, métodos para dibujar los caminos internos y externos.
– (nulo) drawOuterPathForPath: (UIBezierPath *) ruta {
CGRect oldRect = path.bounds;
Radio CGFloat = CGRectGetWidth (oldRect) /2+path.lineWidth/2+1;
CGPoint midPoint = CGPointMake (CGRectGetWidth (self.frame) / 2, CGRectGetHeight (self.frame) / 2);
self.outerPath = [UIBezierPath bezierPathWithArcCenter: radio del punto medio: radio startAngle: degreesToRadians (270) endAngle: degreesToRadians (630) en sentido horario: SÍ];
self.outerPath.lineWidth = 2.0f;
}
– (nulo) drawInnerPathForPath: (UIBezierPath *) ruta {
CGRect oldRect = path.bounds;
Radio CGFloat = CGRectGetWidth (oldRect) /2-path.lineWidth/2-1;
CGPoint midPoint = CGPointMake (CGRectGetWidth (self.frame) / 2, CGRectGetHeight (self.frame) / 2);
self.innerPath = [UIBezierPath bezierPathWithArcCenter: radio del punto medio: radio startAngle: degreesToRadians (270) endAngle: degreesToRadians (630) en sentido horario: SÍ];
self.innerPath.lineWidth = 2.0f;
}
– (nulo) drawRect: (CGRect) rect {
[[UIColor blackColor] setStroke];
[self.outerPath stroke];
[self.innerPath stroke];
}
@fin
3. Y aquí está la clase CAShapeLayer personalizada para obtener el progreso. Encontré esto aquí: devolución de llamada de progreso de animación central
Primero el archivo de encabezado con protocolo. Tuve que cambiar la variable delegado para no interferir con el delegado CAShapeLayer.
//
// LayerWithProgress.h
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
#import
@protocol LayerWithProgressProtocol
– (nulo) progressUpdatedTo: (CGFloat) progreso;
@fin
@interface LayerWithProgress: CAShapeLayer
@property CGFloat progress;
@property (débil) id progressdelegate;
@fin
Y aquí está la implementación.
//
// LayerWithProgress.m
// CircleTest
//
// Creado por J Mundie el 29/04/15.
// Copyright (c) 2015 jpm165. Todos los derechos reservados.
//
// basado en la devolución de llamada de progreso de animación de Core
#import “LayerWithProgress.h”
@implementation LayerWithProgress
– (id) initWithLayer: capa (id)
{
self = [super initWithLayer: capa];
si (auto) {
LayerWithProgress * otherLayer = (LayerWithProgress *) capa;
self.progress = otherLayer.progress;
self.progressdelegate = otherLayer.progressdelegate;
}
volver a sí mismo;
}
+ (BOOL) needsDisplayForKey: tecla (NSString *) {
if ([key isEqualToString: @ “progress”]) {
devuelva SÍ;
} más {
return [super needsDisplayForKey: clave];
}
}
– (nulo) drawInContext: (CGContextRef) ctx
{
if (self.progressdelegate)
{
[self.progressdelegate progressUpdatedTo: self.progress];
}
}
@fin