如何从内部引用 lambda?
How to reference a lambda from inside it?
我试图在 onCreate 方法中获取视图的高度,但我找不到任何方法来删除 OnGlobalLayoutListener。
在Java(工作):
containerLayout.getViewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
containerLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
在 Kotlin 中(不接受 "this"):
containerLayout.viewTreeObserver.addOnGlobalLayoutListener {
containerLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
Toast.makeText(applicationContext, "size is "+ containerLayout.height,Toast.LENGTH_LONG).show()
}
这个问题有参考或例子吗?谢谢
不支持从内部引用 lambda。
作为解决方法,您可以使用匿名对象而不是 lambda SAM 转换为 Java 功能接口 OnGlobalLayoutListener
:
containerLayout.viewTreeObserver.addOnGlobalLayoutListener(object: OnGlobalLayoutListener {
override fun onGlobalLayout() {
// your code here. `this` should work
}
})
另一个解决方案是 implement 并使用自引用:
class SelfReference<T>(val initializer: SelfReference<T>.() -> T) {
val self: T by lazy {
inner ?: throw IllegalStateException()
}
private val inner = initializer()
}
fun <T> selfReference(initializer: SelfReference<T>.() -> T): T {
return SelfReference(initializer).self
}
那么用法就是
containerLayout.viewTreeObserver.addOnGlobalLayoutListener(selfReference {
OnGlobalLayoutListener {
containerLayout.viewTreeObserver.removeOnGlobalLayoutListener(self)
// ...
}
}
而不是 this
,self
属性 被使用。
这样的扩展是怎么回事?
import android.annotation.SuppressLint
import android.os.Build
import android.view.View
import android.view.ViewTreeObserver
inline fun View.doOnGlobalLayout(crossinline action: (view: View) -> Unit) {
val vto = viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
@SuppressLint("ObsoleteSdkInt")
@Suppress("DEPRECATION")
override fun onGlobalLayout() {
action(this@doOnGlobalLayout)
when {
vto.isAlive -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
vto.removeOnGlobalLayoutListener(this)
} else {
vto.removeGlobalOnLayoutListener(this)
}
}
else -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
} else {
viewTreeObserver.removeGlobalOnLayoutListener(this)
}
}
}
}
})
}
最后,您可以直接从 View 调用 OnGlobalLayoutListener
val view: View = ...
view.doOnGlobalLayout {
val width = view?.measuredWidth
val height = view?.measuredHeight
}
简单/清晰的方法(没有泛型或匿名对象):
您可以预先创建监听器,然后根据需要添加/使用/删除:
private var layoutChangedListener: ViewTreeObserver.OnGlobalLayoutListener? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// create the listener
layoutChangedListener = ViewTreeObserver.OnGlobalLayoutListener {
// do something here
// remove the listener from your view
myContainerView.viewTreeObserver.removeOnGlobalLayoutListener(layoutChangedListener)
layoutChangedListener = null
}
// add the listener to your view
myContainerView.viewTreeObserver.addOnGlobalLayoutListener(layoutChangedListener)
}
用例:
我必须能够移除侦听器,以便调整侦听器本身内部的布局 - 不移除侦听器 可能 导致死锁
我试图在 onCreate 方法中获取视图的高度,但我找不到任何方法来删除 OnGlobalLayoutListener。
在Java(工作):
containerLayout.getViewTreeObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
containerLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = layout.getMeasuredWidth();
int height = layout.getMeasuredHeight();
}
});
在 Kotlin 中(不接受 "this"):
containerLayout.viewTreeObserver.addOnGlobalLayoutListener {
containerLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
Toast.makeText(applicationContext, "size is "+ containerLayout.height,Toast.LENGTH_LONG).show()
}
这个问题有参考或例子吗?谢谢
不支持从内部引用 lambda。
作为解决方法,您可以使用匿名对象而不是 lambda SAM 转换为 Java 功能接口 OnGlobalLayoutListener
:
containerLayout.viewTreeObserver.addOnGlobalLayoutListener(object: OnGlobalLayoutListener {
override fun onGlobalLayout() {
// your code here. `this` should work
}
})
另一个解决方案是 implement 并使用自引用:
class SelfReference<T>(val initializer: SelfReference<T>.() -> T) {
val self: T by lazy {
inner ?: throw IllegalStateException()
}
private val inner = initializer()
}
fun <T> selfReference(initializer: SelfReference<T>.() -> T): T {
return SelfReference(initializer).self
}
那么用法就是
containerLayout.viewTreeObserver.addOnGlobalLayoutListener(selfReference {
OnGlobalLayoutListener {
containerLayout.viewTreeObserver.removeOnGlobalLayoutListener(self)
// ...
}
}
而不是 this
,self
属性 被使用。
这样的扩展是怎么回事?
import android.annotation.SuppressLint
import android.os.Build
import android.view.View
import android.view.ViewTreeObserver
inline fun View.doOnGlobalLayout(crossinline action: (view: View) -> Unit) {
val vto = viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
@SuppressLint("ObsoleteSdkInt")
@Suppress("DEPRECATION")
override fun onGlobalLayout() {
action(this@doOnGlobalLayout)
when {
vto.isAlive -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
vto.removeOnGlobalLayoutListener(this)
} else {
vto.removeGlobalOnLayoutListener(this)
}
}
else -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
} else {
viewTreeObserver.removeGlobalOnLayoutListener(this)
}
}
}
}
})
}
最后,您可以直接从 View 调用 OnGlobalLayoutListener
val view: View = ...
view.doOnGlobalLayout {
val width = view?.measuredWidth
val height = view?.measuredHeight
}
简单/清晰的方法(没有泛型或匿名对象):
您可以预先创建监听器,然后根据需要添加/使用/删除:
private var layoutChangedListener: ViewTreeObserver.OnGlobalLayoutListener? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// create the listener
layoutChangedListener = ViewTreeObserver.OnGlobalLayoutListener {
// do something here
// remove the listener from your view
myContainerView.viewTreeObserver.removeOnGlobalLayoutListener(layoutChangedListener)
layoutChangedListener = null
}
// add the listener to your view
myContainerView.viewTreeObserver.addOnGlobalLayoutListener(layoutChangedListener)
}
用例: 我必须能够移除侦听器,以便调整侦听器本身内部的布局 - 不移除侦听器 可能 导致死锁