只修列表滚动:每次渲染换一套新的 Table+ScrollPane 塞回同一单元格(复用时 ScrollPane 不重新测量 widget 高度,maxY=0 导致滚轮失效)

This commit is contained in:
tianmo committed 2026-10-16 16:10:20 +08:00
1 parent 94c467a40d
commit ee1f2a2ced
1 file changed
+36 -6
+36 -6
View File
@@ -49,6 +49,11 @@ public final class ObjectPanel {
java.util.List<Object[]> inspectFields = new ArrayList<Object[]>();
List<Object> objects = new ArrayList<Object>();
Object target;
Class<?> tableClass;
Class<?> scrollClass;
Class<?> actorClass;
Class<?> cellClass;
Object listCell; // 承载列表 ScrollPane 的单元格
}
/**
@@ -66,6 +71,10 @@ public final class ObjectPanel {
Class<?> skinClass = Class.forName("com.badlogic.gdx.scenes.scene2d.ui.Skin", true, loader);
Class<?> fieldClass = Class.forName("com.badlogic.gdx.scenes.scene2d.ui.TextField", true, loader);
state.tableClass = tableClass;
state.scrollClass = scrollClass;
state.actorClass = actorClass;
state.cellClass = cellClass;
Object root = tableClass.getConstructor().newInstance();
Object rows = tableClass.getConstructor().newInstance();
call(rows, Obf.TABLE_TOP, new Class<?>[0], tableClass);
@@ -116,6 +125,7 @@ public final class ObjectPanel {
// 唯一 expand+fill 的单元格:内容区(上面是列表/Inspector,最下面是日志块,同一个滚动区)
cell = call(root, Obf.TABLE_ADD, new Class<?>[] {actorClass}, cellClass, scroll);
layoutCell(cell, Obf.CELL_TOP, Obf.CELL_EXPAND, Obf.CELL_FILL);
state.listCell = cell;
wire(loader, refresh, new Runnable() {
@Override
@@ -272,8 +282,7 @@ public final class ObjectPanel {
state.objects = objects;
try {
// Table.clearChildren()(载荷名 `SourceFile()V`):把列表里的行全清掉重建。
call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class<?>[0], void.class);
state.logBlockStarted = false;
beginRender(state);
Class<?> cellClass = Class.forName(Obf.CELL, true, state.loader);
Class<?> actorClass = Class.forName(Obf.ACTOR, true, state.loader);
for (int i = 0; i < objects.size() && i < 300; i++) {
@@ -508,6 +517,29 @@ public final class ObjectPanel {
* 否则 ScrollPane 里缓存的高度还是旧的,表现为"内容多了却不能滚"。
* `b_()V` = `invalidate()`(来源:MapMethods 对 gdx-1.11.0 的指纹比对)。
*/
/**
* 每次渲染都换一套**全新的 Table + ScrollPane**,塞回同一个单元格。
*
* 为什么必须换:ScrollPane 只在 layout 时量一次里面 widget 的高度,我们之后往 widget 里
* 加/删行,它记的高度还是旧的 —— maxY 一直是 0,滚轮就滚不动(你看到的现象)。
* 换一个新的 ScrollPane 最省事也最稳(只做这一件事,不改任何别的行为)。
*/
private static void beginRender(State state) throws Exception {
Object table = state.tableClass.getConstructor().newInstance();
call(table, Obf.TABLE_TOP, new Class<?>[0], state.tableClass);
call(table, Obf.TABLE_LEFT, new Class<?>[0], state.tableClass);
Class<?> skinClass = Class.forName("com.badlogic.gdx.scenes.scene2d.ui.Skin", true, state.loader);
Object scroll = state.scrollClass.getConstructor(state.actorClass, skinClass)
.newInstance(table, state.skin);
state.listTable = table;
state.listScroll = scroll;
if (state.listCell != null) {
// Cell.setActor(Actor):把旧 ScrollPane 换成新的
call(state.listCell, "D", new Class<?>[] {state.actorClass}, state.cellClass, scroll);
}
state.logBlockStarted = false;
}
private static void invalidateList(final State state) {
try {
call(state.listTable, "b_", new Class<?>[0], void.class);
@@ -528,8 +560,7 @@ public final class ObjectPanel {
private static void fillRows(final State state, List<String> lines,
java.util.Map<Integer, Object[]> clickable) {
try {
call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class<?>[0], void.class);
state.logBlockStarted = false;
beginRender(state);
Class<?> cellClass = Class.forName(Obf.CELL, true, state.loader);
Class<?> actorClass = Class.forName(Obf.ACTOR, true, state.loader);
for (int i = 0; i < lines.size(); i++) {
@@ -586,8 +617,7 @@ public final class ObjectPanel {
/** 用纯文本行填列表区(行不可点)。 */
private static void fillTextRows(final State state, List<String> lines) {
try {
call(state.listTable, Obf.TABLE_CLEAR_CHILDREN, new Class<?>[0], void.class);
state.logBlockStarted = false;
beginRender(state);
Class<?> cellClass = Class.forName(Obf.CELL, true, state.loader);
Class<?> actorClass = Class.forName(Obf.ACTOR, true, state.loader);
for (String line : lines) {