-
-
Save programmerr47/aa32748a337903896ce1a84ffd2f14df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal class TranslationsLayoutInflater( | |
origin: LayoutInflater, | |
context: Context, | |
cloned: Boolean = false, | |
//other args | |
) : LayoutInflater(origin, context) { | |
private var privateFactorySet: Boolean = false | |
init { | |
if (!cloned) { | |
factory?.let { factory = it } | |
factory2?.let { factory2 = it } | |
} | |
} | |
override fun cloneInContext(newContext: Context) = TranslationsLayoutInflater(this, newContext, true, /*other args*/) | |
override fun setFactory(factory: Factory?) { | |
val final = factory?.let { (it as? WrapperFactory) ?: WrapperFactory(/*args*/) } | |
super.setFactory(final) | |
} | |
override fun setFactory2(factory: Factory2?) { | |
val final = factory?.let { (it as? WrapperFactory2) ?: WrapperFactory2(it /*args*/) } | |
super.setFactory2(final) | |
} | |
override fun inflate(parser: XmlPullParser, root: ViewGroup?, attachToRoot: Boolean): View { | |
setPrivateFactoryInternal() | |
return super.inflate(parser, root, attachToRoot) | |
} | |
private fun setPrivateFactoryInternal() { | |
if (privateFactorySet) return | |
val ctx = context | |
if (ctx !is Factory2) { | |
privateFactorySet = true | |
return | |
} | |
getMethod("setPrivateFactory")?.invoke(WrapperFactory2(PrivateFactory2(this, ctx), /*args*/)) | |
privateFactorySet = true | |
} | |
private class WrapperFactory( | |
//..args | |
) : Factory { | |
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? = | |
//you intercept view creation here | |
} | |
private class WrapperFactory2( | |
private val origin: Factory2, | |
//args | |
) : Factory2 { | |
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? = | |
origin.onCreateView(name, context, attrs)?.also { /*intercept view creation here*/ } | |
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? = | |
origin.onCreateView(parent, name, context, attrs)?.also { /*intercept view creation here*/ } | |
} | |
private class PrivateFactory2( | |
private val inflater: LayoutInflater, | |
private val origin: Factory2 | |
) : Factory2 { | |
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? = | |
origin.onCreateView(name, context, attrs) ?: createCustomView(name, context, attrs) | |
override fun onCreateView(parent: View?, name: String, context: Context, attrs: AttributeSet): View? = | |
origin.onCreateView(name, context, attrs) ?: createCustomView(name, context, attrs) | |
private fun createCustomView(name: String, context: Context, attrs: AttributeSet): View? { | |
return name.takeIf { '.' in it }?.let { customViewName -> | |
if (atLeastQ()) { | |
inflater.createView(context, customViewName, null, attrs) | |
} else { | |
createCustomViewViaReflection(name, context, attrs) | |
} | |
} | |
} | |
private fun createCustomViewViaReflection(name: String, context: Context, attrs: AttributeSet): View? { | |
return inflater.getField<Array<Any>> { LayoutInflater::class.java.getField("mConstructorArgs") }?.value?.let { constructionArgs -> | |
val lastCtx = constructionArgs[0] | |
constructionArgs[0] = context | |
val result = runCatching { inflater.createView(name, null, attrs) } | |
constructionArgs[0] = lastCtx | |
result.getOrNull() | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment