You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android纯代码实现下如何高效处理屏幕方向等配置变更

高效处理Android配置变更的方案

针对纯代码编写的Android布局(非Jetpack Compose),推荐采用Android官方首选的「让系统自动重建组件+资源适配」方案,替代手动修改onConfigurationChanged的繁琐逻辑,具体实现方式如下:


方案1:利用资源限定符自动适配布局逻辑

通过Android资源系统的限定符(如land、sw600dp等),在不同配置下加载不同的布局参数,代码无需手动判断配置类型,由系统自动匹配资源。

步骤示例:

  1. 定义自定义布局属性
    在res/values/attrs.xml中创建用于控制布局的属性:

    <declare-styleable name="OrientationLayoutConfig">
        <attr name="editTextWidth" format="dimension" />
        <attr name="editTextAlignRule" format="integer" />
        <attr name="buttonRelativeRule" format="integer" />
    </declare-styleable>
    
  2. 分配置编写资源

    • 竖屏配置(res/values/styles.xml):
      <style name="LayoutStyle">
          <item name="editTextWidth">match_parent</item>
          <item name="editTextAlignRule">@integer/rule_align_parent_top</item>
          <item name="buttonRelativeRule">@integer/rule_below_edittext</item>
      </style>
      
    • 横屏配置(res/values-land/styles.xml):
      <style name="LayoutStyle">
          <item name="editTextWidth">180dp</item>
          <item name="editTextAlignRule">@integer/rule_align_parent_left</item>
          <item name="buttonRelativeRule">@integer/rule_to_right_of_edittext</item>
      </style>
      

    (注:需在res/values/integers.xml中定义对应规则常量,如rule_align_parent_top对应RelativeLayout.ALIGN_PARENT_TOP的整数值)

  3. 代码中读取资源并构建布局

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(buildLayout())
    }
    
    private fun buildLayout(): View {
        val attrs = obtainStyledAttributes(R.style.LayoutStyle, R.styleable.OrientationLayoutConfig)
        
        // 从资源中读取布局参数
        val editTextWidth = attrs.getDimensionPixelSize(
            R.styleable.OrientationLayoutConfig_editTextWidth,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
        val editTextAlignRule = attrs.getInt(
            R.styleable.OrientationLayoutConfig_editTextAlignRule,
            RelativeLayout.ALIGN_PARENT_TOP
        )
        val buttonRelativeRule = attrs.getInt(
            R.styleable.OrientationLayoutConfig_buttonRelativeRule,
            RelativeLayout.BELOW
        )
        attrs.recycle()
    
        // 创建EditText
        val editText = EditText(this).apply {
            id = R.id.et_input // 设置唯一ID,让系统自动保存输入状态
            layoutParams = RelativeLayout.LayoutParams(editTextWidth, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
                addRule(editTextAlignRule)
            }
        }
    
        // 创建Button
        val button = Button(this).apply {
            text = "提交"
            layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
                addRule(buttonRelativeRule, editText.id)
                // 根据规则补充额外布局属性
                if (buttonRelativeRule == RelativeLayout.BELOW) {
                    addRule(RelativeLayout.ALIGN_PARENT_LEFT)
                } else {
                    addRule(RelativeLayout.CENTER_VERTICAL)
                    marginStart = 16.dpToPx()
                }
            }
        }
    
        // 构建根布局
        return RelativeLayout(this).apply {
            addView(editText)
            addView(button)
        }
    }
    
    // 扩展函数:dp转px
    private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).toInt()
    

方案2:拆分布局创建逻辑,根据配置自动调用

将不同配置下的布局创建逻辑拆分为独立方法,在组件创建时根据当前配置自动选择执行,系统重建时会自动适配新配置。

代码示例:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(createLayoutByOrientation())
}

private fun createLayoutByOrientation(): View {
    return if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        createLandscapeLayout()
    } else {
        createPortraitLayout()
    }
}

// 竖屏布局逻辑
private fun createPortraitLayout(): View {
    val editText = EditText(this).apply {
        id = R.id.et_input
        layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
            addRule(RelativeLayout.ALIGN_PARENT_TOP)
            setMargins(16.dpToPx(), 16.dpToPx(), 16.dpToPx(), 0)
        }
    }

    val button = Button(this).apply {
        text = "提交"
        layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
            addRule(RelativeLayout.BELOW, editText.id)
            addRule(RelativeLayout.ALIGN_PARENT_LEFT)
            setMargins(16.dpToPx(), 16.dpToPx(), 0, 0)
        }
    }

    return RelativeLayout(this).apply { addView(editText); addView(button) }
}

// 横屏布局逻辑
private fun createLandscapeLayout(): View {
    val editText = EditText(this).apply {
        id = R.id.et_input
        layoutParams = RelativeLayout.LayoutParams(200.dpToPx(), ViewGroup.LayoutParams.WRAP_CONTENT).apply {
            addRule(RelativeLayout.ALIGN_PARENT_LEFT)
            addRule(RelativeLayout.CENTER_VERTICAL)
            setMargins(16.dpToPx(), 0, 0, 0)
        }
    }

    val button = Button(this).apply {
        text = "提交"
        layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
            addRule(RelativeLayout.TO_RIGHT_OF, editText.id)
            addRule(RelativeLayout.CENTER_VERTICAL)
            setMargins(16.dpToPx(), 0, 0, 0)
        }
    }

    return RelativeLayout(this).apply { addView(editText); addView(button) }
}

private fun Int.dpToPx(): Int = (this * resources.displayMetrics.density).toInt()

关键注意点:状态自动恢复

  • 所有需要保留状态的View(如EditText)必须设置唯一ID,系统会自动保存其输入内容、选中状态等。
  • 若有自定义状态(如按钮点击计数),可通过重写onSaveInstanceState和onRestoreInstanceState实现:
    private var clickCount = 0
    
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("click_count", clickCount)
    }
    
    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        clickCount = savedInstanceState.getInt("click_count", 0)
    }
    

内容的提问来源于stack exchange,提问作者Jatin guglani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 23:08:33