Unreliable iosScreen, tabBar and split view changes

I am trying to create a couple of views that change a little according to orientation.

In landscape, I want a split view - .master has one view (vList), whilst .detail is a tabBar.

In portrait, I want a simple tab view - where vList (from above) is the first tab.

I can do this reasonably well in an IDE build screen - but this doesn’t allow me to access all the views.
I can do this for an programmatically generated screen, but only with a single instance of all the views, tabbars and splits.
If I want to have multiple versions it all comes crashing down.

So now I want to do the same programmatically but I end up with blank views, missing tabs, crashes etc.

I’ve tried some different methods, variously saving instances of the iosViews, iosTabBars, iosScreens and iosScreenContents to be able to apply via app.currentscreen.content = abc.content but none seem to be reliable.

I’m not sure if I am dealing with bugs in the system or bugs in my programming - debugging in iOS is hard.

Some principle questions:

  1. Can an iosView instance appear in more than one iosTabBar or iosSplit?
  2. When applying a new iosScreenContent - what happens to the view that you are currently sitting on? For example, if I have the same iosView in both screens, does it stay sitting on the same view or is a new one activated?
  3. Can instances of iosTabBars, screens and views be saved (eg in arrays) and brought back for re-use. Are there some limitations here?

I have been assuming that I should keep multiple views (screens, tabs etc) in play to be able to navigate around the app. Would I be better off just making a single instance of all the views and re-apply the data each time? How would this then work in a multi-view device like the iPadPro?

Has anyone had better success than me in this area?

A few observations in my dallying with this area in the absence of oracles of wisdom from others:

  1. iosSplitView seems to have no way of accessing screen1.master when in portrait. You might typically have a list in master and some controls in detail - but once you are in split portrait there seems to be no way of getting back to the list (unless you rotate again).

  2. iosSplitView also doesn’t seem to support toolButtons when in portrait. Only the iosSplitView1.master seems to accept toolButtons. This means that when in Portrait there doesn’t seem to be a way of adding a button to the NavigationBar that might allow you to change the app.currentscreen.content to something else (eg to a separate list view). This might be a bug as I note in Apple’s documentation some buttons in their split view when in portrait.

  3. iosTabView does allow toolButtons. So my solution has focused on changing from a split view to a tab view when rotating from landscape to portrait. This allows me to then add toolButtons so that the user can get back to a list view when needed. If buttons were allowed then you could quite easily use the same split view for both orientations, simplifying things somewhat.

  4. Changing from a spilt view to a tab view does not retain the tab positions (as they are now different screens) and there seems to be no way to extract them from iosSplitView1.detail to be applied to iosTabBar1. This remains a problem and seems a significant short-coming for both these screen types. Feature request I think if there’s no known declares for this.

  5. I have tried retaining various instances of iosScreen and iosScreenContent as properties to allow the changing between split and tab views. For some reason saving iosScreen instances doesn’t seem to work at all e.g. despite saving an instance including a split and tab view, returning to it later it seems to have changed to a tab view only.

  6. Same problems with saving iosScreenContent instances. Only generating new screens each time orientation changes seems to result in the desired result - which seems very inefficient.

  7. Don’t use view.contentSize < view.contentSize.width to determine orientation of the screen. Split screens result in ratios that are around the other way. And be careful using the orientation declares noted elsewhere on the forum. Ensure your function returns at least a ternary state (i.e. not just portrait or landscape) as it will quite often return “unknown” - and your code will need to ignore this.

  8. Use of view1.parentSplitView <> nil or view1.parentTabBar <> nil also seem unreliable ways of detecting the current screen or presence of an iPad device. It is quite possible to have both parentSplitView and parentTabBar with some content at the same time - though quite what that means I’m not sure. Instead set a property on startup, based on which view is called by the app.

  9. Split and tab views seem to fire the resized event multiple times (one for each view probably) - code needs to take account of that.

Probably the easiest fixes to above are to provide get and set tabBar positions and to allow toolButtons on the screen1.detail views.

Hi James,

I’ll try to answer most of your statements

1.a. Sliding the finger from left to right will display the Master view.

1.b. The following declare will always show Master view whatever the orientation

Declare Sub setPreferredDisplayMode Lib "UIKit" selector "setPreferredDisplayMode:" (obj As Ptr, mode As Integer) setPreferredDisplayMode(aiOSSplitView.ViewControllerHandle, 2)

1.c. An iOSToolbutton on the split view with the following code will display the Master view momentarily:

Declare Sub setPreferredDisplayMode Lib "UIKit" selector "setPreferredDisplayMode:" (obj As Ptr, mode As Integer) setPreferredDisplayMode(aiOSSplitView.ViewControllerHandle, 3)

  1. I have an app that displays Toolbuttons both in Portrait and Landscape mode. I don’t understand the issue.

3-4. Changing from TabView to Splitview (and the other way-round) seems to be a very bad design. What happens if the user decides to rotate the iPad 10 times in a row ?

5-6. iOSScreenContent is an Interface, not a Class. You shouldn’t be able to retain an instance of it.

  1. Completely true. And sometimes the Resized event of a view can fire before it was actually rotated.

You should use:

[code] declare function NSClassFromString lib FoundationLib (clsName as CFStringRef) as ptr
declare function currentDevice_ lib UIKitLib selector “currentDevice” (clsRef as ptr) as ptr
declare function orientation_ lib UIKitLib selector “orientation” (obj_id as ptr) as integer
Dim ori As Integer = orientation_(currentDevice_(NSClassFromString(“UIDevice”)))
Select Case ori
Case 0
//unknown
Case 1
//portrait
Case 2
//protraitUpsideDown
Case 3
//landscapeleft
Case 4
//landscapeRight
Case 5
//faceUp
Case 6
//faceDown

	End Select
	
	Return ori[/code]
  1. You should either use Jason King’s iOSKit, with the isIPad function (and the above DeviceOrientation function) or this declare:

[code] declare function currentDevice_ lib UIKitLib selector “currentDevice” (clsRef as ptr) as ptr
declare function model_ lib UIKitLib selector “model” (obj_id as ptr) as CFStringRef
dim model as Text = model_(currentDevice_(NSClassFromString(“UIDevice”)))
dim isPad as boolean = model.BeginsWith(“iPad”)

	Return isPad[/code]

Again, Toolbuttons on Splitview detail are supported.
But maybe I’m not seeing any issue because 90% of the Toolbuttons are created by code and not by drag&drop in the layout editor:

dim tb As iOSToolButton = iOSToolButton.NewSystemItem(iOSToolButton.Types.SystemCancel) tb.Tag = "cancel" self.RightNavigationToolbar.Add tb

Jrmie
Many thanks for the detailed reply.

[quote]Sliding the finger from left to right will display the Master view.[/quote] Duh! How stupid of me! I’d been thinking that in the back of my mind - but never tried it. That fixes many of my issues.

I think my one remaining problem is getting toolButtons onto the split view in Portrait. Using code I add tool buttons to all the views - i.e. those in the master view and in the detail views. In Landscape, the tool buttons appear only at the top of the Master view - I guess that is OK. In Portrait I only get toolButtons appearing when the Master view is dragged in. Nothing appears above any of the detail views.

A further question for you Jrmie.

In iPhone - say I have a simple view with a list (called vList) how can I do a pushTo an iosTabBar?

I tried building an iosTabBar containing view1, view2 etc and then pushTo(view1) but that no longer contains the tabs.

I can do an app.currentScreen.content - but that loses the nice animation effects and automatic back buttons.

Alternatively - if I use a split view in iPhone - I can see a back button to take me to the Master, but how do I get back to the detail view again?

Antonio shared some code to select a Tab:
https://forum.xojo.com/18750-programmatically-select-a-tabbar-tab/p1#p157150

You can’t use split view on iphone
It is an iPad only feature, unless using declares and ONLY on iPhone 6/7 Plus

One of my apps has a SplitView on iPad, and a TabView on iPhone. This seemed like the best UX for both devices.

Thanks - so no way of doing a view.pushto a tabBar?

I don’t understand what you mean.

You would like to replace the contents of a Tab by an iOSView ?

On iPhone I’d like to go from a table in an iosview to an iosTabBar - using a pushTo.

@JrmieLeroy Can you tell me where to use this code?

My app is similar to the iOS Contacts app and, when on iPad, I’m trying to keep the Master view on the left at all times, even in portrait mode, like this:

https://drive.google.com/open?id=0B1nZKDrfgvd_OHI1QU52UmE5SXM

https://drive.google.com/open?id=0B1nZKDrfgvd_bHJoNC01R2ZDT3c

Actually please ignore that question. I worked out that I need to put that code in the Resize event of each View.

However I’ve got the same problem as the OP with regard to tool buttons. I add them programatically to my views and they don’t appear in either the left or right navigation bar of the master view when using split views. There’s no problem with the detail view tool buttons, only the master view.

@James Pitchford did you ever solve that problem?

Edit. It seems that this is also my issue: <https://xojo.com/issue/45164>

Jason - my left and right navigation buttons only appear in the master view in split - not in the other views. Conversely - regular tool buttons do appear at the bottom - above the tab-bar in the detail views and on the bottom of the master view.

Thanks James. It’s the other way around for me. In my case the left/right navigation bar toolbuttons appear only in the split (right side) view and not the master (left side) view. I can code around the issue by changing the way my app works with split views/iPads but it’s not ideal.

Let me modify my answer a bit as I’ve been focussing more on iPhone than iPad.
On iPad in Landscape - I get navbarLeft and navbarRight at the top of the master view and toolbar at the bottom.

However the detail views (tab views) now give me nothing - I can see that the tabs seem to get over-written by something (presumably the toolbars).

In portrait - when I drag in the master view it correctly shows me the navbarRight and navBarleft and toolbars in the correct places.

Bit the detail views are all screwed up. I can’t get any navbars at the top and any tabbars at the bottom get overwritten by the toolbar and nothing shows.