Question

est-il possible de déterminer si mon UIView est visible à l'utilisateur ou non?

My View est ajouté comme subview à plusieurs reprises dans un Tab Bar Controller.

Chaque instance de ce point de vue a une NSTimer qui met à jour la vue.

Cependant, je ne veux pas mettre à jour une vue non visible à l'utilisateur.

Est-ce possible?

Merci

Était-ce utile?

La solution

Vous pouvez vérifier si:

  • il est caché, en vérifiant view.hidden
  • il est dans la hiérarchie de la vue, en vérifiant view.superview != nil
  • vous pouvez vérifier les limites d'une vue pour voir si elle est à l'écran

La seule autre chose que je peux penser est que si votre point de vue est enterré derrière les autres et ne peut pas être vu pour cette raison. Vous pourriez avoir à passer par tous les points de vue qui viennent après pour voir si elles obscurcissent votre point de vue.

Autres conseils

Pour quelqu'un d'autre qui se termine ici:

Pour déterminer si un UIView est à l'écran quelque part, plutôt que de vérifier superview != nil, il est préférable de vérifier si window != nil. Dans le premier cas, il est possible que la vue a une superview mais que le superview est pas à l'écran:

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

Bien sûr, vous devriez également vérifier si elle est hidden ou si elle a un alpha > 0.

En ce qui concerne ne pas vouloir votre NSTimer en cours d'exécution tandis que la vue ne soit pas visible, vous devez cacher ces vues manuellement si possible et que l'arrêt de la minuterie lorsque la vue est cachée. Cependant, je ne suis pas du tout sûr de ce que vous faites.

Cela permettra de déterminer si est dans les limites de tous ses superviews (jusqu'à la vue racine) le cadre d'une vue. Un cas d'utilisation pratique consiste à déterminer si une vue enfant est (au moins partiellement) visible dans un scrollview.

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)
}

Améliorations possibles:

  • Respect alpha et hidden.
  • Respect clipsToBounds, en vue peut dépasser les limites de son superview si elle est fausse.

La solution qui a fonctionné pour moi était d'abord vérifier si la vue a une fenêtre, puis itérer sur superviews et vérifier si:

  1. la vue est pas caché.
  2. la vue est dans ses limites de superviews.

Il semble bien fonctionner jusqu'à présent.

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
}

Je vous veux vraiment savoir si une vue est visible à l'utilisateur que vous devez prendre en compte les éléments suivants:

  • Est-ce que la fenêtre de la vue non nulle et égale à la partie supérieure la plus fenêtre
  • est la vue, et l'ensemble de ses superviews alpha> = 0,01 (valeur de seuil également utilisée par UIKit pour déterminer si elle doit manipuler des touches) et non masquée
  • Le z-index (valeur d'empilement) de la vue plus élevé que d'autres points de vue dans la même hiérarchie.
  • Même si le z-index est plus faible, il peut être visible si d'autres points de vue sur le dessus ont une couleur d'arrière-plan transparent, alpha 0 ou sont cachées.

En particulier, la couleur de fond transparent de vues en face peut poser un problème pour vérifier par programme. La seule façon d'être vraiment sûr est de faire un instantané programmatique en vue de vérifier et diff, il est dans son cadre avec l'instantané de l'écran. Ce ne sera toutefois pas travailler pour des vues qui ne sont pas assez distinctif (par exemple entièrement blanc).

Pour l'inspiration voir la méthode isViewVisible dans la section iOS projet Calabash serveur

Dans viewWillAppear définir une valeur "isVisible" true, en viewWillDisappear mettre à false. La meilleure façon de savoir pour une sous-vues de UITabBarController, travaille également pour les contrôleurs de navigation.

Cela peut vous aider à déterminer si votre UIView est le plus haut point de vue. Peut être utile:

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
}

essayez ceci:

func isDisplayedInScreen() -> Bool
{
 if (self == nil) {
     return false
  }
    let screenRect = UIScreen.main.bounds 
    // 
    let rect = self.convert(self.frame, from: nil)
    if (rect.isEmpty || rect.isNull) {
        return false
    }
    // 若view 隐藏
    if (self.isHidden) {
        return false
    }

    // 
    if (self.superview == nil) {
        return false
    }
    // 
    if (rect.size.equalTo(CGSize.zero)) {
        return  false
    }
    //
    let intersectionRect = rect.intersection(screenRect)
    if (intersectionRect.isEmpty || intersectionRect.isNull) {
        return false
    }
    return true
}

solution testée.

func isVisible(_ view: UIView) -> Bool {
    if view.isHidden || view.superview == nil {
        return false
    }

    if let rootViewController = UIApplication.shared.keyWindow?.rootViewController,
        let rootView = rootViewController.view {

        let viewFrame = view.convert(view.bounds, to: rootView)

        let topSafeArea: CGFloat
        let bottomSafeArea: CGFloat

        if #available(iOS 11.0, *) {
            topSafeArea = rootView.safeAreaInsets.top
            bottomSafeArea = rootView.safeAreaInsets.bottom
        } else {
            topSafeArea = rootViewController.topLayoutGuide.length
            bottomSafeArea = rootViewController.bottomLayoutGuide.length
        }

        return viewFrame.minX >= 0 &&
               viewFrame.maxX <= rootView.bounds.width &&
               viewFrame.minY >= topSafeArea &&
               viewFrame.maxY <= rootView.bounds.height - bottomSafeArea
    }

    return false
}

Si vous utilisez la propriété cachée de vue alors:

view.hidden (objectif C) ou view.isHidden (rapide) est la propriété de lecture / écriture. Ainsi, vous pouvez facilement lire ou écrire

Pour rapide 3.0

if(view.isHidden){
   print("Hidden")
}else{
   print("visible")
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top