La misma barra de estado dinámica que está en la nueva aplicación Apple Music

¿Es posible tener dinámicamente colorear statusBar que está en la nueva aplicación Apple Music ?

introduzca la descripción de la imagen aquí

Editar:

La nueva aplicación Apple Music en iOS 8.4 tiene esta function.

  • Abre la aplicación.
  • Selecciona y reproduce una canción (la barra de estado es blanca)
  • Desliza el control del reproductor hacia abajo para ver el controller "Mi música" (tiene una barra de estado negra, tal vez deberás volver a la jerarquía de navigation).
  • Ahora simplemente desliza hacia arriba / abajo para ver los cambios dynamics en la barra de estado.

Editar 2:

La documentation de Apple no parece permitirnos usarla en este momento ( iOS 8.4 ). Estará disponible probablemente en el futuro con iOS 9 .

Editar 3: parece que todavía no está disponible en iOS 9 .

Estoy seguro de que el 99,99% no se puede hacer con una API pública (fácilmente), porque probé casi todo lo que hay (personalmente, tampoco creo que sea un método mágico de su barra de estado, sino que su aplicación es capaz de recupere la vista de la barra de estado y luego aplique la máscara).

De lo que estoy seguro es de que puedes hacer tu propia StatusBar y hay una biblioteca MTStatusBarOverlay para eso, desafortunadamente muy antigua, así que realmente no puedo decir si eso funciona, pero parece que todavía hay personas que lo usan.

Pero usar la librería way lo hace, creo que puede haber una solución que, sin duda, requiere mucho trabajo, pero es factible, aunque no "en vivo". En pocas palabras, haría esto:

  • Tomar una captura de pantalla de los 20 píxeles superiores (barra de estado)
  • Desde esa captura de pantalla, elimine todo lo que no sea negro (puede mejorarlo para que busque bordes negros, de esta manera puede conservar la batería verde y la transparencia) Esto hará que su máscara de superposition y también la barra de estado falso
  • Superposition de la barra de estado con: vista de background que enmascara la barra de estado real, y la image alfa que acaba de crear.
  • Aplicar máscara a esa image , todo lo que está enmascarado cambiará el color a sombras de blanco
  • Cambiar la altura de la máscara según el desplazamiento del usuario

Ahora debería poder desplazarse correctamente y cambiar el color correctamente. El único problema que deja es que la barra de estado no está viva, pero ¿es así? una vez que se desplaza hacia afuera, inmediatamente elimina su superposition, permitiendo que se actualice. Hará lo mismo cuando se desplace a la parte superior, pero en ese caso, cambiará el color de la barra de estado a blanco (sin animation), por lo que se ajusta a su estado. No será en vivo solo por un breve período de time.

¡Espero eso ayude!

Replanteando la respuesta de Jiri, esto te acercará bastante. Sustituya MTStatusBarOverlay con CWStatusBarNotification . Para manejar la transición modal entre los controlleres de vista, estoy usando MusicPlayerTransition . Asumimos un imageView: "art" en self.view con frame: CGRect (0, 0, self.view.bounds.size.width, self.view.bounds.size.width). Necesita un poco masajes, pero obtienes lo esencial. Nota: A pesar de que no estamos "en vivo", lo máximo que perderemos será un segundo, y el color de la batería no se conservará. Además, necesitará configurar la hora de animation en CWStatusBarNotification.m a cero. (propiedad notificationAnimationDuration).

 #import "CWStatusBarNotification.h" #define kStatusTextOffset 5.4 // (rough guess of) space between window's origin.y and status bar label's origin.y @interface M_Player () <UIGestureRecognizerDelegate> @property (retain) UIView *fakeStatusBarView; @property (retain) CWStatusBarNotification *fakeStatusBar; @property (retain) UIImageView *statusImgView; @property (retain) UIImageView *statusImgViewCopy; @property (retain) UIWindow *window; @property (strong, nonatomic) NSTimer *statusTimer; @end @implementation M_Player @synthesisze fakeStatusBarView, fakeStatusBar, statusImgView, statusImgViewCopy, window, statusTimer; -(void)viewDidLoad{ self.window = [[UIApplication shanetworkingApplication] delegate].window; UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleStatusBarDrag:)]; pan.delegate = self; [self.view addGestureRecognizer:pan]; } -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; if (!fakeStatusBar){ [self buildFakeStatusBar]; } if (!statusTimer) { [self setupStatusBarImageUpdateTimer]; } // optional [[UIApplication shanetworkingApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; [self setNeedsStatusBarAppearanceUpdate]; -(void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [self destroyStatusBarImageUpdateTimer]; 

}

 -(void)destroyFakeStatusBar{ [statusImgView removeFromSuperview]; statusImgView = nil; [fakeStatusBarView removeFromSuperview]; fakeStatusBarView = nil; fakeStatusBar = nil; } -(void)buildFakeStatusBar{ UIWindow *statusBarWindow = [[UIApplication shanetworkingApplication] valueForKey:@"_statusBarWindow"]; // This window is actually still fullscreen. So we need to capture just the top 20 points. UIGraphicsBeginImageContext(self.view.bounds.size); [statusBarWindow.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGRect rect = CGRectMake(0, 0, self.view.bounds.size.width, 20); CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect); UIImage *statusImg = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); statusImg = [statusImg imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; // This allows us to set the status bar content's color via the imageView's .tintColor property statusImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)]; statusImgView.image = statusImg; statusImgView.tintColor = [UIColor colorWithWhite:0.859 alpha:1.000]; // any color you want statusImgViewCopy = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)]; statusImgViewCopy.image = statusImg; statusImgViewCopy.tintColor = statusImgView.tintColor; fakeStatusBarView = nil; fakeStatusBar = nil; fakeStatusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)]; [fakeStatusBarView addSubview:statusImgView]; fakeStatusBar = [CWStatusBarNotification new]; fakeStatusBar.notificationStyle = CWNotificationStyleStatusBarNotification; [fakeStatusBar displayNotificationWithView:fakeStatusBarView forDuration:CGFLOAT_MAX]; } -(void)handleStatusBarDrag:(UIPanGestureRecognizer*)gestureRecognizer{ if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { } if (gestureRecognizer.state == UIGestureRecognizerStateChanged){ CGPoint convertedPoint = [self.window convertPoint:art.frame.origin fromView:self.view]; CGFloat originY = convertedPoint.y - kStatusTextOffset; if (originY > 0 && originY <= 10) { // the range of change we're interested in //NSLog(@"originY:%f statusImgView.frame:%@", originY, NSStringFromCGRect(statusImgView.frame)); // render in context from new originY using our untouched copy as reference view UIGraphicsBeginImageContext(self.view.bounds.size); [statusImgViewCopy.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGRect rect = CGRectMake(0, kStatusTextOffset + originY, self.view.bounds.size.width, 20); CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect); UIImage *statusImg = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); statusImgView.image = statusImg; statusImgView.transform = CGAffineTransformMakeTranslation(0, kStatusTextOffset + originY); } // destroy if (originY > 90) { [self destroyFakeStatusBar]; } } if (gestureRecognizer.state == UIGestureRecognizerStateEnded){ } } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ return YES; } 

Para mantener las capturas de pantalla de la barra de estado en synchronization con la barra de estado real, configure su timer. Inciéndalo en la vista. Aparecerá y mátalo en la vista. DID desaparece.

 -(void)setupStatusBarImageUpdateTimer{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_main_queue(), ^(){ // main thread if (!statusTimer) { statusTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleStatusTimer:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:statusTimer forMode:NSRunLoopCommonModes]; } }); }); } -(void)destroyStatusBarImageUpdateTimer{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_main_queue(), ^(){ // main thread [statusTimer invalidate]; statusTimer = nil; }); }); } -(void)handleStatusTimer:(NSTimer*)timer{ UIWindow *statusBarWindow = [[UIApplication shanetworkingApplication] valueForKey:@"_statusBarWindow"]; UIGraphicsBeginImageContext(CGSizeMake(self.view.bounds.size.width, 20)); [statusBarWindow.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGRect rect = CGRectMake(0, 0, self.view.bounds.size.width, 20); CGImageRef imageRef = CGImageCreateWithImageInRect([viewImage CGImage], rect); UIImage *statusImg = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); statusImg = [statusImg imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; statusImgViewCopy.image = statusImg; } 

Debido a que tenemos una fuerte reference al timer y la configuration y la invalidation ocurren en el mismo hilo, no hay que preocuparse de que el timer no invalide. El resultado final debería verse así:

introduzca la descripción de la imagen aquí

A primera vista, parecía una manipulación de una instantánea de la barra de estado, pero la barra de estado está viva en ambos extremos, así que no es así.

A simple vista, parecía una nueva API que se introdujo en iOS 8.4, pero después de revisar la API no pude encontrar nada relacionado con eso.

Me parece muy raro que la manzana use apis privados en su propia aplicación. Esto daría como resultado un ejemplo realmente malo para los desarrolladores pero, nuevamente, no hay nada público que le permita tener dos styles en su barra de estado en vivo.

Esto nos deja con api privado o magia negra.

Pensando en cómo implementar esto sin API privadas.

Creo que puede haber una solución con la segunda UIWindow superponiendo su statusBar.

Agregar vista en StatusBar en iPhone

Tal vez sea posible hacer capturas de pantalla de la barra de estado constantemente (tomadas de su window principal) a la image, aplicarle un filter y mostrar esta 'image de barra de estado falsa' en su segunda window (arriba de 'estado real').

Y puedes hacer lo que quieras con la segunda barra de estado "falso".