)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

IOS 16 Orientation Issues

With IOS 16 all my apps that support multiple orientations are now broken when rotating the device. Apple has broken my apps so many times with stuff like this. It’s so frustrating! Anyway…

Here is how I fixed it for my apps. In my main view controller I listen for orientation changes:

  1. [[NSNotificationCenter defaultCenter] addObserver:self
  2.                                       selector:@selector(orientationChange:)
  3.                                       name:UIDeviceOrientationDidChangeNotification
  4.                                       object:nil];

That has been that way for years… works fine and calls orientationChange.

  1. - (void)orientationChange:(NSNotification *)note {
  2.   UIDevice * device = note.object;
  3.   orient = device.orientation;
  4.  
  5.   // found this by searching around github https://github.com/liLeiBest/LZDependencyToolkit/blob/bca976207ef9674632d448e62ac425c22cecbc4f/LZDependencyToolkit/Classes/Category/UIViewController+LZForceRotation.m#L107
  6.   // glad that someone figured it out :D
  7.   if (@available(iOS 16, *)) {
  8.  
  9.     [self setNeedsUpdateOfSupportedInterfaceOrientations];
  10.     [self.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
  11.     NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
  12.     if (array.count) {
  13.  
  14.       UIWindowScene *scene = (UIWindowScene *)array[0];
  15.       UIWindowSceneGeometryPreferencesIOS *geometryperences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:(1 << orient)];
  16.       [scene requestGeometryUpdateWithPreferences:geometryperences errorHandler:^(NSError * _Nonnull error) {
  17.         NSLog(@"Orientation Error:%@", error);
  18.       }];
  19.     }
  20.  
  21.     [self refreshUI];
  22.  
  23.   }

That big blob checking if IOS 16 is available is now necessary. Within my refreshUI method I use the width and height of the screen to position things. It seems that [[UIScreen mainScreen] bounds].size.height now takes a few hundred milliseconds to be updated with the current orientation. Maybe there is some new animation that needs to be disabled, but I have not been able to find it. So, I just delay 200ms and all seems ok:

  1. - (void) refreshUI {
  2.  
  3.   [self delay:0.2 callback:^(void){
  4.  
  5.     UIWindow* window=[[UIApplication sharedApplication] keyWindow];
  6.  
  7.     float t = window.safeAreaInsets.top;
  8.  
  9.     float b = window.safeAreaInsets.bottom;
  10.  
  11.     float l = window.safeAreaInsets.left;
  12.  
  13.     float r = window.safeAreaInsets.right;
  14.  
  15.     H = [[UIScreen mainScreen] bounds].size.height;
  16.     W = [[UIScreen mainScreen] bounds].size.width;
  17.  
  18.     // do some layout change stuff using `W` and `H`
  19.  
  20.   }];
  21. }

My delay method just looks like this:

  1. - (void)delay:(double)time callback:(void(^)(void))callback {
  2.   double delayInSeconds = time;
  3.   dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  4.   dispatch_after(popTime, dispatch_get_main_queue(), callback);
  5. }

Beware of IOS dev – its riddled with this stuff…

// IOS // iPad // iPhone // ui

Remove a DOM HTML Element

  1. const button = document.createElement('button');
  2. button.innerText = 'Hello There';
  3. document.body.appendChild(button);
  4.  
  5. // click anywhere
  6. document.body.addEventListener('click', () => {
  7.   if (button.parentNode != null) {
  8.     button.parentNode.removeChild(button);
  9.   }
  10. });

In vanilla js you’ll find yourself checking if an HTML DOM element can be removed, by seeing if it has a parent (as seen above). Forgetting to do so is the source of many errors.

With the death of IE11 you can use remove()

  1. const button = document.createElement('button');
  2. button.innerText = 'Hello There 2';
  3. document.body.appendChild(button);
  4.  
  5. // click anywhere
  6. document.body.addEventListener('click', () => {
  7.    button.remove();
  8. });

No error occurs when calling remove() on something that is already removed… just like the old jQuery days 😉

// dom // javascript // ui

Inverse of a Function

  1. const expoIn = t => 
  2.   (t==0) ? 0 : Math.pow(2, 10 * (t - 1))
  3.  
  4. const expoInInverse= t => 
  5.   (t==0) ? 0 : ((Math.log(t) + 10 * Math.log(2)) / Math.log(2)) / 10
  6.  
  7.  
  8. console.log(expoIn(.35) + ' ' +  expoInInverse(expoIn(.35)))

Very nice inverse function calculator by user fawad over at Wolfram Alpha. Was attempting to invert a standard “exponential in” easing function – after some futzing I resorted to the calculator 😀

Normalize Value Between 0 and 1

  1. const d = document.body.appendChild(
  2.   document.createElement`div`)
  3. d.innerHTML = `
  4. <input 
  5.   id="input"
  6.   type="range" 
  7.   min="-2" max="5" 
  8.   value="0">
  9. `
  10.  
  11. let val = 0;
  12.  
  13. console.log('drag slider...')
  14.  
  15. const range = (input.max - input.min);
  16.  
  17. input.oninput = () => {
  18.   val = (input.value - input.min) / range
  19.   console.log(input.value + ' - normalized = ' + val)
  20. }
// html // javascript // math // ui

Little Grid

  1. const NUM = 9
  2. const col = 3
  3. const size = 30
  4. const pad = 10
  5. const box = (x, y) => Object.assign(
  6.   document.body.appendChild(
  7.     document.createElement('div')
  8.   ).style, {
  9.     position: 'absolute',
  10.     width: size + 'px', 
  11.     height: size + 'px',
  12.     top: y + 'px', 
  13.     left: x + 'px',
  14.     background: 'red'
  15. })
  16.  
  17. const off = (size + pad)
  18. for (let i = 0; i < NUM; i++) {
  19.   const x = (i % col) * off
  20.   const y = parseInt(i / col, 10) * off
  21.   box(x, y)
  22. }
snippet.zone ~ 2021-22 /// {s/z}