Android基础之屏幕适配

991 阅读4分钟

1. 横竖屏适配

横竖屏适配存在问题

布局问题

  1. 布局文件适配:通过在res下创建布局文件夹,区分横竖屏加载不同的布局文件,布局文件名需保持一致
  • layout-land:横屏layout
  • layout-port:竖屏layout
  1. 代码适配:可使用resources.configuration.orientation获取横竖屏状态,默认情况下横竖屏切换会重走Activity#onCreate(),可在此判断加载不同的layout文件
  • Configuration.ORIENTATION_LANDSCAPE:横屏
  • Configuration.ORIENTATION_PORTRAIT:竖屏
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    when (resources.configuration.orientation) {
        Configuration.ORIENTATION_LANDSCAPE -> {
            // 横屏
            setContentView(R.layout.layout_landscape)
        }
            
        else -> {
            // 默认加载竖屏
            setContentView(R.layout.layout_portrait)
        }
    }
}

重新加载问题

  1. 在布局问题的第2点中有提到,默认情况下横竖屏切换会重走Activity#onCreate(),可在其中加载不同的布局文件,若需保存切换前的页面状态数据,还需做数据保存恢复处理
/**
 * 恢复数据,回调此方法savedInstanceState一定不为空
 *
 * 调用时机:
 *  1. 横竖屏切换时
 *  2. 异常被杀时(例:内存不足时)
 */
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)
    val state = savedInstanceState.getString("")
    ...
}

/**
 * 可做保存数据操作,用于恢复之前状态
 *
 * 调用时机:
 *  1. 按下Home键时
 *  2. 横竖屏切换时
 *
 * 当前主流系统版本此方法回调时机在onStop()之后
 */
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putString("", "")
    ...
}
  1. AndroidManifest.xml中加入android:configChanges配置,可改变其生命周期回调
  • android:configChanges:若未指定,系统中发生这些配置的更改,Activity都会重新启动,配置后只会回调Activity#onConfigurationChanged

例:android:configChanges="orientation|keyboardHidden"

  • android:configChanges="orientation":横竖屏旋转
  • android:configChanges="keyboardHidden":键盘显示与隐藏
  • android:configChanges="keyboard":键盘变更(例:12键变全键盘)
  • android:configChanges="fontScale":字体变更
  • android:configChanges="locale":语言变更
  • android:configChanges="touchscreen|navigation":触摸屏或导航方式变更

可在Activity#onConfigurationChanged中监测横竖屏状态或键盘状态做额外逻辑处理

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)

    when (newConfig.orientation) {
        Configuration.ORIENTATION_PORTRAIT -> {
            // 竖屏
        }
            
        Configuration.ORIENTATION_LANDSCAPE -> {
            // 横屏
        }
    }

    when (newConfig.hardKeyboardHidden) {
        Configuration.HARDKEYBOARDHIDDEN_NO -> {
            // 实体键盘弹出
        }
            
        Configuration.HARDKEYBOARDHIDDEN_YES-> {
            // 实体键盘隐藏
        }
    }
}
android:configChanges补充

未设置时,横竖屏切换会重走各生命周期,切横屏执行一次,切竖屏执行两次 仅设置值为orientation时,切屏还是会重走生命周期,切横、竖屏只会执行一次 设置值为orientation|keyboardHidden时,切屏不会重走各生命周期,只会执行onConfigurationChanged()

  1. AndroidManifest.xml中加入android:screenOrientation配置,可强制屏幕状态
  • android:screenOrientation="portrait":强制竖屏
  • android:screenOrientation="landscape":强制横屏
  • android:screenOrientation="unspecified":默认值,系统判断,自动切换
  • android:screenOrientation="user":当前用户设置的横竖屏状态
  • android:screenOrientation="behind":与前一个显示的Activity方向一致
  • android:screenOrientation="sensor":使用传感器的方向
  • android:screenOrientation="nosensor":忽略传感器方向(例忽略重力感)

代码设置强制屏幕状态

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 强制横屏
    requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE

    setContentView(view)
    ...
}

2. 屏幕尺寸适配

安卓设备种类繁多,小到智能手表,大到智能手机、平板电脑,甚至电视,屏幕尺寸千差万别,要做到适配所有机型,实属不易!!!

此处只介绍几款手机的适配方案,其他类似

layout适配

手机屏幕大小不一,480320、640360、800*480...,要做到各屏幕其实很简单,只需在res下创建不同layout文件夹即可,系统会加载合适的layout

  • layout-640*360:640*360
  • layout-800*480:800*480
  • layout-land-800*480:横屏布局800*480
  • layout-small:480dp*320dp
  • layout-large:640dp*480dp
  • layout-xlarge:960dp*720dp

drawable适配

系统会根据分辨率加载合适的图片

  • drawable:默认
  • drawable-ldpi:低密度图片(0dpi~120dpi)
  • drawable-mdpi:中等密度图片(120dpi~160dpi)
  • drawable-hdpi:高密度图片(160dpi~240dpi)
  • drawable-xhdpi:超高密度图片(240dpi~320dpi)
  • drawable-xxhdpi:超超高密度图片(320dpi~480dpi)
  • drawable-xxxhdpi:超超超高密度图片(480dpi~640dpi)
  • drawable-nohdpi:无缩放

android_dpi.png

dimen适配

  • values-sw320dp/dimens.xml(320dp 宽设备)
<dimen name="button_width">120dp</dimen>
<dimen name="margin_common">8dp</dimen>
<dimen name="text_size">14sp</dimen>
  • values-sw480dp/dimens.xml(480dp 宽设备)
<dimen name="button_width">160dp</dimen>
<dimen name="margin_common">12dp</dimen>
<dimen name="text_size">16sp</dimen>