February 11, 2016
TABLE OF CONTENTS
To try React out and understand what it means for designers, developers, and users I decided to try to tackle the same challenge I recently had with a design request for a modal search box within an app I was working on. Usually in a native iOS app searching is made available through an inline search bar at the top of a scroll view. However, the screen that I needed to add the search capability to wasn’t a scroll view, so I needed to modally present a search bar after the user tapped on a magnifying glass icon in the navigation bar. It was suggested that I make it work like the native Calendar app for iOS where the search bar animates down from above when it is presented. The final requirement was that a detail view controller should be pushed onto the modal navigation controller stack after a result was tapped, again, just like the native Calendar app.
The first part was fairly straightforward when developing the app using Objective-C. The starting view with the magnifying glass search icon was contained in a UINavigationController so in one line I could call:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(search)];
or in swift:
navigationItem.rightBarButtonItem = UIBarButtonItem( barButtonSystemItem: .Search, target: self, action: "search:" )
Alternatively, this could be setup via a storyboard.
Next, I had to nicely animate the search bar from the top just like the Calendar app so I simply modally presented a configured
presentViewController: on my base view controller. The non-linear animation to drop in the
UISearchBar is contained within
UISearchController so there is no need to guess at the animation settings or update the app every time Apple tweaks the animation with an update.
The final part was the trickiest. We wanted to push a detail view controller into view when the user selects a result, but we didn’t have a
UINavigationController to push onto in our modal view. This UI flow is present in Apple’s Calendar and Music so I thought that there must be an easy way to accomplish this task. I reached out to Apple’s Developer Technical Support (DTS) to make sure I wasn’t missing something simple but they replied that the push functionality in Calendar and Music used private methods. DTS suggested I instead dismiss the
UISearchController after a selection is made and then push a view controller onto the original
UINavigationController stack while keeping track of the search-in-progress with a flag. This way, the
UISearchController is presented again after the user pops the detail view controller. I came up with a different solution which keeps the user in the flow by setting the
UISearchController‘s search results controller property to a
UINavigationController so that the detail view controller can be pushed onto that modal
UINavigationController. I still get the nice drop in animation for the search bar, but I have to hide the search bar on selection of a result and unhide it when the detail view controller is popped. This is less than ideal since the showing of the search bar doesn’t participate in the interactive swipe-to-go-back gesture. This is still better for my use case than modally presenting the search bar after popping the detail view controller because that modal presentation doesn’t participate in the swipe-to-go-back gesture. You can see the result of the approach I took above.
I looked at some example React Native apps since I don’t have much React or React Native experience and I found UIExplore in the React Native Github repo. The starting view has a box to type a search query into, which then filters the original list. This seems like a good starting point. First I needed to clean up the search box. The example uses a
UITextField instead of a
UISearchBar. I pulled up the React Native documentation for
UISearchBar and received zero results. No official React Native support is what you’ll find for a large number of native UI components. The example uses
UINavigationController, but the docs for the React Native equivalent —
NavigatorIOS — lists several issues when using
UINavigationController, such as a backlog of issues that the React Native team isn’t looking into:
For most non-trivial apps, you will want to use Navigator – it won’t be long before you run into issues when trying to do anything complex with NavigatorIOS. – React Native Docs
From this and other things I’ve read about React Native, I gather that a lot of the native iOS views, especially ones with controller in their name, don’t fit well into the declarative UI’s that React Native constructs.
From here, I could write the adapter code needed to make
UISearchBar available to React Native, but someone in the community has beaten me to it. It’s great that this is available, but relying on over 300 lines of community maintained code that lives on top of a completely different paradigm for writing natives for a basic UI component doesn’t instill confidence in me. Tasks that are simple in Obj-C/Swift, such as creating the magnifying glass icon, routinely turned into roadblocks. The
NavigatorIOS class doesn’t have a hook for the
initWithBarButtonSystemItem: method. Also, there isn’t a community library for
UISearchController because once again most native view controllers don’t fit well into the declarative UI model.
A few other areas where you might find it challenging to develop with React Native is with Dynamic Type and custom view controller transitions. React Native currently doesn’t support Dynamic Type because React Native styles text in a web orientated way with font families and sizes where Dynamic Type uses text styles. Custom View Controller transitions can be tricky for React Native when processing incoming data at the same time. Facebook’s post covers the issue the best:
Let me first state that I still have much to learn about React Native. From my limited understanding, React Native works great for a development team that already knows some React and wants to make a performant mobile app. It also works well for an organization that doesn’t want to bifurcate their development teams (iOS and Android) and is already proficient in designing, creating, and maintaining websites.
Go all-in on React Native by starting a greenfield app for both iOS and Android that doesn’t require many platform exclusive mobile features such as NFC for Android or iBeacon for iOS. Optimize the design and development of the app for maximum reuse which means limiting the use of iOS or Android only React Native components. Have those familiar with React lead the development effort and set aside time for knowledge transfer both ways between web and native developers. Make sure everyone is familiar with the platforms by setting up every developer with devices from each platform so that they not only learn that platform but also are able to test their changes on both platforms. Set up a continuous integration server and have developers implement a cross-platform feature and write tests for the platform they are not as familiar with.
I admit that when first looking into React Native I thought it was just a fancier way to write PhoneGap/Cordova apps. Let’s just say I was quite pleasantly surprised. However, if you want the most native experience today and native development works well for your organization then stick to native development while always investigating ways to improve your process and tooling.
Meet our Experts
Steve Moser is an Engineering Manager at Levvel focusing mainly on iOS. He is passionate about leveraging software to deliver great experiences.
You're doing big things, and big things come with big challenges. We're here to help.