Skip to content

Instantly share code, notes, and snippets.

@programmerr47
Created May 28, 2020 04:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save programmerr47/aa32748a337903896ce1a84ffd2f14df to your computer and use it in GitHub Desktop.
Save programmerr47/aa32748a337903896ce1a84ffd2f14df to your computer and use it in GitHub Desktop.
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