Surface Duo双屏设备在实践中如何工作

Surface DUO is the most exciting device I’ve seen in years. Built by Microsoft, it will run Android on a dual-screen setup which allows for apps to run side by side or extended, using both screens.

小号 urface DUO是我多年来看到的最令人兴奋的设备。 它由Microsoft构建,将在双屏设置上运行Android,该设置允许应用同时在两个屏幕上并排运行或扩展运行。

In this article, I want to take a look at what do we need to build a Master/Detail app for dual-screen devices.

在本文中,我想看看为双屏设备构建Master / Detail应用程序需要做什么。

To prepare the post, I’ve rewritten from scratch this Master/Detail sample provided by Microsoft to help me better understand the Surface Duo and to:

为了准备该帖子,我从头开始重写了Microsoft提供的Master / Detail示例,以帮助我更好地了解Surface Duo,并:

  • Reduce the number of fragments used in the sample and (hopefully) make it easier to understand.

    减少样品中使用的碎片数量,并(希望)使其更易于理解。
  • Explore how ViewModel & LiveDatacan be used in dual-screen setups.

    探索如何在双屏设置中使用ViewModelLiveData

  • Add support for Portrait Dual Mode, which the original sample didn’t have.

    添加对肖像双模式的支持,而原始示例则​​没有。

Here’s a link to the repository if you rather jump directly into the code:

如果您直接跳转到代码中,这是到存储库的链接:

注意铰链 (Mind the hinge)

Image for post

A dual-screen device is more than a tablet, we can’t just rely on the app’s landscape layouts to provide the best experience for our users.

双屏设备不仅仅是平板电脑,我们不能仅仅依靠应用程序的横向布局为用户提供最佳体验。

The hinge has a visual and conceptual impact. Having that separation in the middle of the screen forces us to organise our content differently. Our landscape layouts can’t just be a wider portrait with the content aligned in the middle, otherwise, the hinge will cover part of it:

铰链具有视觉和概念上的影响 。 屏幕中间的分隔迫使我们以不同的方式组织内容。 我们的景观布局不能只是将内容对齐在中间的宽阔肖像,否则,铰链将覆盖其中的一部分:

Image for post
See more at https://docs.microsoft.com/en-us/dual-screen/introduction#how-to-work-with-the-seam
请参阅 https://docs.microsoft.com/zh-cn/dual-screen/introduction#how-to-work-with-the-seam

We need to design our layouts having the hinge in mind. We’ll see that there are functions in the Surface Duo SDK to detect if there’s a hinge and where.

我们需要在设计布局时考虑到铰链。 我们将看到Surface Duo SDK中提供了一些功能来检测是否有铰链以及在何处。

There’s also the conceptual implications. Arranging content around the hinge is not enough. Its presence makes a clear separation between both screens and the user will expect the content on them to have different responsibilities. In this case, we’ll explore the Master/Detail concept but there are many more options: Two pages, Companion, Dual view, etc.

还有概念上的含义。 仅在铰链周围布置内容是不够的。 它的存在使两个屏幕之间清晰地分开,并且用户希望它们上的内容具有不同的职责。 在这种情况下,我们将探讨“主/详细”概念,但还有更多选项 :两页,同伴,双重视图等。

掌握/细节:我们需要什么 (Master/Detail: what we need)

Image for post

A Surface Duo device can be in either portrait or landscape and for each one of those rotations our app can be displayed in single mode or dual mode. That’s four options but, as we’ll see, only three different layouts will be needed to cover all of them.

Surface Duo设备可以是纵向或横向模式,对于这些旋转中的每一个旋转,我们的应用程序都可以单模式或双模式显示。 这是四个选项,但是,正如我们将看到的那样,将只需要三个不同的布局即可覆盖所有这些。

What we need:

我们需要的:

  • ListFragment to display the list of Item

    ListFragment显示Item列表

  • DetailsFragment to display one simple Item

    显示一个简单Item DetailsFragment

  • MainActivity to hold both fragments (either in Single Mode or Dual Mode)

    MainActivity可以容纳两个片段(在单模式或双模式下)

  • MainViewModel to hold the view logic and serve as a communication bridge between fragments

    MainViewModel保留视图逻辑并充当片段之间的通信桥梁

Image for post
Image for post
Image for post
Landscape — Mode: Single, Single, Dual 横向 —模式:单,单,双
Image for post
Image for post
Image for post
Portrait — Mode: Single, Single, Dual 纵向 —模式:单,单,双

双模式是棘手的位。 (Dual Mode is the tricky bit.)

In Single Mode, we only need to display one fragment at a time, but in Dual Mode our app needs to display both ListFragment and DetailsFragment together.Here’s when things become interesting. Single Mode only cares about one screen, so for both portrait and landscape we can get away with just one layout if we design it to work well in both orientations. But Dual Mode in portrait needs to arrange things from top to bottom and, in landscape, from left to right. This means we need three different layouts for MainActivity:

在单模式下,我们一次只需要显示一个片段,但是在双模式下,我们的应用程序需要同时显示ListFragmentDetailsFragment 。 “单模式”只关心一个屏幕,因此对于纵向和横向而言,如果我们将其设计为在两种方向都可以正常工作,则可以仅采用一种布局。 但是,肖像双模式需要从上到下,从横向到从左到右排列事物。 这意味着MainActivity需要三种不同的布局

  • Layout 1: Single Mode. This is the one we’re used to, with space for one single fragment and used both in portrait and landscape

    布局1:单模式 。 这是我们习惯使用的空间,只有一个片段的空间,同时用于纵向和横向

  • Layout 2: Dual Mode Portrait: With space for two fragments and a gap for the hinge, organised vertically

    布局2:双模式人像垂直排列 ,有两个碎片的空间和铰链的间隙

  • Layout 3: Dual Mode Landscape: With space for two fragments and a gap for the hinge, organised horizontally

    布局3:双模式景观 :随着对两个片段的空间和用于铰链的间隙,组织水平

Image for post
Image for post
Image for post
Layout 1 (Single Mode, any orientation) — Layout 2 (Dual Mode, portrait) — Layout 3 (Dual Mode, landscape)
布局1(单模式,任何方向)—布局2(双模式,纵向)—布局3(双模式,横向)

以编程方式设置布局 (Setting layouts programmatically)

Every time there’s a configuration change in our app we need to decide which one of those three layouts needs to be set.

每当我们的应用程序中发生配置更改时,我们都需要确定需要设置这三种布局中的哪一种。

Layouts 2 and 3 are the same layout in a different orientation so we can rely on Android’s native resource by orientation support for this.

布局2和布局3是相同的布局,但方向不同,因此我们可以通过方向支持来依靠Android的本机资源。

Resources tree with alternative landscape and portrait layouts for the Main Activity

In our ActivityonConfigurationChange we can have something like this:

在我们的活动onConfigurationChange我们可以像这样:

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val layoutId = when {
isDuoDeviceInDualMode() -> R.layout.main_activity_dual_modeelse -> R.layout.main_activity_single_mode}
setContentView(layoutId)
}

Android will take care of orientation resource provisioning, giving us the correct R.layout.main_activity_dual_mode layout for portrait or landscape.

Android将负责定向资源的配置,为我们提供纵向或横向的正确R.layout.main_activity_dual_mode布局。

Once we have the correct layout set, it’s a matter of displaying the correct fragment (or fragments) in the correct buckets.

一旦我们设置了正确的布局,就可以在正确的存储桶中显示正确的片段。

Image for post

Surface DUO SDK (Surface DUO SDK)

The Duo SDK is not required to build an app able to run in the Surface Duo, but it provides some utilities to make the experience better for the user.

不需要Duo SDK来构建能够在Surface Duo上运行的应用程序,但是它提供了一些实用程序,可以为用户带来更好的体验。

该应用程序是否在Surface Duo设备中运行? (Is the app running in a Surface Duo Device?)

DisplayMask: Represents the area of the display that is not functional for displaying content.

DisplayMask :表示显示器上不能用于显示内容的区域。

If we can create a DisplayMask then the app is running in a Duo Device. We can use this snippet to determine whether our app is running on a Duo Device. We should check this before setting the activity layout.

如果我们可以创建DisplayMask则该应用程序将在Duo设备中运行。 我们可以使用此代码段确定我们的应用程序是否在Duo设备上运行。 在设置活动布局之前,我们应该检查一下。

fun isDuoDevice(context: Context): Boolean {
return try {DisplayMask.fromResourcesRectApproximation(context) != null
} catch (ex: Exception) {
false
}
}

单模还是双模? (Single or Dual Mode?)

DisplayMask.getBoundingRectsForRotation(int rotation) Returns a list of Rects with respect to the rotation, each of which is the bounding rectangle for a non-functional area on the display.

DisplayMask.getBoundingRectsForRotation(int rotation)返回相对于旋转的Rect列表,每个列表都是显示器上非功能区域的边界矩形。

An app is in Dual Mode when it’s presented across both screens. In that case, the hinge will intersect our app window. We can use DisplayMask.getBoundingRectsForRotation() to obtain the hinge Rect and check if it intersects our app window’s Rect

在两个屏幕上同时显示的应用程序处于双模式。 在这种情况下,铰链将与我们的应用程序窗口相交。 我们可以使用DisplayMask.getBoundingRectsForRotation()获取铰链Rect并检查它是否与我们应用窗口的Rect相交

fun isDualMode(): Boolean {
val hinge: Rect = getHinge(rotation)
val windowRect: Rect = getWindowRect()
if (windowRect.width() > 0 && windowRect.height() > 0) {
return hinge.intersect(windowRect)
} else {
return false
}
}private fun getHinge(rotation: Int): Rect {
return displayMask
.getBoundingRectsForRotation(rotation)

.let { boundings -> boundings[0] }}

更多资源 (More resources)

This is only a quick look at what the Surface Duo can offer. I’m looking forward to being able to experiment further with the SDK and excited to find out what new experiences will dual-screen devices bring to the Android ecosystem. Ping me on Twitter if you want to chat more about it, I’d love to hear your thoughts!

这只是对Surface Duo可以提供的功能的快速浏览。 我期待能够进一步试验SDK,并很高兴发现双屏设备将为Android生态系统带来哪些新体验。 如果您想在Twitter上与我聊天,请与我联系,我很想听听您的想法!

Thanks to Cesar Valiente and pablisco for their feedback and help on this post 🙌

感谢Cesar Valientepablisco对本文的反馈和帮助🙌

翻译自: https://medium.com/swlh/surface-duo-how-dual-screen-devices-work-in-practice-5b8057b88376

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值