美文网首页
Android10 屏幕方向适配

Android10 屏幕方向适配

作者: ZuYuan | 来源:发表于2020-08-13 11:39 被阅读0次

    问题

    假如项目突然有一个支持pad的需求,需要将所有的页面都支持横屏,该怎么做?
    常见方案:

    • 将manifest的中活动的screenOrientation属性都固定为unspecified,问题就是手动修改十分麻烦,且项目本身是增量编译的情况下,必须使用耗时的全量编译才行;
    • 使用BaseActivity或者ActivityLifecycleCallbacks中动态去设置(kotlin):
      requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
      问题在于这种方式在Android10上有问题,横屏跳转到下一个活动,手机会先竖屏展示,然后再自动切成横屏,也就是“跳一下”。

    问题解决

    目标一:自动化修改manifest文件,使其支持增量编译

    思路:在Gradle构建APK的过程中,在总的manifest文件生成(每个Module的manifest文件自动合并后)之后,将所有的screenOrientation都改动成unspecified,这样不管在哪种编译模式下都能将所有页面都改动到:

    //在app下的build.gradle文件末尾中添加
    //此处是kts脚本,换成groovy脚本照着抄就行,大同小异
    //将所有的竖屏修改为unspecified,为了测试,临时把代码放在这里
    
    //项目构建之后
    project.afterEvaluate {
        //获取输入,包含了资源输入和manifest输入(输入-transform-输出)
        //其实也可以自己对 process[XXX]Manifest 相关的几个task直接操作
        android.applicationVariants.forEach { variant->
            variant.outputs.forEach { output ->
                val manifestTask = output.processManifestProvider.orNull
                if (manifestTask != null) {
                    doLastReplaceManifest(manifestTask)
                } else {
                    val taskName = output.processManifestProvider.name
                    project.tasks.whenTaskAdded(object : Action<Task> {
                        override fun execute(t: Task) {
                            if (t.name == taskName) {
                                doLastReplaceManifest(output.processManifestProvider.get())
                            }
                        }
                    })
                }
            }
        }
    }
    
    fun doLastReplaceManifest(task: com.android.build.gradle.tasks.ManifestProcessorTask) {
        task.doLast {
            val startTime = System.currentTimeMillis()
            val manifestPath = "${task.manifestOutputDirectory.get().asFile.absolutePath}/AndroidManifest.xml"
            val file = file(manifestPath)
            if (!file.exists()) {
                println("not find manifest file, path=${file.absolutePath}")
                return@doLast
            }
            val str = file.readText()
            file.setWritable(true)
            file.writeText(str.replace(
                    "screenOrientation=\"portrait\"",
                    "screenOrientation=\"unspecified\""
            ))
            println("replace portrait to unspecified, spent ${System.currentTimeMillis() - startTime}ms")
        }
    }
    

    其实方案一有一个问题就是,当需要动态改变屏幕方向的时候就还是会“跳一下”。
    例如在上面的基础上再加上下面的动态代码(固定为横屏)
    requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE

    目标二:解决安卓10动态修改屏幕方向“跳一下”问题

    在探索时发现,对于一个活动,manifest中它的screenOrientation只是locked的时候,动态去修改屏幕方向,它就不会再“跳一下”。
    举个简单例子:

          //manifest.xml
       <activity android:name=".MainActivity2"
                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                android:screenOrientation="locked">    
    
         //Activity.kt
        override fun onCreate(savedInstanceState: Bundle?) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            super.onCreate(savedInstanceState)
        }
    

    至于自动化的过程,请参照方案一。

    转载请注明出处
    https://www.jianshu.com/p/a4cc34923806

    相关文章

      网友评论

          本文标题:Android10 屏幕方向适配

          本文链接:https://www.haomeiwen.com/subject/xmrbdktx.html