How to Support Tablets and Foldable Phones for Flutter
In the emerging mobile market, foldable phones are still in the lower segment, but they are steadily increasing in popularity. As mobile developers and Flutter enthusiasts, we adhere to the motto of “write once, run everywhere.” Therefore, it would be pointless if we didn’t support Android, which includes foldable phones as well.
As you progress in your career, you’ll find yourself balancing between effort and impact. Naturally, our aim is to prioritize activities that yield the greatest results with the least amount of effort. Regarding foldable phone integration for Flutter, I would classify it as requiring low effort for a moderate impact.
Low effort?! How? Believe it or not, with just a few adjustments, you can optimize your application for foldable phones, making it more effective on Google Play. Allow me to show the way. Below is the link for reference to begin with.
To summarize the article, Google Play offers improved visibility for applications that support larger screen devices, including tablets, foldables, and desktops.
In this article, we will focus exclusively on tablets and foldable devices, setting aside considerations for desktop mode due to its additional complexities like cursor functionalities and right-click interactions, which may not align with low-effort optimizations. For the purpose of this discussion, the term “tablet” will encompass devices such as the iPad, and it’s worth noting that when unfolded, a foldable phone essentially functions as a tablet. Here we have outlined the key strategies for enhancing your app’s appearance on a large screen.
Continuity
The app should maintain the state where the user left off, accommodating foldable devices in both their folded and unfolded states, and supporting device orientation.
Regarding the device orientation support for iOS and Android, it’s worth noting that rotating the device horizontally for regular use is less common, typically reserved for activities like gaming or watching movies. Given this, I recommend limiting iPhone orientation to portrait mode only.
However, for iPads, I would suggest enabling support for all orientations. This is particularly beneficial due to the split-screen functionality of iPadOS, where users may frequently switch between landscape and portrait orientations.
Typically, Flutter applications support continuity automatically. For newly completed projects, this functionality works seamlessly. However, for existing projects, you may need to add the following code snippet to your AndroidManifest.xml file to ensure that your Android foldable phone maintains its state when the user folds or unfolds the device:
<activity
android:name=".MainActivity"
android:resizeableActivity="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout">
</activity>
Adding this code to your AndroidManifest.xml file should help your Flutter app maintain its state on foldable devices.
Maintaining Scroll Position State
To maintain scroll position for lists that retain their layout when device orientation changes, you can utilize the PageStorageKey API. Adding a PageStorageKey to the collections page ensures that users can seamlessly resume their scrolling position even after folding/unfolding the device.
Responsive & Adaptive Layout
To optimize the user experience for larger screens such as iPads and Android tablets, it’s essential to design layouts that leverage the available screen real estate effectively. Instead of merely scaling up existing content, the focus should be on adding more relevant content or enhancing the presentation to make the most of the increased space.
1. Don’t just scale up everything. I’ve seen projects that use MediaQuery to calculate the ratio of the screen based on the design and apply that value to scale up. For example, if the font size is 14 on a phone screen, which is around 375 pixels wide, they calculate it by using MediaQuery.Width / 375, then multiply it by the font size of 14. As a result, the font size ends up being around 20–22, depending on the screen size of the tablet, which doesn’t look good at all. Therefore, don’t follow this approach.
2. Check the condition to determine if the user is on a phone-size, tablet-size, or desktop-size screen by using this:
enum ScreenSize { small, normal, large, extraLarge }
ScreenSize getSize(BuildContext context) {
final deviceWidth = MediaQuery.sizeOf(context).shortestSide;
if (deviceWidth > 900) return ScreenSize.extraLarge;
if (deviceWidth > 600) return ScreenSize.large;
if (deviceWidth > 300) return ScreenSize.normal;
return ScreenSize.small;
}
But since our discussion limits to phones and tablets, I would remove ‘extra large’ from the enum. Once you understand your user’s device type, you can adjust the UI accordingly.
3. Use the library to help you determine if the user is using a foldable phone or just a tablet. You can identify this by checking if their device has a hinge with hingeAngleEvents. You can investigate further by using hasHingeAngleSensor to observe the angle of the fold on the phone. Personally, I’m skipping this 😆 since I don’t want to invest too much effort just to implement functionality for foldable events.
4. Utilize the concept of a list view paired with details to create a split-screen layout. For example, as illustrated below, the ListView is positioned on the left side, while the DetailsView is located on the right side. This approach is recommended as it optimizes the screen space, instead of displaying both the ListView and DetailsView in full screen.
Typically, the ListView occupies about 33% of the device screen, while the DetailsView takes up approximately 66% of the screen. Though it’s important to note that this approach may not be suitable for foldable phones as they essentially double the screen size when unfolded. I would suggest disregarding the 33–66 theory and considering the use of split-screen layouts instead. You can check for tablet or foldable devices by using hasHingeAngleSensor and apply a 33–66 ratio for non-hinge devices and a 50–50 ratio for hinge devices. However, I won’t pursue this approach either and will opt for only 50–50 😆
5. For some pages that don’t have a ListView and DetailsView, utilize ScreenSize to determine and increase the content. For example, you can adjust the parameters such as the number of columns in a GridView, like changing the parameter from 2 to 4 can accommodate larger screen sizes.
Old Design vs New Design: Unfold Mode
By doing so, you preserve the image ratio, ensuring it remains visually appealing rather than simply scaling up.
6. Popups don’t need to occupy the entire screen, as it can detract from the overall appearance of our app. I normally limit the maximum width of popups to around 480 pixels. This approach ensures that the popup appears in full screen on mobile phones, as they generally occupy around 300 to 375 pixels. However, considering devices like the Samsung S24 Ultra, which has a width of around 440 pixels, this maximum width ensures a visually balanced presentation by using ConstrainedBox Widget.
Phone vs Tablet Mode: BottomSheet Popup
Phone vs Tablet: Dialog Old Design
The design includes a nearly full-screen dialog with a 16-pixel padding from the left and right edges. While this layout works well on smaller screens such as phones, it may not be ideal for tablets or in unfolded mode. We should consider adjusting the padding or layout to ensure a more visually appealing appearance across different screen sizes.
Phone vs Tablet: Dialog New Design
Fixed the width of the dialog to not exceed 480 pixels. This number isn’t a universally applicable ‘magic number,’ but rather based on my personal aesthetic preferences. I believe that a range of 400–500 pixels is acceptable for its usage, while Google claims that it shouldn’t be more than 560 pixels.
This pretty much encompasses everything I consider low effort. All we did was simply removing the UI scaling, adding a maximum constraint to dialog width (not exceeding 480 pixels), adjusting parameters for the tablet mode, and configured state retention when folding/unfolding. In total, I spent around 3–4 hours on my current project to transition from non-tablet-friendly to tablet-friendly. If you’re inclined to push further, an adaptive layout could be explored. For instance, you can redesign pages entirely for larger screens. However, I typically opt for responsive layouts to streamline my workflow and save time.
In the meantime, I’m also exploring the dual-screen functionality for Android 14 on my device. Though, it’s currently only available in Native Android.
My experiment will focus on how to utilize both screens — inside and outside — in my current financial app to benefit users. I’m considering displaying non-privacy information to other users while keeping private information on their individual screens. Let’s see how it goes!
For those who enjoy this article, don’t forget to follow Medium: KBTG Life. We have tons of great pieces written by KBTG people in both English and Thai.