ios - sonido - tono de iphone notificacion
Manejo de la barra de estado de llamada entrante con presentaciĆ³n modal personalizada (5)
Aquí hay una solución que puse en mi delegado de aplicación que me solucionó el problema:
- (void)application:(UIApplication *)application willChangeStatusBarFrame:(CGRect)newStatusBarFrame
{
if (newStatusBarFrame.size.height < 40) {
for (UIView *view in self.window.subviews) {
view.frame = self.window.bounds;
}
}
}
El problema
He notado un comportamiento extraño al presentar un UINavigationController
(con un controlador de vista raíz, ya UIViewControllerAnimatedTransitioning
, naturalmente) con UIViewControllerAnimatedTransitioning
durante una llamada telefónica.
- Si la barra de estado durante la llamada está habilitada después de que se presenta el controlador de navegación, el controlador de navegación cambia su vista hacia abajo como se esperaba. Pero cuando finaliza la llamada, el controlador no cambia su vista hacia atrás, dejando un espacio de 20p debajo de la barra de estado.
- Si la barra de estado de llamada entrante está habilitada antes de presentar el controlador, el controlador no cuenta para nada la barra de estado, dejando 4p de la barra de navegación de 44p de altura fuera de la barra de estado 40p. Cuando finaliza la llamada, el controlador desplaza su vista hacia abajo para acomodar la barra de estado normal 20p.
* Nota: esto se probó en el simulador, debido a la facilidad de habilitar / deshabilitar la barra de estado durante la llamada, pero los probadores han observado este fenómeno en los teléfonos reales.
Mi solución (parcial)
Analicé el problema ajustando el marco del controlador durante la presentación, si la barra de estado tenía una altura anormal:
@interface CustomAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
@end
@implementation CustomAnimationController
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = [transitionContext containerView];
CGRect frame = [transitionContext finalFrameForViewController:toController];
if (CGRectEqualToRect(frame, CGRectZero))
{
// In my experience, the final frame is always a zero rect, so this is always hit
UIEdgeInsets insets = UIEdgeInsetsZero;
// My "solution" was to inset the container frame by the difference between the
// actual status bar height and the normal status bar height
insets.top = CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - 20;
frame = UIEdgeInsetsInsetRect(container.bounds, insets);
}
toController.view.frame = frame;
[container addSubview:toController.view];
// Perform whiz-bang animation here
}
@end
Esta solución asegura que la barra de navegación se encuentre debajo de la barra de estado, pero el controlador de navegación aún no puede volver a realizar una copia de seguridad cuando finaliza la llamada. Por lo tanto, la aplicación es al menos utilizable, pero hay una fea brecha de 20p por encima de la barra de navegación después de que finaliza una llamada.
¿Hay una mejor manera?
¿Estoy perdiendo algún paso crítico para garantizar que el controlador de navegación represente la barra de estado de la llamada en sí mismo? Funciona muy bien cuando se presenta con el estilo de presentación modal incorporado.
En mi opinión, esto huele a un error UIKit - después de todo, el controlador de navegación parece recibir el UIApplicationWillChangeStatusBarFrameNotification
(ver el segundo punto del problema). Si alguien más ha encontrado este problema y ha encontrado una mejor manera, agradecería mucho una solución.
He gastado demasiado tiempo en superar el problema de la altura de la barra de estado y he encontrado una solución general que me funciona y creo que también funcionará para su situación.
Primero, un par de cosas que son extrañas sobre la barra de estado.
Normalmente tiene 20 puntos de altura y la pantalla tiene normalmente 5 6 8 puntos de altura
Mientras está "en llamada", la barra de estado tiene 40 puntos de altura y la pantalla tiene 5 4 8 puntos de altura
Mientras la barra de estado está oculta, la barra de estado tiene 0 puntos de alto y la pantalla tiene 5 6 8 puntos de alto
Si la barra de estado cambia pero no actualiza la altura de la pantalla, los cálculos estarán desactivados, y esto se puede ver en algunas aplicaciones de gran nombre (e incluso predeterminadas).
Entonces, la solución que se me ocurrió es doble: 1. Crear una macro para obtener la altura de la pantalla ajustada 2. Registrar una notificación para actualizar la vista cuando la barra de estado cambie.
Aquí están las macros, recomiendo ponerlas en su archivo de prefix
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kStatusBarHeight (([[UIApplication sharedApplication] statusBarFrame].size.height == 20.0f) ? 20.0f : (([[UIApplication sharedApplication] statusBarFrame].size.height == 40.0f) ? 20.0f : 0.0f))
#define kScreenHeight (([[UIApplication sharedApplication] statusBarFrame].size.height > 20.0f) ? [UIScreen mainScreen].bounds.size.height - 20.0f : [UIScreen mainScreen].bounds.size.height)
Además, aquí está la llamada del centro de notificaciones que he encontrado que funciona para mí el 100% del tiempo que la barra de estado cambia.
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self.view selector:@selector(layoutSubviews) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
Simplemente configure el marco en layoutSubviews como se llama cuando la altura de la barra de estado cambia. En general, como regla general, configure todo el marco en layoutSubviews solamente.
Tuve el mismo problema y el problema fue con la vista que estaba presentando, que se ajustó automáticamente en 20 puntos debido a la barra en la llamada. Sin embargo, como inserté la vista en el contenedor, tuve que restablecer el marco para que coincida con los límites del contenedor.
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
UIView* destinationView = [transitionContext viewForKey:UITransitionContextToViewKey];
UIView* container = transitionContext.containerView;
// Make sure destination view matches container bounds
// This is necessary to fix the issue with in-call bar
// which adjusts the view''s frame by 20pt.
destinationView.frame = container.bounds;
// Add destination view to container
[container insertSubview:destinationView atIndex:0];
// [reducted]
}
Tuve el mismo problema y lo solucioné mediante la vista de marco de actualización de llamadas, por lo que obtuve la barra de estado de altura. Mi problema fue resuelto
UIView *toViewSnapshot = [toView resizableSnapshotViewFromRect:toView.frame afterScreenUpdates:YES withCapInsets:UIEdgeInsetsZero];