Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-25301] iPhone X: Need to be able to control the Insets / Layout Margins

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2017-10-16T21:45:00.000+0000
Affected Version/sRelease 6.2.0
Fix Version/sRelease 6.3.0
ComponentsiOS
Labelsiphonex
ReporterMatthew Delmarter
AssigneeVijay Singh
Created2017-09-16T10:25:45.000+0000
Updated2018-07-27T23:11:35.000+0000

Description

I am not sure what property will allow control over the indents that seem to automatically happen when the device is rotated into Landscape, but we really need to be able to control these. The "Designing for iPhone X" video from Apple mentioned that "Even if you are not using Auto Layout, UIView provides the Safe Area Insets and Layout Margin values as properties." There are many instances in my app where a rotation to Landscape causes messy UI issues. If I can programmatically control the Insets and Layout Margin, particularly when it affects ListViews and TableViews, that would be great. For example see the attached screenshot. I would like to programmatically disable the margin on the ListView if the orientation is LANDSCAPE_RIGHT, as the margin is unnecessary and ugly. But obviously if rotated the other way, then the indent / margin is needed.

Attachments

FileDateSize
iPhone_X_-_iOS_11_0_and_Desktop_—_Local.png2017-09-16T10:27:59.000+0000148653
iPhone_X_-_iOS_11_0_and_Desktop_—_Local.png2017-09-16T10:25:14.000+0000154287

Comments

  1. Hans Knöchel 2017-09-16

    Hey there, thank you for this ticket as well! Really great feedback. We are working on the safe-area updates already and currently designing it in a way it's easy to adapt. Maybe a new property useSafeArea: [true/false] would make sense? Let me know if you have thoughts that would help from a developers perspective! P.S.: Nice app, you should show-case that :-)
  2. Matthew Delmarter 2017-09-16

    @Hans thanks for the feedback :) I don't have a total understanding of the options that Apple is making available. Is the useSafeArea a tiapp.xml entry? Or a window property? Or a ListView/TableView property? Although there may be an app level or window level setting, I would love to be able to control the useSafeArea true/false at a ListView/TableView level. i.e. not just when the ListView is initially created, but at any time. This is because I would like to have a different inset value for LANDSCAPE_LEFT as opposed to LANDSCAPE_RIGHT. So I would need to be able to change this on the ListView or TableView when the orientation change is detected. Beyond that I am not sure, but seem to see vague references to Layout Margins, and the ability to control these? If it is possible to control the Layout Margins at a granular level then that also would be great and I think give developers the flexibility they need for various situations. The default Layout Margins will likely be ok "most" of the time, but Apple has thrown us a real curve-ball here if we do anything too creative, which of course we want to be able to do. So if we are able to control the size of the Margin at a granular level that would also be very welcome. I hope that helps. As mentioned, I am not totally confident about the options Apple makes available, so forgive me if some of the things I mention are not possible.
  3. Sebastian Klaus 2017-09-21

    Something like *useSafeArea* in the tiapp.xml would be very comfortable
  4. Hans Knöchel 2017-09-21

    We are working on a Window-based extendSafeArea property that allows developers to manually extend the safe-area per window. It will be false by default, respecting the safe-area. For properties like backgroundColor, backgroundGradient and backgroundImage, it will still extend the layout automatically to not have any black bars at the top and bottom. In addition, root-containers like Ti.UI.iOS.NavigationWindow and Ti.UI.TabGroup, as well as the Ti.UI.Window.toolbar will adjust automatically as managed by iOS.
  5. Matthew Delmarter 2017-09-21

    @Hans that sounds great thank you. Just wanted to verify that the property can be applied dynamically, not just when the window is initially created. Hopefully :) Thanks for your efforts.
  6. Matt Berg 2017-09-21

    To add to this ticket, would it be possible to get access to the safeAreaLayoutGuide? That way we could programmatically get the values (view.safeAreaLayoutGuide.topAnchor) Example here: https://www.bignerdranch.com/blog/wwdc-2017-large-titles-and-safe-area-layout-guides/
  7. Vijay Singh 2017-09-23

    Master (PR) : https://github.com/appcelerator/titanium_mobile/pull/9475 Test Case 1 -
       var win = Ti.UI.createWindow({
           backgroundColor: 'yellow',
           extendSafeArea : true
       });
       
       var btn = Ti.UI.createButton({
           left:0,
           top:0,
           title: 'Trigger'
       });
       
       
       
       var win2 = Ti.UI.createWindow({
           backgroundColor: 'green',
           extendSafeArea : false
       });
       
       var btn2 = Ti.UI.createButton({
           bottom:0,
           title: 'Trigger2'
       });
       
       win2.add(btn2);
       
       var btn3 = Ti.UI.createButton({
           top:0,
           title: 'Trigger3'
       });
       
       win2.add(btn3);
       
       win.addEventListener('click', function() {
           Ti.API.info('Hello world!');
           win2.open();
       });
       
       btn2.addEventListener('click', function() {
           Ti.API.info('Hello world!');
           win2.close();
       });
       
       win.add(btn);
       win.open();
       
       
    Test Case 2 -
       var win1 = Ti.UI.createWindow({
           backgroundColor: 'blue',
           title: 'Blue',
           extendSafeArea:true
       });
       var label1 = Ti.UI.createLabel({
         text: 'I am a blue window.',
         top: 0,
         left: 0
       });
       win1.add(label1);
       
       var win2 = Ti.UI.createWindow({
           backgroundColor: 'red',
           title: 'Red'
       });
       var label2 = Ti.UI.createLabel({
         text: 'I am a red window.',
         top: 0,
         left: 0
       });
       win2.add(label2);
       
       var tab1 = Ti.UI.createTab({
           window: win1,
           title: 'Blue'
       }),
       tab2 = Ti.UI.createTab({
           window: win2,
           title: 'Red'
       }),
       tabGroup = Ti.UI.createTabGroup({
           tabs: [tab1, tab2]
       });
       tabGroup.open();
       
    Test Case 3-
       var win2 = Titanium.UI.createWindow({
           backgroundColor: 'red',
           title: 'Red Window',
           extendSafeArea:true
       });
       
       var win1 = Titanium.UI.iOS.createNavigationWindow({
          window: win2
       });
       
       var win3 = Titanium.UI.createWindow({
           backgroundColor: 'blue',
           title: 'Blue Window'
       });
       
       var button = Titanium.UI.createButton({
           title: 'Open Blue Window',
           bottom:0
       });
       button.addEventListener('click', function(){
           win1.openWindow(win3, {animated:true});
       });
       
       win2.add(button);
       var button2 = Titanium.UI.createButton({
           title: 'Close Blue Window',
           bottom:0
       });
       button2.addEventListener('click', function(){
           win1.closeWindow(win3, {animated:false}); //win3.close() will also work!!
       });
       
       win3.add(button2);
       win1.open();
       
    Test case 4:
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff',
           extendSafeArea:false
       });
       
       var btn1 = Ti.UI.createButton({
           top:50,
       
           title: 'Replace with button 4'
       });
       
       btn1.addEventListener('click', function() {
           Ti.API.info('Replaced with button 4!');
           win.replaceAt({
               'position':0,
               'view':btn4
           });
       });
       
       var btn2 = Ti.UI.createButton({
           top: 100,
           title: 'Remove'
       });
       
       btn2.addEventListener('click', function() {
           Ti.API.info('Remove button removed!');
           win.remove(btn2);
       });
       
       var btn3 = Ti.UI.createButton({
           top: 150,
       
           title: 'Remove all'
       });
       
       btn3.addEventListener('click', function() {
           Ti.API.info('All buttons removed!');
           win.removeAllChildren(win);
       });
       
       var btn4 = Ti.UI.createButton({
           top:200,
           title: 'Button 4'
       });
       
       btn4.addEventListener('click', function() {
           Ti.API.info('Hello world!');
       });
       
       win.add(btn1);
       win.add(btn2)
       win.add(btn3);
       win.open();
       
  8. Vijay Singh 2017-09-28

    PR (6_3_X) : https://github.com/appcelerator/titanium_mobile/pull/9485
  9. Hans Knöchel 2017-09-29

    Putting ticket back in progress as there are some critical issues that need to be addressed before:

    When placing a plain view into a window, it does not extend the status-bar anymore (not 100 % sure this is a valid issue with this PR as the status-bar probably also is a safe-area, but it's definitely a breaking change that would need to go into 7.0.0)

    When testing my [Studentenfutter sample-app](https://github.com/hansemannn/studentenfutter-app), the app works initially but then freezes after opening a window a few times.

    Code for (1):
       var win = Ti.UI.createWindow();
       win.add(Ti.UI.createView({ backgroundColor: 'red' }));
       win.open();
       
  10. Matthew Delmarter 2017-09-30

    Also I am curious about the extendSafeArea property. The tests show this being set at the time a window is created. But, as per the initial requests in this ticket, can this property be updated later? After window creation? For example I can change the window title whenever I like. Can I do the same with extendSafeArea?
  11. Vijay Singh 2017-10-02

    [~hknoechel] Status bar is not part of safe area, if we see that in native iOS app. Actually our window by default have clearColor. So status bar is not visible . If we set backgroundColor of window, status bar will visible. [~mdelmarter] This property can be set at creation of window only. And it is per window.
  12. Vijay Singh 2017-10-05

    Let's expose safeAreaView to developer. When developer wants to modify the layout of safeAreaView other than default safe area, they can. If extendSafeArea is false it will return the TIViewProxy if true will return nil. And rather making default value of extendSafeArea false, we should make it true. Reason is if someone really need to use this then only will pass it in window and will be aware of the behavior of safe area. If we make default to false , safe area will come in picture and may be developer will not be aware of the same. [~hknoechel] What you think?
  13. Hans Knöchel 2017-10-05

    I like the general idea to habe safe-area specific views as well (to be more flexible) and I'd love to hear more feedback from [~mdelmarter] if possible!
  14. Vijay Singh 2017-10-11

    Test Cases for split window - Test Case 5.
        var detail = Ti.UI.createWindow({backgroundColor: 'white',extendSafeArea:false});
        var label1 = Ti.UI.createLabel({text: 'Detail View', left:0, top:0});
        detail.add(label1);
        var label3 = Ti.UI.createLabel({text: 'Detail View 1', right:0, bottom:0});
        detail.add(label3);
        
        var detailNav = Ti.UI.iOS.createNavigationWindow({window: detail});
        
        var master = Ti.UI.createWindow({backgroundColor: 'gray', extendSafeArea:false});
        var label2 = Ti.UI.createLabel({text: 'Master View', left:0, top:0});
        master.add(label2);
        
        var label4 = Ti.UI.createLabel({text: 'Master View', bottom:0, right:0});
        
        master.add(label4);
        
        var masterNav = Ti.UI.iOS.createNavigationWindow({window: master});
        
        var splitWin = Ti.UI.iOS.createSplitWindow({
            detailView: detailNav,
            masterView: masterNav,
            showMasterInPortrait:true
        });
        splitWin.open();
        
        
    Test Case 6 -
        var label1 = Ti.UI.createLabel({text: 'Detail View', left:0, top:0});
        detail.add(label1);
        var label3 = Ti.UI.createLabel({text: 'Detail View 1', right:0, bottom:0});
        detail.add(lvar detail = Ti.UI.createWindow({backgroundColor: 'white',extendSafeArea:false});
        abel3);
        
        var master = Ti.UI.createWindow({backgroundColor: 'gray', extendSafeArea:false});
        var label2 = Ti.UI.createLabel({text: 'Master View', left:0, top:0});
        master.add(label2);
        
        var label4 = Ti.UI.createLabel({text: 'Master View 1', bottom:0, right:0});
        
        master.add(label4);
        
        var splitWin = Ti.UI.iOS.createSplitWindow({
            detailView: detail,
            masterView: master,
            showMasterInPortrait:true
        });
        splitWin.open();
        
    Test Case 7 -
        var win1 = Ti.UI.createWindow({
            backgroundColor: 'blue',
            title: 'Blue',
            extendSafeArea:false
        });
        var label1 = Ti.UI.createLabel({
          text: 'I am a blue window.',
          top: 0,
          left: 0
        });
        win1.add(label1);
        
        var win2 = Ti.UI.createWindow({
            backgroundColor: 'red',
            title: 'Red',
            extendSafeArea:false
        });
        var label2 = Ti.UI.createLabel({
          text: 'I am a red window.',
          bottom: 0,
          right: 0
        });
        win2.add(label2);
        
        var tab1 = Ti.UI.createTab({
            window: win1,
            title: 'Blue'
        }),
        tab2 = Ti.UI.createTab({
            window: win2,
            title: 'Red'
        }),
        tabGroup = Ti.UI.createTabGroup({
            tabs: [tab1, tab2]
        });
        
        var master = Ti.UI.createWindow({
          backgroundColor: 'gray',
           extendSafeArea:false
         });
        var label3 = Ti.UI.createLabel({
          text: 'Master View', 
          left:0, 
          top:0
        });
        master.add(label3);
        var label4 = Ti.UI.createLabel({
          text: 'Master View', 
          bottom:0, 
          right:0
        });
        master.add(label4);
        
        var masterNav = Ti.UI.iOS.createNavigationWindow({
          window: master
        });
        
        var splitWin = Ti.UI.iOS.createSplitWindow({
            detailView: tabGroup,
            masterView: masterNav,
            showMasterInPortrait:true,
        });
        splitWin.open();
        
  15. Abir Mukherjee 2017-11-14

    PR on master merged.
  16. Eric Wieber 2017-11-14

    Verified in SDK builds 6.3.0.GA & 7.0.0.v20171114134144
  17. Matthew Delmarter 2017-11-15

    Hey guys - just wanted to acknowledge the work done here. Sorry I didn't reply earlier, life has thrown some unexpected curveballs lately. I have been updating my app for iPhone X support and am very pleased with the results. All working well. Thanks again.

JSON Source