{"id":1023,"date":"2020-11-05T12:27:54","date_gmt":"2020-11-05T20:27:54","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/surface-duo\/?p=1023"},"modified":"2020-11-05T12:27:54","modified_gmt":"2020-11-05T20:27:54","slug":"dual-screen-list-detail-navigation","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/surface-duo\/dual-screen-list-detail-navigation\/","title":{"rendered":"Dual-screen list-detail with navigation"},"content":{"rendered":"<p>\n  Hello Kotlin and Java developers!\n<\/p>\n<p>\n  When you\u2019re enhancing your existing Android apps for the Microsoft Surface Duo, you may want to keep your existing single-screen behavior. In today\u2019s blog, I\u2019ll share an <a href=\"https:\/\/github.com\/CesarValiente\/list-detail-variant\">example list-detail<\/a> that supports the traditional back-button behavior in a single screen, but shows the list and detail side-by-side when the app is spanned across two screens.\n<\/p>\n<h2>Single screen navigation<\/h2>\n<p>\n  The expected list-detail user experience on a single screen is for a list view to be replaced by the detail when an item is selected. A back arrow appears in the navigation bar, and the back gesture is supported to return to the list view. \n<\/p>\n<p>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image.png\" class=\"wp-image-1024\" width=\"250\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image.png 342w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-193x300.png 193w\" sizes=\"(max-width: 342px) 100vw, 342px\" \/>&nbsp;&nbsp;&nbsp;&nbsp;<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-1.png\" class=\"wp-image-1025\" width=\"250\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-1.png 342w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-1-193x300.png 193w\" sizes=\"(max-width: 342px) 100vw, 342px\" \/>\n<br\/><em>Figure 1: Single screen list-detail with back button<\/em>\n<\/p>\n<h2>Spanned list-detail behavior<\/h2>\n<p>\n  When the app is spanned across two screens, the back button isn\u2019t required, but the list should indicate which item is selected.\n<\/p>\n<p>\n  <img decoding=\"async\" width=\"684\" height=\"534\" src=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-2.png\" class=\"wp-image-1026\" srcset=\"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-2.png 684w, https:\/\/devblogs.microsoft.com\/surface-duo\/wp-content\/uploads\/sites\/53\/2020\/11\/word-image-2-300x234.png 300w\" sizes=\"(max-width: 684px) 100vw, 684px\" \/>\n<br\/><em>Figure 2: List-detail spanned across two screens<\/em>\n<\/p>\n<p>\n  When the app is unspanned, it should show the single screen view, with the selected detail view showing and the back-stack set to return to the list view.\n<\/p>\n<h2>List-detail navigation with SurfaceDuoLayout <\/h2>\n<p>\n  If your app already uses fragments to manage individual views, you can add the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/api-reference\/dualscreen-library\/layouts\/surfaceduo-layout\/?WT.mc_id=docs-surfaceduoblog-CesarValiente\">SurfaceDuoLayout<\/a> to your app and implement this navigation by following the <a href=\"https:\/\/github.com\/CesarValiente\/list-detail-variant\">sample on GitHub<\/a>. If your views are still implemented as activities, consider refactoring them into fragments first.\n<\/p>\n<p>\n  Review these six steps shown in the sample app to enable this navigation behavior:\n<\/p>\n<ol>\n<li>\n  In the <strong>AndroidManifest.xml<\/strong>, choose a theme without an action bar:<\/p>\n<pre>android:theme=\"@style\/Theme.AppCompat.Light.NoActionBar\"<\/pre>\n<\/li>\n<li>\n  In <strong>activity_main.xml<\/strong>, add a toolbar and the SurfaceDuoLayout:<\/p>\n<pre>&lt;androidx.appcompat.widget.Toolbar\r\n    android:id=\"@+id\/my_toolbar\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"?attr\/actionBarSize\"\r\n    android:background=\"?attr\/colorPrimary\"\r\n    android:elevation=\"4dp\"\r\n    android:theme=\"@style\/AppTheme\"\r\n    app:popupTheme=\"@style\/ThemeOverlay.AppCompat.Light\" \/>\r\n\r\n&lt;com.microsoft.device.dualscreen.layouts.SurfaceDuoLayout\r\n    android:id=\"@+id\/fragment_container\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\" \/>\r\n<\/pre>\n<\/li>\n<li>\n  The sample application does not handle any configuration changes, so in the <strong>onCreate<\/strong> method, check whether the app is spanned and set the fragments accordingly. It uses the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/api-reference\/dualscreen-library\/core\/screen-helper\/?WT.mc_id=docs-surfaceduoblog-CesarValiente\">ScreenHelper<\/a> class to determine if the app is spanned:<\/p>\n<pre>if (ScreenHelper.isDualMode(this)) {\r\n    supportFragmentManager.beginTransaction()\r\n        .replace(R.id.first_container_id, ListItemsFragment())\r\n        .replace(R.id.second_container_id, DetailFragment(), \"detailFragment\")\r\n        .commit()\r\n}\r\n\/\/when we are in single screen mode and we don't currently show the detail view, \r\n\/\/it means we are in the initial state when the app starts\r\nelse if (supportFragmentManager.findFragmentByTag(\"detailFragment\") == null) {\r\n    supportFragmentManager.beginTransaction()\r\n        .replace(R.id.first_container_id, ListItemsFragment())\r\n        .commit()\r\n    supportFragmentManager.popBackStackImmediate()\r\n} else {\r\n    \/\/when we are back from spanned mode, we want to show the previous detail view\r\n    supportFragmentManager.beginTransaction()\r\n        .replace(R.id.first_container_id, DetailFragment(), \"detailFragment\")\r\n        .addToBackStack(\"detailFragmentBackStack\")\r\n        .commit()\r\n}<\/pre>\n<\/li>\n<li>\n  The list fragment should load and display a list \u2013 the example uses a <strong>RecyclerView<\/strong> and some hardcoded data. It uses a view model to keep track of the selected item index, and when the app is spanned it disables the back arrow:<\/p>\n<pre>if (!ScreenHelper.isDualMode(requireContext())) {\r\n    (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)\r\n}<\/pre>\n<p>\n  This list fragment also declares an <strong>onClickListener<\/strong> for when an item is selected \u2013 when the app is on a single screen, the list fragment is replaced with the detail fragment and the back stack is updated:\n<\/p>\n<pre>if (!ScreenHelper.isDualMode(this)) {\r\n    \/\/We replace this fragment for the detail view when we click on an item and we are in single screen mode\r\n    parentFragmentManager.beginTransaction()\r\n        .replace(R.id.first_container_id, DetailFragment(), \"detailFragment\")\r\n        .addToBackStack(\"detailFragmentBackStack\")\r\n        .commit()\r\n}<\/pre>\n<p>\n  When the app is spanned, the view model updates are observed and updated by the details fragment.\n<\/p>\n<\/li>\n<li>\n  The <strong>ItemsAdapter<\/strong> used by the list detects when the app is spanned, and highlights the selected item:<\/p>\n<pre>if (ScreenHelper.isDualMode(view.context)) {\r\n    changeItemBackground(position, sharedVM.selectedItemPosition.value as Int, layout)\r\n}<\/pre>\n<\/li>\n<li>\n  The detail fragment uses the view model to display the selected item, and detects whether the app is spanned before enabling the back arrow:<\/p>\n<pre>if (!ScreenHelper.isDualMode(requireContext())) {\r\n    (activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)\r\n}<\/pre>\n<\/li>\n<\/ol>\n<p>\n  This approach preserves the expected functionality on single screen devices while providing an enhanced dual-screen experience.\n<\/p>\n<h2>Resources and feedback<\/h2>\n<p>\n  You can find additional documentation on the SurfaceDuoLayout, ScreenHelper, and other useful controls in the <a href=\"https:\/\/docs.microsoft.com\/dual-screen\/android\/api-reference\/dualscreen-library\/layouts\/surfaceduo-layout\/?WT.mc_id=docs-surfaceduoblog-CesarValiente\">dual-screen library<\/a> docs, and browse other <a href=\"https:\/\/docs.microsoft.com\/samples\/browse\/?expanded=surface&#038;products=surface-duo&#038;WT.mc_id=docs-surfaceduoblog-CesarValiente\">Surface Duo code samples<\/a>.\n<\/p>\n<p>\n  If you\u2019re a Xamarin developer, you can find an example similar to this post, but using C# and XAML as part of this <a href=\"https:\/\/docs.microsoft.com\/learn\/modules\/xamarin-forms-dual-screen\/?WT.mc_id=docs-surfaceduoblog-CesarValiente\">Microsoft Learn module<\/a>.\n<\/p>\n<p>\n  We\u2019d love to hear from you! Please leave us feedback or just share your testing tips using our\u00a0<a href=\"http:\/\/aka.ms\/SurfaceDuoSDK-Feedback\" target=\"_blank\" rel=\"noopener noreferrer\">feedback forum<\/a>, or message me on\u00a0<a href=\"https:\/\/twitter.com\/CesarValiente\" target=\"_blank\" rel=\"noopener noreferrer\">Twitter<\/a>\u00a0or\u00a0<a href=\"https:\/\/github.com\/CesarValiente\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello Kotlin and Java developers! When you\u2019re enhancing your existing Android apps for the Microsoft Surface Duo, you may want to keep your existing single-screen behavior. In today\u2019s blog, I\u2019ll share an example list-detail that supports the traditional back-button behavior in a single screen, but shows the list and detail side-by-side when the app is [&hellip;]<\/p>\n","protected":false},"author":30297,"featured_media":1026,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[473,45],"class_list":["post-1023","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-surface-duo-sdk","tag-kotlin","tag-surface-duo-sdk"],"acf":[],"blog_post_summary":"<p>Hello Kotlin and Java developers! When you\u2019re enhancing your existing Android apps for the Microsoft Surface Duo, you may want to keep your existing single-screen behavior. In today\u2019s blog, I\u2019ll share an example list-detail that supports the traditional back-button behavior in a single screen, but shows the list and detail side-by-side when the app is [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/1023","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\/30297"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/comments?post=1023"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/posts\/1023\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media\/1026"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/media?parent=1023"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/categories?post=1023"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/surface-duo\/wp-json\/wp\/v2\/tags?post=1023"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}