Proportionally Sized Views, Views that inherit backgroundColor

So, I’m a bit of a late adopter. The problem with working intensively on a project that is grossly understaffed is that you don’t have time to keep up with all the technology. So just now am I getting a deeper understanding of Autolayout on iOS.

There is no way to avoid using Autolayout, so if you haven’t started using it, please do! The various screen sizes of the various iPhones, not to mention multi-tasking on iPad will basically demand you use it.

I’ve run into a situation where I might design some elements for iPhone 5s, but on iPhone 6 they could be bigger. I don’t like the complexity of Size classes, and don’t even think they work very well for the different iPhones. I think it was a way to make one layout work on iPhone and iPad. Hmm… the topic here.

On my latest project I found two things that I needed. So I built them. I wanted a UI Element (a UIView) to always maintain a certain proportion of its superview. Say 75% of the screen width. I didn’t know how to do this in Autolayout. (I suspect it might have something to do with Multipliers??)

Anyway, I also wanted to be able to define a view that would just inherit the background color of its superview. This makes it easier to make changes later in Interface Builder without having to go and alter the whole view hierarchy by hand, or to make outlets for all those views and change them in code.

Well, try for yourself. Here’s the code:

// HSProportionallySizedView.h
//
// Created by Stephen O'Connor on 30/09/15.
// Copyright © 2015 Iconoclasm Spasms. All rights reserved.
// Actually, MIT License. Hack to your heart's content!
  
#import <UIKit/UIKit.h>
  
extern CGFloat const HSProportionallySizedViewNoEffect;
  
@interface HSProportionallySizedView : UIView
  
@property (nonatomic, assign) IBInspectable BOOL inheritsBGColor;  // default: NO
  
// between 0...1.f. Defaults to HSProportionallySizedViewNoEffect
@property (nonatomic, assign) IBInspectable CGFloat widthProportion;
@property (nonatomic, assign) IBInspectable CGFloat heightProportion;
  
@end
//  HSProportionallySizedView.m
//
//  Created by Stephen O'Connor on 30/09/15.
//  Copyright © 2015 Iconoclasm Spasms. All rights reserved.
//  Actually, MIT License.  Hack to your heart's content!

#import "HSProportionallySizedView.h"

CGFloat const HSProportionallySizedViewNoEffect = -1.f;

@implementation HSProportionallySizedView

- (void)willMoveToSuperview:(UIView *)newSuperview
{
    if (self.inheritsBGColor) {
        self.backgroundColor = newSuperview.backgroundColor;
    }
}

- (void)awakeFromNib
{
    if (self.inheritsBGColor && self.superview) {
        self.backgroundColor = self.superview.backgroundColor;
    }
}

- (void)makeDefaultValues
{
    _inheritsBGColor = NO;
    _widthProportion = HSProportionallySizedViewNoEffect;
    _heightProportion = HSProportionallySizedViewNoEffect;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self makeDefaultValues];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self makeDefaultValues];
    }
    return self;
}

- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize];
    if (self.superview) {
        
        if (_widthProportion != HSProportionallySizedViewNoEffect) {
            
            CGFloat proportionalWidth = MAX(0, MIN(1, _widthProportion));
            
            if (proportionalWidth == 0) {
                NSLog(@"One of your proportional size values is set to 0!!");
            }
            size.width = proportionalWidth * self.superview.bounds.size.width;
        }
        
        if (_heightProportion != HSProportionallySizedViewNoEffect) {
            
            CGFloat proportionalHeight = MAX(0, MIN(1, _heightProportion));
            if (proportionalHeight == 0) {
                NSLog(@"One of your proportional size values is set to 0!!");
            }
            size.height = proportionalHeight * self.superview.bounds.size.height;
        }
        
    }
    return size;
}
  
@end

You can see that with the default values it behaves exactly like a UIView. So it makes a suitable baseclass in your codebase.

NOTE: I’m sure there’s a way to do the proportional size in Autolayout without this, so please help me in the comments!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s