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

Kotlin继承android.widget.FrameLayout适配minSdk19遇构造器问题

解决Kotlin继承FrameLayout时的构造器兼容问题

我刚好碰到过类似的情况,升级Kotlin版本后确实会在View构造器的处理上踩一些坑,结合你的需求(兼容API19、放弃@JvmOverloads),给你一个可行的解决方案:

正确的构造器写法

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.widget.FrameLayout

class CustomFrameLayout(
    context: Context,
    attrs: AttributeSet?,
    defStyleAttr: Int
) : FrameLayout(context, attrs, defStyleAttr) {

    // 简化的无参/单参构造器,统一调用主构造器
    constructor(context: Context) : this(context, null, 0)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    // API21+专属的四参数构造器,用@TargetApi避免编译错误,同时调用主构造器
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : this(context, attrs, defStyleAttr) {
        // 在这里添加仅API21+需要执行的逻辑
    }

    init {
        // 现在可以正常访问attrs变量了
        attrs?.let {
            // 示例:解析自定义属性
            val ta = context.obtainStyledAttributes(it, R.styleable.CustomFrameLayout)
            // ... 你的属性处理逻辑
            ta.recycle()
        }
    }
}

针对你遇到的两个问题的解释

  1. init块无法识别attrs:
    之前的写法里,attrs可能只是某个次构造器的局部参数,而主构造器没有包含这个参数。Kotlin的init块是和主构造器绑定的,只能访问主构造器声明的参数。把attrs放到主构造器的参数列表里,init块就能直接访问它了。

  2. 四参数构造器报错“Primary constructor call expected”:
    Kotlin的规则是:如果类声明了主构造器,所有次构造器必须直接或间接调用主构造器(用this(...))。你之前的四参数构造器直接调用了super(...),违反了这个规则,所以报错。上面的写法里,四参数构造器先调用this(context, attrs, defStyleAttr)(主构造器),就解决了这个问题。

如果必须调用父类的四参数构造器

如果你的逻辑确实需要用到FrameLayout的四参数构造器(比如自定义styleRes),可以把主构造器设为private,让次构造器可以直接调用对应的父类构造器:

class CustomFrameLayout private constructor(
    context: Context,
    attrs: AttributeSet?,
    defStyleAttr: Int,
    defStyleRes: Int
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {

    constructor(context: Context) : this(context, null, 0, 0)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : this(context, attrs, defStyleAttr, 0)

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int,
        defStyleRes: Int
    ) : super(context, attrs, defStyleAttr, defStyleRes) {
        // API21+专属逻辑
    }

    init {
        // 依然可以访问attrs,因为主构造器包含它
        attrs?.let {
            // 处理属性逻辑
        }
    }
}

这样既满足了API19的兼容性,又解决了Kotlin构造器的编译问题,同时避开了@JvmOverloads的bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:12:02