Determinar si UIView es visible para el usuario?


Es posible determinar si mi UIView es visible para el usuario o no?

Mi punto de vista se añade como subview varias veces en un Tab Bar Controller.

Cada instancia de esta vista tiene un NSTimer que actualiza la vista.

Sin embargo, no quiero actualizar una vista que no sea visible para el usuario.

Es esto posible?

Gracias

Author: Undo, 2009-10-08

8 answers

Puedes comprobar si:

  • está oculto, marcando vista.oculto
  • está en la jerarquía de vistas, marcando view.superview != nil
  • puede comprobar los límites de una vista para ver si está en pantalla

La única otra cosa en la que puedo pensar es si tu punto de vista está enterrado detrás de otros y no puede ser visto por esa razón. Es posible que tenga que revisar todas las vistas que vienen después para ver si oscurecen su vista.

 70
Author: mahboudz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-07 23:58:29

Para cualquier otro que termine aquí:

Para determinar si una UIView está en pantalla en algún lugar, en lugar de verificar superview != nil, es mejor verificar si window != nil. En el primer caso, es posible que la vista tenga una supervision pero que la supervision no esté en pantalla:

if (view.window != nil) {
    // do stuff
}

Por supuesto, también debe comprobar si es hidden o si tiene un alpha > 0.

Con respecto a no querer que su NSTimer se ejecute mientras la vista no es visible, debe ocultar estas vistas manualmente si es posible y haga que el temporizador se detenga cuando la vista esté oculta. Sin embargo, no estoy del todo seguro de lo que estás haciendo.

 86
Author: walkingbrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 21:26:42

Esto determinará si el marco de una vista está dentro de los límites de todas sus superviews (hasta la vista raíz). Un caso de uso práctico es determinar si una vista hija es (al menos parcialmente) visible dentro de una vista de desplazamiento.

func isVisible(view: UIView) -> Bool {
    func isVisible(view: UIView, inView: UIView?) -> Bool {
        guard let inView = inView else { return true }
        let viewFrame = inView.convertRect(view.bounds, fromView: view)
        if CGRectIntersectsRect(viewFrame, inView.bounds) {
            return isVisible(view, inView: inView.superview)
        }
        return false
    }
    return isVisible(view, inView: view.superview)
}

Mejoras potenciales:

  • Respetar alpha y hidden.
  • Respeta clipsToBounds, ya que una vista puede exceder los límites de su supervisión si es falsa.
 16
Author: John Gibb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-06 20:15:21

La solución que funcionó para mí fue primero verificar si la vista tiene una ventana, luego iterar sobre superviews y verificar si:

  1. la vista no está oculta.
  2. la vista está dentro de sus límites de superviews.

Parece funcionar bien hasta ahora.

Swift 3.0

public func isVisible(view: UIView) -> Bool {

  if view.window == nil {
    return false
  }

  var currentView: UIView = view
  while let superview = currentView.superview {

    if (superview.bounds).intersects(currentView.frame) == false {
      return false;
    }

    if currentView.isHidden {
      return false
    }

    currentView = superview
  }

  return true
}
 8
Author: AlexGordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-14 13:06:23

Si realmente desea saber si una vista es visible para el usuario, debe tener en cuenta lo siguiente:

  • Es la ventana de la vista no nula e igual a la ventana superior
  • Es la vista, y todas sus superviews alpha >= 0.01 (valor de umbral también utilizado por UIKit para determinar si debe manejar toques) y no oculto
  • Es el índice z (valor de apilamiento) de la vista más alto que otras vistas en la misma jerarquía.
  • Incluso si el índice z es más bajo, puede ser visible si otras vistas en la parte superior tienen un color de fondo transparente, alfa 0 o están ocultas.

Especialmente el color de fondo transparente de las vistas en frente puede plantear un problema para comprobar mediante programación. La única manera de estar realmente seguro es hacer una instantánea programática de la vista para verificarla y diferenciarla dentro de su marco con la instantánea de toda la pantalla. Sin embargo, esto no funcionará para vistas que no son lo suficientemente distintivas (por ejemplo, completamente blancas).

Para la inspiración ver el método es visible en el proyecto iOS Calabash-server

 3
Author: Werner Altewischer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-07 12:52:57

En viewWillAppear establece un valor "IsVisible" en true, en viewWillDisappear lo establece en false. Mejor manera de saber para un subviews UITabBarController, también funciona para controladores de navegación.

 2
Author: BadPirate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-26 18:34:15

Esto puede ayudarlo a averiguar si su UIView es la vista más alta. Puede ser útil:

let visibleBool = view.superview?.subviews.last?.isEqual(view)
//have to check first whether it's nil (bc it's an optional) 
//as well as the true/false 
if let visibleBool = visibleBool where visibleBool { value
  //can be seen on top
} else {
  //maybe can be seen but not the topmost view
}
 1
Author: teradyl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-26 20:53:39

En caso de que esté utilizando la propiedad oculta de view, entonces:

Vista.oculto (objetivo C) o vista.isHidden (swift) es una propiedad de lectura/escritura. Para que pueda leer o escribir fácilmente

Para swift 3.0

if(view.isHidden){
   print("Hidden")
}else{
   print("visible")
}
 0
Author: Deepak Chaudhary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-08 12:17:11