递归链接 ConstraintLayout 转换与 Runnable 在第一个 运行 后停止
Recursively Chaining ConstraintLayout Transitions with Runnable stops after first run
我正在尝试为自定义菜单创建切换动画。有多个菜单,可以通过不同的按钮进行选择。
当没有菜单打开时,点击按钮应该打开该菜单。
如果另一个菜单打开,则打开的菜单将关闭,并且在该动画之后,应打开所选的菜单。
每个 closing/opening 动作都与 ConstraintLayout 转换相结合。
由于无法正常工作,我创建了以下测试程序:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
ConstraintLayout layout_main;
ConstraintSet l_mh0c = new ConstraintSet();
ConstraintSet l_mh1o = new ConstraintSet();
ConstraintSet l_mh1c = new ConstraintSet();
Button btn;
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleOne();
}
});
layout_main = (ConstraintLayout) findViewById(R.id.constraintMain);
l_mh1o.clone(this, R.layout.main_menue_header1_open);
l_mh1c.clone(this, R.layout.main_menue_header1_closed);
l_mh0c.clone(this, R.layout.activity_main);
...
}
int openedMenue = -1;
long animationTime = 1000;
private void toggleOne() {
TransitionManager.endTransitions(layout_main); //<- makes no difference when commented
if(openedMenue==1) {
System.out.println("sync closing");
Runnable r = () -> toggleOne();
closeMenue(1, animationTime, r);
} else {
System.out.println("sync opening");
startMenue(1, animationTime);
}
}
public void startMenue(Integer index, final Long maxtime) {
Transition t;
switch (index) {
case 1:
t = new ChangeBounds();
t.setDuration(0).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime / 2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime / 2);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0o.applyTo(layout_main);
openedMenue = 1;
System.out.println("sync start finished");
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1o.applyTo(layout_main);
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1c.applyTo(layout_main);
// the following does not provoke any changes
Scene s = new Scene(layout_main);
TransitionManager.go(s);
break;
}
}
private void closeMenue(int index, final long maxtime, Runnable callback) {
System.out.println("sync closing menue " + openedMenue);
Transition t;
switch (index) {
case 1:
t = new ChangeBounds();
t.setDuration(maxtime/2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime/2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(0);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
try {
callback.run();
} catch (Exception e) { e.printStackTrace(); }
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1c.applyTo(layout_main);
openedMenue = 1;
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1o.applyTo(layout_main);
break;
}
}
当我 运行 它时,我得到以下输出:
[Button Click]
sync opening
sync start finished
[Button Click]
sync closing
sync closing menue 1
sync opening
sync start finished // problem
然而,最后一行从未被打印;似乎(在关闭动作再次开始打开动作之后)startMenue() 中的第一个转换从未对 onTransitionEnd() 进行回调。
这里是 TransitionEndListener(只是接口的简单包装)
public abstract class TransitionEndListener implements Transition.TransitionListener {
@Override
public final void onTransitionStart(Transition transition) {}
@Override
public final void onTransitionCancel(Transition transition) {}
@Override
public final void onTransitionPause(Transition transition) {}
@Override
public final void onTransitionResume(Transition transition) {}
}
我已经通过在 onTransitionCancel() 中放置打印语句来检查是否取消了第二个开始转换,但似乎并非如此。
你能解释一下为什么会这样吗?
更新
我找到了 this post on TransitionManager callbacks;
从 mh0c t0 mh1c 的过渡是 ConstraintLayout 过渡,因为约束实际上发生了变化;但是,过渡在 UI 上不可见,因为过渡中元素的宽度为 0。(此过渡是从一个菜单点跳转到不应该可见的另一个菜单点。)
这可能是 Transition 不执行回调的原因吗?
如果是的话;我该如何解决这个问题?
更新 2
我正在阅读 the documentation,可能已经找到了使用 TransitionManager.go(scene, transition)
的解决方案。
--> 不幸的是这没有用;查看 startMenue() 的代码以进行更改
经过越来越多的努力和审查这些帖子:
- TransitionListener callbacks not called when there is nothing to change
我已经找出问题的原因:
在closeMenue()的最里面(最里面的回调)
Transition t = new ChangeBounds();
t.setDuration(0);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
try {
callback.run();
} catch (Exception e) { e.printStackTrace(); }
命令顺序略有错误。它应该是这样的:
Transition t = new ChangeBounds();
t.setDuration(0).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
try {
callback.run();
} catch (Exception e) { e.prtinStackTrace(); }
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
这确保首先完成结束过渡,然后开始开放过渡。
我正在尝试为自定义菜单创建切换动画。有多个菜单,可以通过不同的按钮进行选择。 当没有菜单打开时,点击按钮应该打开该菜单。 如果另一个菜单打开,则打开的菜单将关闭,并且在该动画之后,应打开所选的菜单。 每个 closing/opening 动作都与 ConstraintLayout 转换相结合。
由于无法正常工作,我创建了以下测试程序:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
ConstraintLayout layout_main;
ConstraintSet l_mh0c = new ConstraintSet();
ConstraintSet l_mh1o = new ConstraintSet();
ConstraintSet l_mh1c = new ConstraintSet();
Button btn;
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleOne();
}
});
layout_main = (ConstraintLayout) findViewById(R.id.constraintMain);
l_mh1o.clone(this, R.layout.main_menue_header1_open);
l_mh1c.clone(this, R.layout.main_menue_header1_closed);
l_mh0c.clone(this, R.layout.activity_main);
...
}
int openedMenue = -1;
long animationTime = 1000;
private void toggleOne() {
TransitionManager.endTransitions(layout_main); //<- makes no difference when commented
if(openedMenue==1) {
System.out.println("sync closing");
Runnable r = () -> toggleOne();
closeMenue(1, animationTime, r);
} else {
System.out.println("sync opening");
startMenue(1, animationTime);
}
}
public void startMenue(Integer index, final Long maxtime) {
Transition t;
switch (index) {
case 1:
t = new ChangeBounds();
t.setDuration(0).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime / 2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime / 2);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0o.applyTo(layout_main);
openedMenue = 1;
System.out.println("sync start finished");
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1o.applyTo(layout_main);
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1c.applyTo(layout_main);
// the following does not provoke any changes
Scene s = new Scene(layout_main);
TransitionManager.go(s);
break;
}
}
private void closeMenue(int index, final long maxtime, Runnable callback) {
System.out.println("sync closing menue " + openedMenue);
Transition t;
switch (index) {
case 1:
t = new ChangeBounds();
t.setDuration(maxtime/2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(maxtime/2).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
Transition t = new ChangeBounds();
t.setDuration(0);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
try {
callback.run();
} catch (Exception e) { e.printStackTrace(); }
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1c.applyTo(layout_main);
openedMenue = 1;
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh1o.applyTo(layout_main);
break;
}
}
当我 运行 它时,我得到以下输出:
[Button Click]
sync opening
sync start finished
[Button Click]
sync closing
sync closing menue 1
sync opening
sync start finished // problem
然而,最后一行从未被打印;似乎(在关闭动作再次开始打开动作之后)startMenue() 中的第一个转换从未对 onTransitionEnd() 进行回调。
这里是 TransitionEndListener(只是接口的简单包装)
public abstract class TransitionEndListener implements Transition.TransitionListener {
@Override
public final void onTransitionStart(Transition transition) {}
@Override
public final void onTransitionCancel(Transition transition) {}
@Override
public final void onTransitionPause(Transition transition) {}
@Override
public final void onTransitionResume(Transition transition) {}
}
我已经通过在 onTransitionCancel() 中放置打印语句来检查是否取消了第二个开始转换,但似乎并非如此。
你能解释一下为什么会这样吗?
更新
我找到了 this post on TransitionManager callbacks;
从 mh0c t0 mh1c 的过渡是 ConstraintLayout 过渡,因为约束实际上发生了变化;但是,过渡在 UI 上不可见,因为过渡中元素的宽度为 0。(此过渡是从一个菜单点跳转到不应该可见的另一个菜单点。)
这可能是 Transition 不执行回调的原因吗?
如果是的话;我该如何解决这个问题?
更新 2
我正在阅读 the documentation,可能已经找到了使用 TransitionManager.go(scene, transition)
的解决方案。
--> 不幸的是这没有用;查看 startMenue() 的代码以进行更改
经过越来越多的努力和审查这些帖子:
- TransitionListener callbacks not called when there is nothing to change
我已经找出问题的原因:
在closeMenue()的最里面(最里面的回调)
Transition t = new ChangeBounds();
t.setDuration(0);
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
try {
callback.run();
} catch (Exception e) { e.printStackTrace(); }
命令顺序略有错误。它应该是这样的:
Transition t = new ChangeBounds();
t.setDuration(0).addListener(new TransitionEndListener() {
@Override
public void onTransitionEnd(Transition transition) {
try {
callback.run();
} catch (Exception e) { e.prtinStackTrace(); }
}
});
TransitionManager.beginDelayedTransition(layout_main, t);
l_mh0c.applyTo(layout_main);
openedMenue = -1;
这确保首先完成结束过渡,然后开始开放过渡。