Определить, виден ли пользователь UIView? - PullRequest
66 голосов
/ 08 октября 2009

можно ли определить, виден ли мой UIView пользователю или нет?

My View добавляется как subview несколько раз в Tab Bar Controller.

Каждый экземпляр этого представления имеет NSTimer, который обновляет представление.

Однако я не хочу обновлять вид, который не виден пользователю.

Возможно ли это?

Спасибо

Ответы [ 9 ]

98 голосов
/ 13 ноября 2013

Для всех, кто сюда попал:

Чтобы определить, находится ли где-нибудь на экране UIView, вместо проверки superview != nil, лучше проверить, если window != nil. В первом случае возможно, что представление имеет суперпредставление, но суперпредставление не отображается на экране:

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

Конечно, вы должны также проверить, является ли он hidden или имеет alpha > 0.

Если вы не хотите, чтобы ваш NSTimer работал, пока вид не виден, вы должны скрыть эти виды вручную, если это возможно, и отключить таймер, когда вид скрыт. Однако я совсем не уверен в том, что ты делаешь.

72 голосов
/ 11 октября 2009

Вы можете проверить, если:

  • скрыто, проверяя view.hidden
  • это в иерархии представлений, проверяя view.superview != nil
  • Вы можете проверить границы вида, чтобы увидеть, отображается ли он на экране

Единственное, о чем я могу думать, это о том, скрыт ли ваш взгляд за другими и по этой причине его не видно Возможно, вам придется просмотреть все последующие взгляды, чтобы увидеть, не затеняют ли они ваш взгляд.

18 голосов
/ 06 января 2016

Это определит, находится ли кадр представления в границах всех его суперпредставлений (вплоть до корневого представления). Одним из практических вариантов использования является определение, является ли дочернее представление (хотя бы частично) видимым в представлении прокрутки.

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

Потенциальные улучшения:

  • Респект alpha и hidden.
  • Respect clipsToBounds, поскольку представление может выходить за пределы своего суперпредставления, если оно ложно.
14 голосов
/ 14 июля 2017

Решение, которое работало для меня, состояло в том, чтобы сначала проверить, есть ли у представления окно, затем перебрать суперпредставления и проверить:

  1. вид не скрыт.
  2. представление находится в пределах своих суперпредставлений.

Кажется, до сих пор хорошо работает.

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
}
3 голосов
/ 07 ноября 2016

Если вы действительно хотите знать, виден ли пользователь для просмотра, вам необходимо принять во внимание следующее:

  • Разве окно вида не равно нулю и равно верхнему самому окну
  • Является ли представление и все его суперпредставления альфа> = 0,01 (пороговое значение также используется UIKit для определения того, должен ли он обрабатывать касания) и не скрыто
  • Является ли z-индекс (значение стека) представления выше, чем другие представления в той же иерархии.
  • Даже если z-индекс ниже, это может быть видно, если другие виды сверху имеют прозрачный фоновый цвет, альфа 0 или скрыты.

Особенно прозрачный фоновый цвет представлений спереди может создать проблему для программной проверки. Единственный способ быть по-настоящему уверенным - это сделать программный снимок вида, чтобы проверить и отобразить его в кадре со снимком всего экрана. Однако это не будет работать для видов, которые недостаточно различимы (например, полностью белый).

Для вдохновения см. Метод isViewVisible в проекте iOS Calabash-server

2 голосов
/ 26 января 2016

В viewWillAppear установите значение «isVisible» в значение true, в viewWillDisappear установите его в значение false. Лучший способ узнать для подпредставлений UITabBarController, также работает для контроллеров навигации.

1 голос
/ 26 апреля 2016

Это может помочь вам понять, является ли ваш UIView самым верхним видом. Может быть полезно:

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
}
0 голосов
/ 13 марта 2019

попробуйте это:

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 голосов
/ 08 мая 2017

Если вы используете скрытое свойство view, то:

view.hidden (цель C) или view.isHidden (swift) является свойством чтения / записи. Так что вы можете легко читать или писать

Для быстрой версии 3.0

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