Introduce LayoutInflaterFactory
This add the ability touch layout XML instantiates process. And most importantly, we can access AttributeSet, making custom view attribute possible. Some other changes requires this.
This commit is contained in:
parent
fa3ef8a1c1
commit
385853a290
@ -17,6 +17,7 @@ import androidx.navigation.fragment.NavHostFragment
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||||
|
import com.topjohnwu.magisk.ui.inflater.LayoutInflaterFactory
|
||||||
import com.topjohnwu.magisk.ui.theme.Theme
|
import com.topjohnwu.magisk.ui.theme.Theme
|
||||||
|
|
||||||
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||||
@ -44,6 +45,8 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
||||||
|
|
||||||
setTheme(themeRes)
|
setTheme(themeRes)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.inflater
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.InflateException
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.collection.SimpleArrayMap
|
||||||
|
import java.lang.reflect.Constructor
|
||||||
|
|
||||||
|
open class LayoutInflaterFactory(private val delegate: AppCompatDelegate) : LayoutInflater.Factory2 {
|
||||||
|
|
||||||
|
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
|
||||||
|
return onCreateView(null, name, context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? {
|
||||||
|
val view = delegate.createView(parent, name, context, attrs)
|
||||||
|
?: LayoutInflaterFactoryDefaultImpl.createViewFromTag(context, name, attrs)
|
||||||
|
onViewCreated(view, parent, name, context, attrs)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onViewCreated(view: View?, parent: View?, name: String, context: Context, attrs: AttributeSet) {
|
||||||
|
if (view == null) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object LayoutInflaterFactoryDefaultImpl {
|
||||||
|
|
||||||
|
private val constructorSignature = arrayOf(
|
||||||
|
Context::class.java, AttributeSet::class.java)
|
||||||
|
|
||||||
|
private val classPrefixList = arrayOf(
|
||||||
|
"android.widget.",
|
||||||
|
"android.view.",
|
||||||
|
"android.webkit."
|
||||||
|
)
|
||||||
|
|
||||||
|
private val constructorMap = SimpleArrayMap<String, Constructor<out View?>>()
|
||||||
|
|
||||||
|
fun createViewFromTag(context: Context, name: String, attrs: AttributeSet): View? {
|
||||||
|
var name = name
|
||||||
|
if (name == "view") {
|
||||||
|
name = attrs.getAttributeValue(null, "class")
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
if (-1 == name.indexOf('.')) {
|
||||||
|
for (prefix in classPrefixList) {
|
||||||
|
val view: View? = createViewByPrefix(context, name, attrs, prefix)
|
||||||
|
if (view != null) {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
createViewByPrefix(context, name, attrs, null)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ClassNotFoundException::class, InflateException::class)
|
||||||
|
private fun createViewByPrefix(context: Context, name: String, attrs: AttributeSet, prefix: String?): View? {
|
||||||
|
var constructor = constructorMap[name]
|
||||||
|
return try {
|
||||||
|
if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it
|
||||||
|
val clazz = Class.forName(
|
||||||
|
if (prefix != null) prefix + name else name,
|
||||||
|
false,
|
||||||
|
context.classLoader).asSubclass(View::class.java)
|
||||||
|
constructor = clazz.getConstructor(*constructorSignature)
|
||||||
|
constructorMap.put(name, constructor)
|
||||||
|
}
|
||||||
|
constructor!!.isAccessible = true
|
||||||
|
constructor.newInstance(context, attrs)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user