如何解决如何监听多个 GlobalLayout 事件
我正在尝试使用
监听GlobalLayout
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
int c=0;
@Override
public void onGlobalLayout() {
c++; //without removing the listener c will grow for ever even though there is no GlobalLayout events
view.setText(""+c);
}
});
但它被无休止地调用。
我知道我应该像这样删除监听器:view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
但我想让监听器在接下来的 GlobalLayout
事件中保持活动状态。
目前我只是尝试使用 this question 来监听视图位置的变化
我试过 onPreDraw
但还是一样。
是否可以监听多个 GlobalLayout
事件?
提前致谢。
解决方法
您作为示例发布的代码不应编译,因为从侦听器访问变量 c
时出现问题。如果你尝试一下,你应该在 Android Studio 中得到以下错误:
从内部类内部访问变量'c',需要是final或有效final
我们可以根据错误检查的建议创建一个单元素数组,如下所示:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int[] c = {0};
final View[] view = {findViewById(R.id.textView)};
view[0].getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
c[0]++;
}
});
}
}
如果您针对以下布局运行此代码,您将看到侦听器被调用两次,我认为这对应于两次布局传递:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
如果布局在全局布局侦听器中以某种方式被修改,那么它将触发另一个布局和另一个对侦听器的调用。如果监听器再次进行更改,则监听器将再次被调用,以此类推。
如果您能发布遇到问题的实际代码或演示问题的简单项目,将会很有帮助。是否在侦听器内以某种方式修改了布局?
更新:正如您在对此答案的评论中所说,您的问题是您对全局布局侦听器中的视图进行了更改,从而触发了另一个布局和对侦听器的另一次调用无止境。删除导致布局更改的代码后,该特定问题就解决了。
,如果您只是在视图位置更改后尝试触发代码,那么您可能只需在增加变量 c
像这样:
int c = 0;
int x = 0;
int y = 0;
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int x2 = view.getX();
int y2 = view.getY();
// do not increase c unless position has changed
if (x2 != x && y2 != y) {
c++;
// update coordinates values
x = x2;
y = y2;
}
}
});
,
您可以在您的视图上设置监听器尝试使用 view.addOnLayoutChangeListener
https://developer.android.com/reference/android/view/View.OnLayoutChangeListener
它将为您提供布局的新旧 X&Y,您可以根据它调整视图
,只需添加一个标志来检测它是正常事件还是侦听器调用的 setText()
并在需要时跳过它。
代码未测试。但我想你会明白的。
int c=0;
view.getViewTreeObserver().addOnGlobalLayoutListener(new CustomLayoutListener() {
int c=0;
@Override
public void onGlobalLayout() {
if(skipEvent)
return;
c++;
//flag skipEvent while performing setText()
skipEvent = true;
view.setText(""+c);
skipEvent = false;
}
});
class CustomLayoutListener extends ViewTreeObserver.OnGlobalLayoutListener {
static boolean skipEvent;
@Override
public void onGlobalLayout() {}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。