I told myself I’d take a break for a bit, but I’ve been having too much fun putting together the iPad UI. I just updated my dev branch with a bunch of changes: https://github.com/johnridesabike/WordRoom/tree/working-copy
I’m posting it now because I want to share my AdaptiveView class I came up with. I really wanted a UI that could dynamically change between compact mode for iPhones and iPad split-view, and regular mode for iPad full-screen. Here’s what it looks like:
class AdaptiveView(ui.View):
def __init__(self, nav_column, content_column):
# Putting content_column inside a NavigationView is a hack to make its
# title bar visible. We never invoke the NavigationView methods.
self.add_subview(nav_column)
self.add_subview(ui.NavigationView(content_column))
self.content_column = content_column
self.nav_column = nav_column
# open_words will probably always just have one item, but it's
# technically possible to have more than one open.
self.open_words = []
self.current_layout = None
# background color is used as a border between the columns.
self.background_color = 'lightgrey'
def layout(self):
# 678 is the width of an iPad pro app in 1/2 split mode.
if self.width >= 678 and self.current_layout != 'regular':
self.regular()
elif self.width < 678 and self.current_layout != 'compact':
self.compact()
def compact(self):
nav, content = self.subviews
nav.x = self.x
nav.width = self.width
nav.height = self.height
nav.flex = 'WH'
content.hidden = True
for word in self.open_words:
compact_word_view.load_word(word)
nav.push_view(compact_word_view, False)
self.current_layout = 'compact'
def regular(self):
nav, content = self.subviews
nav.width = 320
nav.height = self.height
nav.flex = 'H'
nav.x = self.x
content.hidden = False
content.flex = 'WHR'
content.x = nav.width + 1
content.width = self.width - nav.width - 1
content.height = self.height
if self.current_layout == 'compact':
for word in self.open_words:
nav.pop_view(False)
self.content_column.load_word(word)
self.current_layout = 'regular'
if __name__ == '__main__':
lookup_view = ui.load_view('lookup')
nav_view = ui.NavigationView(lookup_view, flex='WH')
word_view = ui.load_view('word')
compact_word_view = ui.load_view('word')
container = AdaptiveView(nav_view, word_view)
container.present('fullscreen')
Basically, if you already have two views for navigation and content, you can just load them into an AdaptiveView instance and it will display them according to the window width. You’ll need two instances of the content view (the “word_view” in my code), one to display in the right column and one to push in compact mode. If you open some content and then resize the window, this view will “smartly” move the content from one column to the other.
I also tried making a “regular_narrow” layout for iPads in portrait mode, where just the content is displayed and the menu can slide out with a button. I wasn’t really happy with the way it looked though, and I didn’t take the time to implement features like gestures, so I didn’t include it.
Edit: I’ve since discovered way of checking for the layout class that’s much better than comparing the width. You can use self.objc_instance.traitCollection().horizontalSizeClass()
which returns 1 for compact and 2 for regular.