Manage Focus with multiple controls on Apple TV

拜拜、爱过 提交于 2019-12-10 23:49:20

问题


I have multiple controls on my screen. A collection view on right-top, then a button at left-center and besides the button, i have another collection view. Please refer the attached image for it

I am able to move the focus from button to bottom collection view and vice versa. I have created a focus guide for the same as below:


        focusGuide.preferredFocusedView = self.btn
        self.view.addLayoutGuide(self.focusGuide)

        self.focusGuide.topAnchor.constraintEqualToAnchor(collectionViewHeader.topAnchor).active = true
        self.focusGuide.bottomAnchor.constraintEqualToAnchor(collectionViewBottom.topAnchor).active = true
        self.focusGuide.leadingAnchor.constraintEqualToAnchor(collectionViewBottom.leadingAnchor).active = true
        self.focusGuide.widthAnchor.constraintEqualToAnchor(collectionViewBottom.widthAnchor).active = true

and in didUpdateFocusInContext: , I have write :


    override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
        super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)

        guard let nextFocusedView = context.nextFocusedView else { return }

            if(nextFocusedView .isKindOfClass(bottomCell)) {
            self.focusGuide.preferredFocusedView = self.btn
        } else {
            self.focusGuide.preferredFocusedView = self.collectionViewBottom
        }
    }

But, I am not able to move focus from button to top collection view. I may need multiple focus guide for this, but I do not know what should come there. Can anyone help me on this?

Thank you


回答1:


I had similar problems in many parts of my UI so ended up defining a custom view to create larger areas of the screen that represent groups of focusable controls. Because I setup these larger areas to cover empty regions that don't contain controls, they intercept the focus movement and transfer to focus to the controls within the area independently of vertical or horizontal alignment with the original control where focus started from.

This is the custom view. You use it by placing one or more controls inside it in IB.

Note that it has additional features such as forcing focus to a specific control without having to override preferredFocusView but you can drop those if you don't need them).

class FocusGroup : UIView
{
   weak private var nextFocusView:UIView? = nil
   weak var initialView:UIView?           = nil
   var captureFocus:Bool                  = false

   func focusOnView(view:UIView, now:Bool=false)
   {
      if not(view.isDescendantOfView(self))
      || view === self
      { return }

      nextFocusView = view
      setNeedsFocusUpdate()
      if now  { updateFocusIfNeeded() }
   }

   func resetFocus(now now:Bool=false)
   {
      nextFocusView = nil
      setNeedsFocusUpdate()
      if now  { updateFocusIfNeeded() }
   }

   override func canBecomeFocused() -> Bool 
   {
      if nextFocusView != nil { return true }
      if containsFocus { return false }      
      return firstFocusableSubView() != nil 
   }


   func firstFocusableSubView() -> UIView?
   {

     return findSubview({ 
                           $0.canBecomeFocused()
                           && $0.userInteractionEnabled
                           && $0.visible
                           &&  ( not($0 is UIButton)
                                 || ($0 as! UIButton).enabled )
                       })
   }


   override var preferredFocusedView: UIView? 
   {
      if let viewToFocus = ( nextFocusView ?? initialView ) ?? firstFocusableSubView() 
      {
        return viewToFocus
      }
      return nil
   }

   override func shouldUpdateFocusInContext(context: UIFocusUpdateContext) -> Bool 
   {
      // when capturing focus, prevent navigation outside of grouped subviews
      if captureFocus 
      && containsFocus 
      && context.previouslyFocusedView!.isDescendantOfView(self)
      && (
            context.nextFocusedView == nil
            || context.nextFocusedView === self 
            || not(context.nextFocusedView!.isDescendantOfView(self))
         )
      { return false }

      return true
   }

   override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) 
   {
      // give focus to specific view as requested
      if nextFocusView != nil
      {
         if context.nextFocusedView === nextFocusView
         || not(nextFocusView!.canBecomeFocused())
         { nextFocusView = nil }
         return
      }      
   }

}



回答2:


Just insert a focus guide above the button and to the left of the top collection view, redirecting focus to the top collection view:

 focusGuide.preferredFocusedView = self.topView
    self.view.addLayoutGuide(focusGuide)

    self.focusGuide.topAnchor.constraintEqualToAnchor(topView.topAnchor).active = true
    self.focusGuide.bottomAnchor.constraintEqualToAnchor(topView.bottomAnchor).active = true
    self.focusGuide.leadingAnchor.constraintEqualToAnchor(btn.leadingAnchor).active = true
    self.focusGuide.trailingAnchor.constraintEqualToAnchor(btn.trailingAnchor).active = true

You may also want to insert a focus guide to the right of the button and below the top collection view so that navigating down from the top row redirects focus to the button instead of to the bottom row.



来源:https://stackoverflow.com/questions/37006755/manage-focus-with-multiple-controls-on-apple-tv

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!