IBOutletCollection set ordering in Interface Builder

前端 未结 10 1019
我寻月下人不归
我寻月下人不归 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 23:06

    I ran with cduhn's answer and made this NSArray category. If now xcode really preserves the design-time order this code is not really needed, but if you find yourself having to create/recreate large collections in IB and don't want to worry about messing up this could help (at run time). Also a note: most likely the order in which the objects were added to the collection had something to do with the "Object ID" you find in the Identity Inspector tab, which can get sporadic as you edit the interface and introduce new objects to the collection at a later time.

    .h

    @interface NSArray (sortBy)
    - (NSArray*) sortByObjectTag;
    - (NSArray*) sortByUIViewOriginX;
    - (NSArray*) sortByUIViewOriginY;
    @end
    

    .m

    @implementation NSArray (sortBy)
    
    - (NSArray*) sortByObjectTag
    {
        return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){
            return(
                ([objA tag] < [objB tag]) ? NSOrderedAscending  :
                ([objA tag] > [objB tag]) ? NSOrderedDescending :
                NSOrderedSame);
        }];
    }
    
    - (NSArray*) sortByUIViewOriginX
    {
        return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){
            return(
                ([objA frame].origin.x < [objB frame].origin.x) ? NSOrderedAscending  :
                ([objA frame].origin.x > [objB frame].origin.x) ? NSOrderedDescending :
                NSOrderedSame);
        }];
    }
    
    - (NSArray*) sortByUIViewOriginY
    {
        return [self sortedArrayUsingComparator:^NSComparisonResult(id objA, id objB){
            return(
                ([objA frame].origin.y < [objB frame].origin.y) ? NSOrderedAscending  :
                ([objA frame].origin.y > [objB frame].origin.y) ? NSOrderedDescending :
                NSOrderedSame);
        }];
    }
    
    @end
    

    Then include the header file as you chose to name it and the code can be:

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Order the labels based on their y position
        self.labelsArray = [self.labelsArray sortByUIViewOriginY];
    }
    
    0 讨论(0)
  • 2020-11-30 23:07

    It seems very random how IBOutletCollection is ordered. Maybe I am not understanding Nick Lockwood's methodology correctly - but I as well made a new project, added a bunch of UILabels, and connected them to a collection in the order they were added to the view.

    After logging, I got a random order. It was very frustrating.

    My workaround was setting tags in IB and then sorting the collections like so:

    [self setResultRow1:[self sortCollection: [self resultRow1]]];
    

    Here, resultRow1 is an IBOutletCollection of about 7 labels, with tags set through IB. Here is the sort method:

    -(NSArray *)sortCollection:(NSArray *)toSort {
        NSArray *sortedArray;
        sortedArray = [toSort sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
            NSNumber *tag1 = [NSNumber numberWithInt:[(UILabel*)a tag]];
            NSNumber *tag2 = [NSNumber numberWithInt:[(UILabel*)b tag]];
            return [tag1 compare:tag2];
        }];
    
        return sortedArray;
    }
    

    Doing this, I can now access objects by using [resultRow1 objectAtIndex: i] or such. This saves overhead of having to iterate through and compare tags every time I need to access an element.

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

    I used the extension proposed by @scott-gardner to order Image Views in order to display counters using individual png images of dot-matrix digits. It worked like a charm in Swift 5.

    self.dayDigits.sortUIViewsInPlaceByTag()
    
    func updateDayDigits(countString: String){
            for i in 0...4 {
                dayDigits[i].image = offDigitImage
            }
            let length = countString.count - 1
            for i in 0...length {
                let char = Array(countString)[length-i]
                dayDigits[i].image = digitImages[char.wholeNumberValue!]
            }
        }
    
    0 讨论(0)
  • 2020-11-30 23:10

    I needed this ordering for a collection of UITextField objects for setting where the "Next" button on the keyboard would lead to (field tabbing). This is going to be an international app so I wanted the language direction to be ambiguous.

    .h

    #import <Foundation/Foundation.h>
    
    @interface NSArray (UIViewSort)
    
    - (NSArray *)sortByUIViewOrigin;
    
    @end
    

    .m

    #import "NSArray+UIViewSort.h"
    
    @implementation NSArray (UIViewSort)
    
    - (NSArray *)sortByUIViewOrigin {
        NSLocaleLanguageDirection horizontalDirection = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
        NSLocaleLanguageDirection verticalDirection = [NSLocale lineDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
        UIView *window = [[UIApplication sharedApplication] delegate].window;
        return [self sortedArrayUsingComparator:^NSComparisonResult(id object1, id object2) {
            CGPoint viewOrigin1 = [(UIView *)object1 convertPoint:((UIView *)object1).frame.origin toView:window];
            CGPoint viewOrigin2 = [(UIView *)object2 convertPoint:((UIView *)object2).frame.origin toView:window];
            if (viewOrigin1.y < viewOrigin2.y) {
                return (verticalDirection == kCFLocaleLanguageDirectionLeftToRight) ? NSOrderedDescending : NSOrderedAscending;
            }
            else if (viewOrigin1.y > viewOrigin2.y) {
                return (verticalDirection == kCFLocaleLanguageDirectionLeftToRight) ? NSOrderedAscending : NSOrderedDescending;
            }
            else if (viewOrigin1.x < viewOrigin2.x) {
                return (horizontalDirection == kCFLocaleLanguageDirectionTopToBottom) ? NSOrderedDescending : NSOrderedAscending;
            }
            else if (viewOrigin1.x > viewOrigin2.x) {
                return (horizontalDirection == kCFLocaleLanguageDirectionTopToBottom) ? NSOrderedAscending : NSOrderedDescending;
            }
            else return NSOrderedSame;
        }];
    }
    
    @end
    

    Usage (after layout)

    - (void)viewDidAppear:(BOOL)animated {
        _availableTextFields = [_availableTextFields sortByUIViewOrigin];
    
        UITextField *previousField;
        for (UITextField *field in _availableTextFields) {
            if (previousField) {
                previousField.nextTextField = field;
            }
            previousField = field;
        }
    }
    
    0 讨论(0)
提交回复
热议问题