{"id":2777,"date":"2022-09-22T12:58:48","date_gmt":"2022-09-22T19:58:48","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=2777"},"modified":"2022-09-22T12:58:48","modified_gmt":"2022-09-22T19:58:48","slug":"jetpack-compose-accompanist-twopane","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/jetpack-compose-accompanist-twopane\/","title":{"rendered":"Jetpack Compose Accompanist TwoPane"},"content":{"rendered":"<p>\n  Hello Compose developers!\n<\/p>\n<p>\n  This week, we\u2019d like to talk about the <a href=\"https:\/\/google.github.io\/accompanist\/adaptive\/\">TwoPane<\/a> layout from Google\u2019s Accompanist Adaptive library!\n<\/p>\n<p>\n  Not to be confused with our own Microsoft Compose SDK <a href=\"https:\/\/learn.microsoft.com\/dual-screen\/android\/jetpack\/compose\/two-pane-layout\">TwoPaneLayout component<\/a>, TwoPane from Accompanist is a fold-aware UI component that works great for cases when you always want to show two pieces of content.\n<\/p>\n<h2>Accompanist libraries<\/h2>\n<p>\n  If you\u2019re unfamiliar with Accompanist, it\u2019s a group of support\/utility libraries built for Jetpack Compose. These libraries are considered to be more experimental, which is why they\u2019re not yet part of AndroidX, but <a href=\"https:\/\/google.github.io\/accompanist\">according to Google<\/a>, the eventual goal is to \u201cupstream them into the official toolkit, at which point they will be deprecated and removed from Accompanist\u201d.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"2501\" height=\"1392\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1.png\" class=\"wp-image-2778\" alt=\"\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1.png 2501w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1-300x167.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1-1024x570.png 1024w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1-768x427.png 768w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1-1536x855.png 1536w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/graphical-user-interface-text-application-email-1-2048x1140.png 2048w\" sizes=\"(max-width: 2501px) 100vw, 2501px\" \/>\n<\/p>\n<p><em>Figure 1. Picture of the Accompanist overview page.<\/em>\n<\/p>\n<p>\n  Right now, Accompanist offers the following libraries:\n<\/p>\n<ul>\n<li>\n    System UI Controller\n  <\/li>\n<li>\n    AppCompat Theme Adapter\n  <\/li>\n<li>\n    Pager\n  <\/li>\n<li>\n    Permissions\n  <\/li>\n<li>\n    Placeholder\n  <\/li>\n<li>\n    Flow Layouts\n  <\/li>\n<li>\n    Navigation-Animation\n  <\/li>\n<li>\n    Navigation-Material\n  <\/li>\n<li>\n    Drawable Painter\n  <\/li>\n<li>\n    Swipe to Refresh\n  <\/li>\n<li>\n    Web\n  <\/li>\n<li>\n    Adaptive\n  <\/li>\n<\/ul>\n<p>\n  In this blog post, we\u2019ll focus on Adaptive, the last library, but if you want to learn more about the others, you can check out these <a href=\"https:\/\/medium.com\/androiddevelopers\/jetpack-compose-accompanist-an-faq-b55117b02712\">FAQS<\/a> or <a href=\"https:\/\/medium.com\/surfstudio\/accompanist-the-first-chord-a-jetpack-compose-library-reviewed-9e007771db70\">this library review<\/a>.\n<\/p>\n<h2>Use the TwoPane component<\/h2>\n<p>\n  The TwoPane component from the Adaptive Accompanist library helps you place <strong>exactly two<\/strong> groups of content on the screen and it uses Jetpack Window Manager to provide foldable support.\n<\/p>\n<p>\n  For those of you who are familiar with our Microsoft TwoPaneLayout component, you may notice that the main difference here is that TwoPane <strong>always shows these two groups of content<\/strong>, whereas with TwoPaneLayout, you show only one group of content at a time when no fold is present. As mentioned in the <a href=\"https:\/\/google.github.io\/accompanist\/api\/adaptive\/com.google.accompanist.adaptive\/-two-pane.html\">TwoPane API documentation<\/a>:\n<\/p>\n<p><em> \u201cThe TwoPane layout will always place both first and second, based on the provided strategy and window environment. If you instead only want to place one or the other, that should be controlled at a higher level and not calling TwoPane if placing both is not desired.\u201d<\/em>\n<\/p>\n<p>\n  You can import the latest version of the Adaptive library in your project:\n<\/p>\n<pre>implementation \"com.google.accompanist:accompanist-adaptive:0.26.3-beta\"<\/pre>\n<p>\n  Note that the latest version depends on Compose <code>1.3.0-beta02<\/code>, so you\u2019ll have to make sure all your dependencies are up to date!\n<\/p>\n<h3>TwoPane properties<\/h3>\n<p>\n  To use the TwoPane component in your Compose apps,  you need to pass Composable content to the <code>first<\/code> and <code>second<\/code> slots, as well as specify a <code>TwoPaneStrategy<\/code> and a list of <code>displayFeatures<\/code>. There are also other option properties, including a <code>Modifier<\/code> and a <code>FoldAwareConfiguration<\/code>.\n<\/p>\n<pre>@Composable()\r\n  fun TwoPane(\r\n    first: @Composable() () -&gt; Unit,\r\n    second: @Composable() () -&gt; Unit,\r\n    strategy: TwoPaneStrategy,\r\n    displayFeatures: List&lt;DisplayFeature&gt;,\r\n    modifier: Modifier = Modifier,\r\n    foldAwareConfiguration: FoldAwareConfiguration = FoldAwareConfiguration.AllFolds\r\n)<\/pre>\n<h4>TwoPaneStrategy<\/h4>\n<p>\n  The <code>TwoPaneStrategy<\/code> describes how the content will be placed when no fold is detected; you can choose from either vertical or horizontal arrangement, and then you can also pass in an offset or a ratio that describes how much space each group of content will occupy and a dp value for the size of the gap between each group of content. For example, if I want the <code>first<\/code> content to take up 30% of the screen in a side-by-side arrangement, I would use the following strategy:\n<\/p>\n<pre>HorizontalTwoPaneStrategy(splitFraction = 0.3f)<\/pre>\n<p>If instead I wanted vertical arrangement and the <code>first<\/code> content to always be 300 dp from the bottom of the screen with a gap of 30 dp in between <code>first<\/code> and <code>second<\/code>, I would use this strategy:\n<\/p>\n<pre>VerticalTwoPaneStrategy(splitOffset = 300.dp, offsetFromTop = false, gapHeight = 30.dp)<\/pre>\n<p>\n  <img decoding=\"async\" width=\"800\" height=\"571\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/animation-of-a-the-twopane-widget-on-a-single-scre.gif\" class=\"wp-image-2779\" alt=\"Animation of a the TwoPane widget on a single screen, dynamically changing the split fraction\" \/>\n<br\/><em>Figure 2. Animation of how TwoPaneStrategy split fraction can affect content layout.<\/em>\n<\/p>\n<h4>Display features<\/h4>\n<p>\n  The Adaptive library provides a handy utility function that will extract the list of display features from your activity using Jetpack Window Manager, so all you need to pass into your TwoPane component is the following:\n<\/p>\n<pre>displayFeatures = calculateDisplayFeatures(activity = this@MainActivity)<\/pre>\n<h4>FoldAwareConfiguration<\/h4>\n<p>\n  The optional <code>FoldAwareConfiguration<\/code> parameter can be used like the <a href=\"https:\/\/learn.microsoft.com\/dual-screen\/android\/jetpack\/compose\/two-pane-layout#pane-mode\">PaneMode<\/a> from our TwoPaneLayout component, as it lets you control when a fold affects your layout. The configuration can be set to <code>FoldAwareConfiguration.AllFolds<\/code>, <code>FoldAwareConfiguration.HorizontalFoldsOnly<\/code>, or <code>FoldAwareConfiguration.VerticalFoldsOnly<\/code>.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"800\" height=\"571\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/animation-of-the-twopane-sample-spanned-across-bot.gif\" class=\"wp-image-2780\" alt=\"Animation of the TwoPane sample spanned across both screens of a Surface Duo, changing the configuration options and observing the different possible layouts.\" \/>\n<br\/><em>Figure 3. Animation of how the different fold aware configurations affect content layout.<\/em>\n<\/p>\n<h2>TwoPane sample<\/h2>\n<p>\n  To help ourselves understand the library better and the different configuration options, we created a simple <a href=\"https:\/\/github.com\/khalp\/two-pane-sample\">TwoPane sample<\/a>!\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"1200\" height=\"851\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/word-image-2777-4.png\" class=\"wp-image-2781\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/word-image-2777-4.png 1200w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/word-image-2777-4-300x213.png 300w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/word-image-2777-4-1024x726.png 1024w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2022\/09\/word-image-2777-4-768x545.png 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/>\n<br\/><em>Figure 4. Screenshots of the TwoPane sample.<\/em>\n<\/p>\n<p>\n  In the sample, you can change the <code>TwoPaneStrategy<\/code> and the <code>FoldAwareConfiguration<\/code> to see how it affects the way content is laid out.\n<\/p>\n<p>\n  Whether it\u2019s using Jetpack Window Manger, TwoPane, TwoPaneLayout, or any other custom components, we hope you\u2019re taking advantage of all these great foldable Compose resources to enhance your apps!\n<\/p>\n<h2>Resources and feedback<\/h2>\n<p>\n  You can read more about Jetpack Compose for foldable devices in the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/jetpack\/compose\/\">Surface Duo developer documentation<\/a>. \n<\/p>\n<p>\n  If you have any questions or would like to tell us about your dual-screen applications, use the\u202f<a href=\"http:\/\/aka.ms\/SurfaceDuoSDK-Feedback\" target=\"_blank\" rel=\"noopener\">feedback forum<\/a>\u202for message us on Twitter\u202f<a href=\"https:\/\/twitter.com\/surfaceduodev\" target=\"_blank\" rel=\"noopener\">@surfaceduodev<\/a>.\u202f\u00a0\n<\/p>\n<p>\n  Finally, please join us every Friday on\u202f<a href=\"https:\/\/twitch.tv\/surfaceduodev\" target=\"_blank\" rel=\"noopener\">Twitch<\/a>\u202fat 11am Pacific time to chat about Surface Duo developer topics!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Compose developers! This week, we\u2019d like to talk about the TwoPane layout from Google\u2019s Accompanist Adaptive library! Not to be confused with our own Microsoft Compose SDK TwoPaneLayout component, TwoPane from Accompanist is a fold-aware UI component that works great for cases when you always want to show two pieces of content. Accompanist libraries [&hellip;]<\/p>\n","protected":false},"author":72597,"featured_media":2781,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[692,706,473],"class_list":["post-2777","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-jetpack-compose","tag-jetpack-window-manager","tag-kotlin"],"acf":[],"blog_post_summary":"<p>Hello Compose developers! This week, we\u2019d like to talk about the TwoPane layout from Google\u2019s Accompanist Adaptive library! Not to be confused with our own Microsoft Compose SDK TwoPaneLayout component, TwoPane from Accompanist is a fold-aware UI component that works great for cases when you always want to show two pieces of content. Accompanist libraries [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2777","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/users\/72597"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=2777"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/2777\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/2781"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=2777"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=2777"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=2777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}