webentwicklung-frage-antwort-db.com.de

Bestimmen Sie, ob UIView für den Benutzer sichtbar ist?

ist es möglich festzustellen, ob mein UIView für den Benutzer sichtbar ist oder nicht?

Meine Ansicht wird mehrmals als subview zu einem Tab Bar Controller Hinzugefügt.

Jede Instanz dieser Ansicht verfügt über ein NSTimer, das die Ansicht aktualisiert.

Ich möchte jedoch keine Ansicht aktualisieren, die für den Benutzer nicht sichtbar ist.

Ist das möglich?

Vielen Dank

66
jantimon

Sie können überprüfen, ob:

  • es wird ausgeblendet, indem view.hidden aktiviert wird
  • es befindet sich in der Ansichtshierarchie, indem Sie view.superview != nil
  • sie können die Grenzen einer Ansicht überprüfen, um festzustellen, ob sie auf dem Bildschirm angezeigt wird

Das einzige andere, woran ich denken kann, ist, wenn Ihre Sicht hinter anderen verborgen ist und aus diesem Grund nicht gesehen werden kann. Möglicherweise müssen Sie alle folgenden Ansichten durchgehen, um festzustellen, ob sie Ihre Ansicht verdecken.

73
mahboudz

Für alle anderen, die hier landen:

So stellen Sie fest, ob ein UIView irgendwo auf dem Bildschirm angezeigt wird, anstatt superview != nil, es ist besser zu überprüfen, ob window != nil. Im ersten Fall ist es möglich, dass die Ansicht eine Übersicht enthält, diese jedoch nicht auf dem Bildschirm angezeigt wird:

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

Natürlich sollten Sie auch prüfen, ob es sich um hidden handelt oder ob es ein alpha > 0.

Wenn Sie nicht möchten, dass Ihr NSTimer ausgeführt wird, während die Ansicht nicht sichtbar ist, sollten Sie diese Ansichten nach Möglichkeit manuell ausblenden und den Timer anhalten lassen, wenn die Ansicht ausgeblendet ist. Ich bin mir jedoch nicht sicher, was Sie tun.

100
walkingbrad

Hiermit wird bestimmt, ob der Frame einer Ansicht innerhalb der Grenzen aller Superviews liegt (bis zur Stammansicht). Ein praktischer Anwendungsfall besteht darin, zu bestimmen, ob eine untergeordnete Ansicht (zumindest teilweise) in einer Bildlaufansicht sichtbar ist.

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

Mögliche Verbesserungen:

  • Respektiere alpha und hidden.
  • Respektieren Sie clipsToBounds, da eine Ansicht die Grenzen ihrer Übersicht überschreiten kann, wenn sie falsch ist.
18
John Gibb

Die Lösung, die für mich funktioniert hat, war, zuerst zu überprüfen, ob die Ansicht ein Fenster hat, dann über die Übersichten zu iterieren und zu überprüfen, ob:

  1. die Ansicht ist nicht verborgen.
  2. die Ansicht befindet sich innerhalb ihrer Übersichtsgrenzen.

Scheint soweit gut zu funktionieren.

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
}
15
AlexGordon

Wenn Sie wirklich wissen möchten, ob eine Ansicht für den Benutzer sichtbar ist, müssen Sie Folgendes berücksichtigen:

  • Ist das Fenster der Ansicht nicht gleich null und entspricht dem obersten Fenster
  • Ist die Ansicht und alle ihre Superviews Alpha> = 0,01 (Schwellenwert, der auch von UIKit verwendet wird, um zu bestimmen, ob Berührungen behandelt werden sollen) und nicht ausgeblendet
  • Ist der Z-Index (Stapelwert) der Ansicht höher als bei anderen Ansichten in derselben Hierarchie?.
  • Selbst wenn der Z-Index niedriger ist, kann er sichtbar sein, wenn andere Ansichten oben eine transparente Hintergrundfarbe Alpha 0 haben oder ausgeblendet sind.

Insbesondere die transparente Hintergrundfarbe der Ansichten im Vordergrund kann zu Problemen bei der programmgesteuerten Überprüfung führen. Die einzige Möglichkeit, um wirklich sicher zu sein, besteht darin, einen programmgesteuerten Schnappschuss der Ansicht zu erstellen, um ihn innerhalb seines Rahmens mit dem Schnappschuss des gesamten Bildschirms zu vergleichen. Dies funktioniert jedoch nicht für Ansichten, die nicht unterscheidungskräftig genug sind (z. B. vollständig weiß).

Inspiration finden Sie in der Methode isViewVisible im Abschnitt iOS Calabash-Server-Projekt

3

In viewWillAppear setzen Sie einen Wert "isVisible" auf true, in viewWillDisappear setzen Sie ihn auf false. Die beste Methode, um für einen UITabBarController Unteransichten zu ermitteln, funktioniert auch für Navigationscontroller.

2
BadPirate

Dies kann Ihnen dabei helfen, herauszufinden, ob Ihre UIView-Ansicht die Ansicht mit der höchsten Priorität ist. Kann hilfreich sein:

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
teradyl

Wenn Sie eine versteckte Eigenschaft der Ansicht verwenden, gehen Sie wie folgt vor:

view.hidden (Objective C) oder view.isHidden (Swift) ist eine Lese-/Schreibeigenschaft. So können Sie leicht lesen oder schreiben

Für Swift 3.

if(view.isHidden){
   print("Hidden")
}else{
   print("visible")
}
0

Getestete Lösung.

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
}
0
Andrey M.

versuche dies:

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
}
0
Feng Chengjing