Kann festgestellt werden, ob meine UIView
für den Benutzer sichtbar ist oder nicht?
Meine Ansicht wird subview
mehrmals in eine hinzugefügt Tab Bar Controller
.
Jede Instanz dieser Ansicht verfügt über eine NSTimer
, die die Ansicht aktualisiert.
Ich möchte jedoch keine Ansicht aktualisieren, die für den Benutzer nicht sichtbar ist.
Ist das möglich?
Vielen Dank
iphone
uiview
uitabbarcontroller
visibility
nstimer
jantimon
quelle
quelle
.window
aktualisieren, dh die Antwort, die überprüft (von walkbrad), da die Antwort, die überprüft wird.superview
(von mahboudz), technisch nicht korrekt ist und Fehler für mich verursacht hat .Antworten:
Sie können überprüfen, ob:
view.superview != nil
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 nachfolgenden Ansichten durchgehen, um festzustellen, ob sie Ihre Ansicht verdecken.
quelle
Für alle anderen, die hier landen:
Um festzustellen, ob ein UIView irgendwo auf dem Bildschirm angezeigt wird, anstatt zu überprüfen
superview != nil
, sollten Sie überprüfen, obwindow != nil
. Im ersteren Fall ist es möglich, dass die Ansicht eine Übersicht hat, die Übersicht jedoch nicht auf dem Bildschirm angezeigt wird:if (view.window != nil) { // do stuff }
Natürlich sollten Sie auch prüfen, ob es eine ist
hidden
oder ob es eine hatalpha > 0
.NSTimer
Wenn Sie nicht möchten, dass Sie ausgeführt werden, 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 überhaupt nicht sicher, was Sie tun.quelle
po [self.view recursiveDescription]
meine Unteransichten in der Ansichtshierarchie angezeigt, aber sieview.window
sind immer gleich Null.self.view
auch einewindow
Null ist. Ist das der Fall? (Entschuldigung für die späte Antwort)Dadurch wird bestimmt, ob sich der Rahmen einer Ansicht innerhalb der Grenzen aller ihrer Übersichten befindet (bis zur Stammansicht). Ein praktischer Anwendungsfall besteht darin, zu bestimmen, ob eine untergeordnete Ansicht (zumindest teilweise) in einer Bildlaufansicht sichtbar ist.
Swift 5.x:
func isVisible(view: UIView) -> Bool { func isVisible(view: UIView, inView: UIView?) -> Bool { guard let inView = inView else { return true } let viewFrame = inView.convert(view.bounds, from: view) if viewFrame.intersects(inView.bounds) { return isVisible(view: view, inView: inView.superview) } return false } return isVisible(view: view, inView: view.superview) }
Ältere schnelle Versionen
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:
alpha
undhidden
.clipsToBounds
, da eine Ansicht die Grenzen ihrer Übersicht überschreiten kann, wenn sie falsch ist.quelle
Die Lösung, die für mich funktioniert hat, bestand darin, zuerst zu überprüfen, ob die Ansicht ein Fenster hat, dann über Übersichten zu iterieren und zu überprüfen, ob:
Scheint bisher 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 }
quelle
Wenn Sie wirklich wissen möchten, ob eine Ansicht für den Benutzer sichtbar ist, müssen Sie Folgendes berücksichtigen:
Insbesondere die transparente Hintergrundfarbe der vorderen Ansichten kann ein Problem darstellen, das programmgesteuert überprüft werden muss. Die einzige Möglichkeit, wirklich sicher zu sein, besteht darin, einen programmgesteuerten Schnappschuss der Ansicht zu erstellen, um sie zu überprüfen und innerhalb ihres Rahmens mit dem Schnappschuss des gesamten Bildschirms zu unterscheiden. Dies funktioniert jedoch nicht für Ansichten, die nicht unterscheidungskräftig genug sind (z. B. vollständig weiß).
Inspiration finden Sie unter der Methode isViewVisible im iOS Calabash-Server-Projekt
quelle
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 }
quelle
In viewWillAppear setzen Sie einen Wert "isVisible" auf true, in viewWillDisappear auf false. Der beste Weg, um für einen UITabBarController Unteransichten zu wissen, funktioniert auch für Navigations-Controller.
quelle
Ich habe sowohl @Audrey M. als auch @John Gibb ihre Lösungen verglichen.
Und @Audrey M. sein Weg schnitt besser ab (mal 10).
Also habe ich das benutzt, um es sichtbar zu machen.
Ich habe ein RxSwift Observable erstellt, um benachrichtigt zu werden, wenn das UIView sichtbar wird.
Dies kann nützlich sein, wenn Sie ein Banner-Ansichtsereignis auslösen möchten
import Foundation import UIKit import RxSwift extension UIView { var isVisibleToUser: Bool { if isHidden || alpha == 0 || superview == nil { return false } guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else { return false } let viewFrame = convert(bounds, to: rootViewController.view) let topSafeArea: CGFloat let bottomSafeArea: CGFloat if #available(iOS 11.0, *) { topSafeArea = rootViewController.view.safeAreaInsets.top bottomSafeArea = rootViewController.view.safeAreaInsets.bottom } else { topSafeArea = rootViewController.topLayoutGuide.length bottomSafeArea = rootViewController.bottomLayoutGuide.length } return viewFrame.minX >= 0 && viewFrame.maxX <= rootViewController.view.bounds.width && viewFrame.minY >= topSafeArea && viewFrame.maxY <= rootViewController.view.bounds.height - bottomSafeArea } } extension Reactive where Base: UIView { var isVisibleToUser: Observable<Bool> { // Every second this will check `isVisibleToUser` return Observable<Int>.interval(.milliseconds(1000), scheduler: MainScheduler.instance) .flatMap { [base] _ in return Observable.just(base.isVisibleToUser) }.distinctUntilChanged() } }
Verwenden Sie es so:
import RxSwift import UIKit import Foundation private let disposeBag = DisposeBag() private func _checkBannerVisibility() { bannerView.rx.isVisibleToUser .filter { $0 } .take(1) // Only trigger it once .subscribe(onNext: { [weak self] _ in // ... Do something }).disposed(by: disposeBag) }
quelle
Auf diese Weise können Sie herausfinden, ob Ihre UIView die oberste Ansicht 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 }
quelle
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 }
quelle
Eine weitere nützliche Methode ist
didMoveToWindow()
Beispiel: Wenn Sie den View Controller drücken, rufen Ansichten Ihres vorherigen View Controllers diese Methode auf. Wenn Sieself.window != nil
indidMoveToWindow()
überprüfen, können Sie feststellen, ob Ihre Ansicht auf dem Bildschirm angezeigt wird oder nicht.quelle
Wenn Sie eine versteckte Ansichtseigenschaft verwenden, gehen Sie wie folgt vor:
view.hidden (Ziel C) oder view.isHidden (schnell) ist eine Lese- / Schreibeigenschaft. So können Sie leicht lesen oder schreiben
Für schnelle 3.0
if(view.isHidden){ print("Hidden") }else{ print("visible") }
quelle