Android折叠屏开发学习(二)---使用Jetpack WindowManager监听折叠屏开合状态

本文主要是介绍Android折叠屏开发学习(二)---使用Jetpack WindowManager监听折叠屏开合状态,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

学更好的别人,

做更好的自己。

——《微卡智享》

6a356ae28ff79cb1ab882a863753da2f.png

本文长度为4521,预计阅读8分钟

前言

上一篇《Android折叠屏开发学习(一)---通过传感器获取铰链角度》使用了传感器获取折叠屏打开的角度。而在2021 Google I/O,发布了Jetpack WindowManager 用于进行折叠屏适配,今天这篇我们就来使用一下Jetpack WindowManager来做个折叠屏的Demo

81d7024d09b7ab029bf00c8405b5a9c6.png

实现效果

19b26dca14e043c34e921893af25e3a9.gif

b75363a043136fbd30ad2d2ac9420555.png

微卡智享

WindowManager

Jetpack WindowManager 是一个以Kotlin 优先的现代化库,它支持不同形态的新设备,并提供 “类 AppCompat” 的功能以构建具有响应式 UI 的应用。

通过WindowManager API中WindowInfoTracker来获取折叠屏的状态,其中WindowLayoutInfo获取的信息包含了窗口的显示特性,例如该窗口是否可折叠或包含铰链,在WindowLayoutInfo中可以得到FoldingFeature,让您能够监听可折叠设备的折叠状态得以判断设备的姿态。

FoldingFeature中几个关键的项:

  • state 折叠特征的角度(HALF_OPENED 或 FLAT)

  • orientation - 折叠特征的方向(HORIZONTAL 或 VERTICAL)

  • isSeparating - 如果折叠特征将显示区域分隔为两个不同的部分

其中isSeparating属性对于双屏设备,当应用跨铰链时,这始终为 true;对于其他可折叠设备,仅当状态是 HALF_OPENED 时(例如设备处于桌面状态时)这个为 true。所以我们可以定义同个函数在显示当前的状态。

fun isTableTopPosture(foldFeature: FoldingFeature?): Boolean {return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL}fun isBookPosture(foldFeature: FoldingFeature?): Boolean {return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&foldFeature.orientation == FoldingFeature.Orientation.VERTICAL}fun isSeparating(foldFeature: FoldingFeature?): Boolean {return foldFeature?.state == FoldingFeature.State.FLAT && foldFeature.isSeparating}

对应的状态图如下:

ff5b4265c5aa31a0808640c84797c4d2.png

代码实现

0f526565da51817e1d5d00df3abd601c.png

微卡智享

01

build.gradle依赖

Demo还是接着我们的MVI的Demo,首先就是加入依赖项。

dependencies {implementation "androidx.window:window:1.0.0"implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
}

这里windowmanager我用的是1.0稳定版,当前已经到了1.1.0-alpha02了,当然监听还是用到了lifecycle及协程,所以也加进来,我的项目依赖项如下图:

32a891b202c0b0225c69c00bb9e871df.png

02

布局文件

创建了一个新的Activity,其中布局文件只有一个图片(ImageView)和一个文本(TextView)。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="50dp"tools:context=".ui.view.WindowInfoTrackerActivity"><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:id="@+id/imv_view" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/tv_imgstatus"app:layout_constraintTop_toBottomOf="@id/imv_view"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:textSize="13pt"android:text="111" /></androidx.constraintlayout.widget.ConstraintLayout>

图片资源就是上图里面四个图片的状态,文件直接复制到drawable中了。

80890bfd970cd1a829c4dd925ca547e4.png

03

Activity代码

新建的Activity中,创建WindowInfoTracker和Flow<WindowLayoutInfo>的变量。

4ef5c98526fff75367fb8fac2379733a.png

class WindowInfoTrackerActivity : AppCompatActivity() {private lateinit var windowInfoTracker : WindowInfoTrackerprivate lateinit var windowLayoutInfoFlow : Flow<WindowLayoutInfo>

在OnCreate中初始化变量和监听

d1fc954e95a0ae84e9c7a5a143e6766d.png

private fun observeFold() {lifecycleScope.launch(Dispatchers.Main) {lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {windowLayoutInfoFlow.collect { layoutInfo ->Log.i(TAG, "size:${layoutInfo.displayFeatures.size}")val foldingFeature = layoutInfo.displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull()foldingFeature?.let {Log.i(TAG, "state:${it.state}")}when {isTableTopPosture(foldingFeature) ->sendInfoMsg("横向半开")isBookPosture(foldingFeature) ->sendInfoMsg("竖向半开")isSeparating(foldingFeature) ->// Dual-screen devicefoldingFeature?.let {if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {sendInfoMsg("横向全展开")} else {sendInfoMsg("竖向全展开")}}else -> {sendInfoMsg("主屏")}}}}}}

监听就是通过LifeCycle获取到windowLayoutInfo信息,然后提取FoldingFeature,通过判断FoldingFeature的当前状态.

代码中可以看到判断FoldingFeature的状态后使用sendInfoMsg发送消息,是用协程直接给VIewModel发送消息。

6c02c70383c80fbb7b6824eb2a3c0a59.png

使用MVI架构更新UI

《Android MVI架构初探》文章中介绍了MVI的架构,本文的Demo也是在这个基础上做的,所以实现更新UI,下图中是当时我们MVI架构的示意图,我们重新看一下怎么处理的。

e5ef8dc5d0e8537579565e1ee79c15da.png

ActionIntent和ActionState增加Info项

ec1b8b1230b492db16953ad082125969.png

21a276c97bcac628699cd4be9f3a8dd1.png

ViewModel中的处理

72ab05ff3e9d401e399c622e4c0a5a76.png

ViewModel中接收到Intent的消息后,直接再往State中进行推送。

Activity中ViewModel的监听

5445b7bb1a2a4e1bba12e01ec452be32.png

在Activity的OnCreate中开启ViewModel的监听

54ef527400b4ae4f6e961ff4a0630891.png

接收到ActionState.Info后直接调用setControlShow来更新UI显示

7bc2ca77195aa3bec5c062565c5a1593.png

setControlShow中更新TextView显示当前的状态,并根据状态更换显示的图片。这样我们的Demo就完成了。

a7c9878ad9dcc2ca94ea352abeac4056.png

微卡智享

划重点

文章中可以看到,我用的虚拟机进行的测试,最主要的原因是使用WindowManager获取折叠屏当前状态,在Android 11下完全正常,但是在Android 12中就不好用了,我的真机是Android 12就完全没反应,后来创建了一个Android 12的虚拟机也是如此,代码其实挺简单,但是这个问题倒是卡了我好几天,后来又下的WindowManager的官方Demo也算比较旧的了,用了官方Demo试过,也是一样的,在Android 12下用不了。如果有知道怎么解决的朋友麻烦留言告之一下。

P2为当前程序运行的实现效果视频。下一篇将使用MotionLayout来实现折叠屏不同状态的不同布局效果,代码还是在这个项目中,会再增加一个Activity实现。

源码地址

https://github.com/Vaccae/AndroidMVIDemo.git

点击阅读原文可以看到“码云”的地址

567f37c0e76b32a23f152148b97847d4.png

a7fa1ac75adab443a7f092a3807a5f67.png

往期精彩回顾

 

86c0a20249892b18c54e95a4c8f8edad.png

Android折叠屏开发学习(一)---通过传感器获取铰链角度

 

 

041ae31970e2ed7fd5cb23983a40999d.png

Android MVI架构初探

 

 

a6e2d84c9089b56bf0a11b12d7a10a2d.png

Android Kotlin协程间的通信Channel介绍

 

这篇关于Android折叠屏开发学习(二)---使用Jetpack WindowManager监听折叠屏开合状态的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/493664

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没