IBOutletCollection set ordering in Interface Builder

前端 未结 10 1018
我寻月下人不归
我寻月下人不归 2020-11-30 22:20

I am using IBOutletCollections to group several Instances of similar UI Elements. In particular I group a number of UIButtons (which are similar to buzzers in a quiz game) a

相关标签:
10条回答
  • 2020-11-30 22:54

    EDIT: Several commenters have claimed that more recent versions of Xcode return IBOutletCollections in the order the connections are made. Others have claimed that this approach didn't work for them in storyboards. I haven't tested this myself, but if you're willing to rely on undocumented behavior, then you may find that the explicit sorting I've proposed below is no longer necessary.


    Unfortunately there doesn't seem to be any way to control the order of an IBOutletCollection in IB, so you'll need to sort the array after it's been loaded based on some property of the views. You could sort the views based on their tag property, but manually setting tags in IB can be rather tedious.

    Fortunately we tend to lay out our views in the order we want to access them, so it's often sufficient to sort the array based on x or y position like this:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // Order the labels based on their y position
        self.labelsArray = [self.labelsArray sortedArrayUsingComparator:^NSComparisonResult(UILabel *label1, UILabel *label2) {
            CGFloat label1Top = CGRectGetMinY(label1.frame);
            CGFloat label2Top = CGRectGetMinY(label2.frame);
    
            return [@(label1Top) compare:@(label2Top)];
        }];
    }
    
    0 讨论(0)
  • 2020-11-30 22:57

    Not sure when this changed exactly, but as of Xcode 4.2 at least, this no longer seems to be a problem. IBOutletCollections now preserve the order in which the views were added in Interface Builder.

    UPDATE:

    I made a test project to verify that this is the case: IBOutletCollectionTest

    0 讨论(0)
  • 2020-11-30 22:57

    I found that Xcode sorts the collection alphabetically using the ID of the connection. If you open the version editor on your nib file you can easily edit the id's (making sure they are unique otherwise Xcode will crash).

    <outletCollection property="characterKeys" destination="QFa-Hp-9dk" id="aaa-0g-pwu"/>
    <outletCollection property="characterKeys" destination="ahU-9i-wYh" id="aab-EL-hVT"/>
    <outletCollection property="characterKeys" destination="Kkl-0x-mFt" id="aac-0c-Ot1"/>
    <outletCollection property="characterKeys" destination="Neo-PS-Fel" id="aad-bK-O6z"/>
    <outletCollection property="characterKeys" destination="AYG-dm-klF" id="aae-Qq-bam"/>
    <outletCollection property="characterKeys" destination="Blz-fZ-cMU" id="aaf-lU-g7V"/>
    <outletCollection property="characterKeys" destination="JCi-Hs-8Cx" id="aag-zq-6hK"/>
    <outletCollection property="characterKeys" destination="DzW-qz-gFo" id="aah-yJ-wbx"/>
    

    It helps if you first order your object manually in the Document Outline of IB so they show up in sequence in the the xml code.

    0 讨论(0)
  • 2020-11-30 23:03

    Not as far as I am aware.

    As a workaround, you could assign each of them a tag, sequentially. Have the buttons range 100, 101, 102, etc. and the labels 200, 201, 202, etc. Then add 100 to the button's tag to get its corresponding label's tag. You can then get the label by using viewForTag:.

    Alternatively, you could group the corresponding objects into their own UIView, so you only have one button and one label per view.

    0 讨论(0)
  • 2020-11-30 23:03

    The extension proposed by @scott-gardner is great & solves problems such as a collection of [UIButtons] not showing in the expected order. The below code is simply updated for Swift 5. Thanks really goes to Scott for this! extension Array where Element: UIView {

      /**
       Sorts an array of `UIView`s or subclasses by `tag`. For example, this is useful when working with `IBOutletCollection`s, whose order of elements can be changed when manipulating the view objects in Interface Builder. Just tag your views in Interface Builder and then call this method on your `IBOutletCollection`s in `viewDidLoad()`.
       - author: Scott Gardner
       - seealso:
       * [Source on GitHub](bit dot ly/SortUIViewsInPlaceByTag)
       */
      mutating func sortUIViewsInPlaceByTag() {
        sort { (left: Element, right: Element) in
          left.tag < right.tag
        }
      }
    
    }
    
    0 讨论(0)
  • 2020-11-30 23:03

    Here's an extension I created on Array<UIView> to sort by tag, e.g., useful when working w/ IBOutletCollections.

    extension Array where Element: UIView {
    
      /**
       Sorts an array of `UIView`s or subclasses by `tag`. For example, this is useful when working with `IBOutletCollection`s, whose order of elements can be changed when manipulating the view objects in Interface Builder. Just tag your views in Interface Builder and then call this method on your `IBOutletCollection`s in `viewDidLoad()`.
       - author: Scott Gardner
       - seealso:
       * [Source on GitHub](http://bit.ly/SortUIViewsInPlaceByTag)
       */
      mutating func sortUIViewsInPlaceByTag() {
        sortInPlace { (left: Element, right: Element) in
          left.tag < right.tag
        }
      }
    
    }
    
    0 讨论(0)
提交回复
热议问题