Wednesday 15 July 2015

objective c - Sizing class for iPad portrait and Landscape Modes -



objective c - Sizing class for iPad portrait and Landscape Modes -

i want have subviews positioned differently depending upon orientation of ipad (portrait or landscape) using sizing classes introduced in xcode 6. have found numerous tutorials explaining how different sizing classes available iphones in portrait , landscape on ib there seem none cover individual landscape or portrait modes ipad on ib. can help?

it appears apple's intent treat both ipad orientations same -- number of finding, there legitimate design reasons want vary ui layout ipad portrait vs. ipad landscape.

unfortunately, current os doesn't seem provide back upwards distinction ... meaning we're manipulating auto-layout constraints in code or similar workarounds accomplish should ideally able free using adaptive ui.

not elegant solution.

isn't there way leverage magic apple's built ib , uikit utilize size class of our choosing given orientation?

~

in thinking problem more generically, realized 'size classes' ways address multiple layouts stored in ib, can called needed @ runtime.

in fact, 'size class' pair of enum values. uiinterface.h:

typedef ns_enum(nsinteger, uiuserinterfacesizeclass) { uiuserinterfacesizeclassunspecified = 0, uiuserinterfacesizeclasscompact = 1, uiuserinterfacesizeclassregular = 2, } ns_enum_available_ios(8_0);

so regardless of apple has decided name these different variations, fundamentally, they're pair of integers used unique identifier of sorts, distinguish 1 layout another, stored in ib.

now, supposing create alternate layout (using unused size class) in ib -- say, ipad portrait ... there way have device utilize our choice of size class (ui layout) needed @ runtime?

after trying several different (less elegant) approaches problem, suspected there might way override default size class programmatically. , there (in uiviewcontroller.h):

// phone call modify trait collection kid view controllers. - (void)setoverridetraitcollection:(uitraitcollection *)collection forchildviewcontroller:(uiviewcontroller *)childviewcontroller ns_available_ios(8_0); - (uitraitcollection *)overridetraitcollectionforchildviewcontroller:(uiviewcontroller *)childviewcontroller ns_available_ios(8_0);

thus, if can bundle view controller hierarchy 'child' view controller, , add together top-level parent view controller ... can conditionally override kid thinking it's different size class default os.

here's sample implementation this, in 'parent' view controller:

@interface rdtraitcollectionoverrideviewcontroller : uiviewcontroller { bool _willtransitiontoportrait; uitraitcollection *_traitcollection_compactregular; uitraitcollection *_traitcollection_anyany; } @end @implementation rdtraitcollectionoverrideviewcontroller - (void)viewdidload { [super viewdidload]; [self setupreferencesizeclasses]; } - (void)setupreferencesizeclasses { uitraitcollection *traitcollection_hcompact = [uitraitcollection traitcollectionwithhorizontalsizeclass:uiuserinterfacesizeclasscompact]; uitraitcollection *traitcollection_vregular = [uitraitcollection traitcollectionwithverticalsizeclass:uiuserinterfacesizeclassregular]; _traitcollection_compactregular = [uitraitcollection traitcollectionwithtraitsfromcollections:@[traitcollection_hcompact, traitcollection_vregular]]; uitraitcollection *traitcollection_hany = [uitraitcollection traitcollectionwithhorizontalsizeclass:uiuserinterfacesizeclassunspecified]; uitraitcollection *traitcollection_vany = [uitraitcollection traitcollectionwithverticalsizeclass:uiuserinterfacesizeclassunspecified]; _traitcollection_anyany = [uitraitcollection traitcollectionwithtraitsfromcollections:@[traitcollection_hany, traitcollection_vany]]; } -(void)viewwillappear:(bool)animated { [super viewwillappear:animated]; _willtransitiontoportrait = self.view.frame.size.height > self.view.frame.size.width; } - (void)viewwilltransitiontosize:(cgsize)size withtransitioncoordinator:(id<uiviewcontrollertransitioncoordinator>)coordinator { _willtransitiontoportrait = size.height > size.width; } -(uitraitcollection *)overridetraitcollectionforchildviewcontroller:(uiviewcontroller *)childviewcontroller { uitraitcollection *traitcollectionforoverride = _willtransitiontoportrait ? _traitcollection_compactregular : _traitcollection_anyany; homecoming traitcollectionforoverride; } @end

as quick demo see whether worked, added custom labels 'regular/regular' , 'compact/regular' versions of kid controller layout in ib:

and here's looks running, when ipad in both orientations:

voila! custom size class configurations @ runtime.

hopefully apple create unnecessary in next version of os. in meantime, may more elegant , scalable approach programmatically messing auto-layout constraints or doing other manipulations in code.

~

edit (6/4/15): please bear in mind sample code above proof of concept demonstrate technique. sense free adapt needed own specific application.

~

edit (7/24/15): it's gratifying above explanation seems help demystify issue. while haven't tested it, code mohamede1945 [below] looks helpful optimization practical purposes. sense free test out , allow know think. (in involvement of completeness, i'll leave sample code above as-is.)

objective-c ios8 size-classes adaptive-ui

No comments:

Post a Comment