objective c - mexico - Obtener referencia a la ventana/vista más alta en la aplicación de iOS
licencia de desarrollo ios (9)
Cada vez que quiero mostrar una superposición sobre todo lo demás, simplemente la agrego directamente sobre la ventana de la aplicación:
[[[UIApplication sharedApplication] keyWindow] addSubview:someView]
Estoy creando un marco reutilizable para mostrar notificaciones en una aplicación de iOS. Me gustaría que las vistas de notificación se agreguen por encima de todo lo demás en la aplicación, algo así como un UIAlertView. Cuando inicio el administrador que escucha los eventos NSNotification y agrega vistas en respuesta, necesito obtener una referencia a la vista más alta de la aplicación. Esto es lo que tengo en este momento:
_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
¿Esto funcionaría para cualquier aplicación de iOS o es una forma más segura / mejor para obtener la vista superior?
En realidad, puede haber más de una ventana UI en tu aplicación. Por ejemplo, si hay un teclado en la pantalla, entonces [[UIApplication sharedApplication] windows]
contendrá al menos dos ventanas (su ventana clave y la ventana del teclado).
Entonces, si quieres que tu vista aparezca en la parte superior de ambos, debes hacer algo como:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];
(Suponiendo que lastObject contiene la ventana con la mayor prioridad windowLevel).
Hay dos partes del problema: ventana superior, vista superior en la ventana superior.
Todas las respuestas existentes omitieron la parte superior de la ventana. Pero no se garantiza que [[UIApplication sharedApplication] keyWindow]
sea la ventana superior.
Ventana superior. Es muy poco probable que haya dos ventanas con la misma
windowLevel
coexiste para una aplicación, por lo que podemos ordenar todas las ventanas porwindowLevel
y obtener la más alta.UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) { return win1.windowLevel - win2.windowLevel; }] lastObject];
Vista superior en la ventana superior. Solo para ser completo. Como ya se señaló en la pregunta:
UIView *topView = [[topWindow subviews] lastObject];
Me estoy apegando a la pregunta como dice el título y no la discusión. ¿Qué vista es superior visible en cualquier punto dado?
@implementation UIView (Extra)
- (UIView *)findTopMostViewForPoint:(CGPoint)point
{
for(int i = self.subviews.count - 1; i >= 0; i--)
{
UIView *subview = [self.subviews objectAtIndex:i];
if(!subview.hidden && CGRectContainsPoint(subview.frame, point))
{
CGPoint pointConverted = [self convertPoint:point toView:subview];
return [subview findTopMostViewForPoint:pointConverted];
}
}
return self;
}
- (UIWindow *)topmostWindow
{
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
return topWindow;
}
@end
Puede usarse directamente con cualquier UIWindow como receptor o como UIView como receptor.
Por lo general, eso le dará la vista superior, pero no hay garantía de que sea visible para el usuario. Podría estar fuera de la pantalla, tener un alfa de 0.0, o podría tener un tamaño de 0x0, por ejemplo.
También podría ser que keyWindow no tenga subvistas, por lo que probablemente debería probarlo primero. Esto sería inusual, pero no es imposible.
UIWindow es una subclase de UIView, por lo que si desea asegurarse de que su notificación esté visible para el usuario, puede agregarla directamente a la ventana clave mediante addSubview:
instantáneamente será la vista más alta. No estoy seguro de si esto es lo que estás buscando hacer. (Según su pregunta, parece que ya lo sabe).
Si está agregando una vista de carga (una vista de indicador de actividad, por ejemplo), asegúrese de tener un objeto de la clase UIWindow. Si muestra una hoja de acción justo antes de mostrar su vista de carga, la keyWindow
será la UIActionSheet
y no UIWindow
. Y dado que la hoja de acción desaparecerá, la vista de carga se irá con ella. O eso es lo que me estaba causando problemas.
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:@"UIWindow"]) {
// find uiwindow in windows
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"]) {
keyWindow = window;
break;
}
}
}
Si su aplicación solo funciona en orientación vertical, esto es suficiente:
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]
Y su vista no se mostrará sobre el teclado y la barra de estado.
Si desea obtener una vista superior que sobre el teclado o la barra de estado, o si desea que la vista superior pueda rotar correctamente con los dispositivos, pruebe este marco:
github.com/HarrisonXi/TopmostView
Es compatible con iOS7 / 8/9.
Simplemente use este código si desea agregar una vista arriba de todo en la pantalla.
[[UIApplication sharedApplication].keyWindow addSubView: yourView];
prueba esto
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];