JavaFX使非标准小部件动画出现问题
我试图用JavaFX证明一个可扩展的小部件,它不同于JavaFX使非标准小部件动画出现问题,java,animation,javafx,Java,Animation,Javafx,我试图用JavaFX证明一个可扩展的小部件,它不同于标题窗格,因为标签周围的边框随着小部件的扩展而增长。我已经找到了做这件事的方法 然而,我有一个奇怪的小故障,在扩展/崩溃一两次后出现 这是一个简短视频的链接,问题出现在第三次和第四次扩展中: 我已经没有东西了,我可以试着让它表现出来 代码如下,为它的古怪道歉,希望在我重构它之前让它工作 class ExpansionManager { enum LayoutState { INITIALIZE, ANI
标题窗格
,因为标签周围的边框随着小部件的扩展而增长。我已经找到了做这件事的方法
然而,我有一个奇怪的小故障,在扩展/崩溃一两次后出现
这是一个简短视频的链接,问题出现在第三次和第四次扩展中:
我已经没有东西了,我可以试着让它表现出来
代码如下,为它的古怪道歉,希望在我重构它之前让它工作
class ExpansionManager {
enum LayoutState {
INITIALIZE,
ANIMATING,
IDLE,
REQUEST_ANIMATION
}
LayoutState layoutState = LayoutState.INITIALIZE;
Double fromWidth = 0.0;
Double fromHeight = 0.0;
Double stepWidth = 0.0;
Double stepHeight = 0.0;
Double toWidth = 0.0;
Double toHeight = 0.0;
}
public class ExpandableTitledList extends VBox {
private Label title = new Label();
private ListProperty<String> listItem = new SimpleListProperty<>();
private ListView listView = new ListView<>(listItem);
Timeline timeline;
WritableValue<Double> writableHeight = new WritableValue<Double>() {
@Override
public Double getValue() {
return expansionManager.stepHeight;
}
@Override
public void setValue(Double value) {
expansionManager.stepHeight = value;
requestLayout();
}
};
WritableValue<Double> writableWidth = new WritableValue<Double>() {
@Override
public Double getValue() {
return expansionManager.stepWidth;
}
@Override
public void setValue(Double value) {
expansionManager.stepWidth = value;
requestLayout();
}
};
private boolean expanded = false;
ExpansionManager expansionManager = new ExpansionManager();
// private Dimension2D contractedDimension;
// private Dimension2D expandedDimension;
public ExpandableTitledList() {
setTitle("boom");
// title.layout();
// System.out.println(title.getLayoutBounds().getWidth());
// set down right caret
listItem.setValue(FXCollections.observableArrayList("one", "two"));
Insets theInsets = new Insets(-3, -5, -3, -5);
Border theBorder = new Border(
new BorderStroke(
Color.BLACK,
BorderStrokeStyle.SOLID,
new CornerRadii(4),
new BorderWidths(2),
theInsets
)
);
// expandedDimension = new Dimension2D(200,200);
setBorder(theBorder);
getChildren().addAll(title);
title.setOnMouseClicked((event) -> {
System.out.println("mouse clicked");
if (this.expanded) contract();
else expand();
});
}
@Override
protected void layoutChildren() {
System.out.println(expansionManager.layoutState);
if (expansionManager.layoutState == ExpansionManager.LayoutState.INITIALIZE) {
super.layoutChildren();
expansionManager.layoutState = ExpansionManager.LayoutState.IDLE;
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.ANIMATING) {
super.layoutChildren();
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.REQUEST_ANIMATION) {
setCache(false);
listView.setCache(false);
expansionManager.layoutState = ExpansionManager.LayoutState.ANIMATING;
System.out.println("from : " + expansionManager.fromWidth + ", "+ expansionManager.fromHeight);
System.out.println("to : " + expansionManager.toWidth + ", "+ expansionManager.toHeight);
timeline = new Timeline();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.ZERO,
new KeyValue(writableHeight, expansionManager.fromHeight),
new KeyValue(writableWidth, expansionManager.fromWidth)),
new KeyFrame(Duration.millis(100),
new KeyValue(writableHeight, expansionManager.toHeight),
new KeyValue(writableWidth, expansionManager.toWidth))
);
timeline.play();
timeline.setOnFinished((done) -> {
System.out.println("done");
expansionManager.layoutState = ExpansionManager.LayoutState.IDLE;
timeline = null;
});
} else {
System.out.println("idle");
super.layoutChildren();
}
}
@Override
protected double computePrefHeight(double width) {
if (expansionManager.layoutState == ExpansionManager.LayoutState.INITIALIZE) {
expansionManager.fromHeight = super.computePrefHeight(width);
return expansionManager.fromHeight;
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.ANIMATING) {
return expansionManager.stepHeight;
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.REQUEST_ANIMATION) {
expansionManager.fromHeight = getHeight();
expansionManager.stepHeight = expansionManager.fromHeight;
expansionManager.toHeight = super.computePrefHeight(width);
return expansionManager.fromHeight;
} else {
return expansionManager.toHeight;
}
}
@Override
protected double computePrefWidth(double height) {
if (expansionManager.layoutState == ExpansionManager.LayoutState.INITIALIZE) {
expansionManager.fromWidth = super.computePrefWidth(height);
return expansionManager.fromWidth;
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.ANIMATING) {
return expansionManager.stepWidth;
} else if (expansionManager.layoutState == ExpansionManager.LayoutState.REQUEST_ANIMATION) {
expansionManager.fromWidth = getWidth();
expansionManager.stepWidth = expansionManager.fromWidth;
expansionManager.toWidth = super.computePrefWidth(height);
return expansionManager.fromWidth;
} else {
System.out.println("BANG BANG BANG");
return expansionManager.toWidth;
}
}
// @Override
// protected double computeMinWidth(double height) {
// return computePrefWidth(height);
// }
//
// @Override
// protected double computeMinHeight(double width) {
// return computePrefHeight(width);
// }
//
// @Override
// protected double computeMaxWidth(double height) {
// return computePrefWidth(height);
// }
//
// @Override
// protected double computeMaxHeight(double width) {
// return computePrefHeight(width);
// }
private void expand() {
System.out.println(expansionManager.layoutState);
// if(contractedDimension == null)
// contractedDimension = new Dimension2D(this.getWidth(), this.getHeight());
// setPrefSize(expandedDimension.getWidth(), expandedDimension.getHeight());
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
this.getChildren().setAll(title, listView);
expanded = true;
}
private void contract() {
// this.setPrefSize(contractedDimension.getWidth(), contractedDimension.getHeight());
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
this.getChildren().setAll(title);
expanded = false;
}
public String getTitle() {
return title.getText();
}
public void setTitle(String title) {
this.title.setText(title);
}
}
类扩展管理器{
枚举布局状态{
初始化,
制作动画,
闲置的
请求动画
}
LayoutState LayoutState=LayoutState.INITIALIZE;
双fromWidth=0.0;
双fromHeight=0.0;
双台阶宽度=0.0;
双stepHeight=0.0;
双toWidth=0.0;
双toHeight=0.0;
}
公共类ExpandableTitleList扩展了VBox{
私有标签标题=新标签();
private ListProperty listItem=新的SimpleListProperty();
私有ListView ListView=新ListView(listItem);
时间线;
WritableValue writableHeight=新的WritableValue(){
@凌驾
公共双getValue(){
返回expansionManager.stepHeight;
}
@凌驾
公共无效设置值(双值){
expansionManager.stepHeight=值;
requestLayout();
}
};
WritableValue writableWidth=新的WritableValue(){
@凌驾
公共双getValue(){
返回expansionManager.stepWidth;
}
@凌驾
公共无效设置值(双值){
expansionManager.stepWidth=值;
requestLayout();
}
};
私有布尔扩展=false;
ExpansionManager ExpansionManager=新的ExpansionManager();
//私人维度2D合同维度;
//私有维度2D扩展维度;
公共可扩展标题列表(){
SETTILE(“boom”);
//title.layout();
//System.out.println(title.getLayoutBounds().getWidth());
//放下右插入符号
setValue(FXCollections.observearraylist(“一”、“二”));
插图-插图=新插图(-3,-5,-3,-5);
Border theBorder=新边框(
新边界笔划(
颜色,黑色,
BorderStrokeStyle.SOLID,
新的转弯半径(4),
新边界宽度(2),
插曲
)
);
//扩展尺寸=新尺寸2D(200200);
边境秩序;
getChildren().addAll(标题);
title.setOnMouseClicked((事件)->{
System.out.println(“鼠标点击”);
如果(本扩展)合同();
else展开();
});
}
@凌驾
受保护的void layoutChildren(){
System.out.println(expansionManager.layoutState);
if(expansionManager.layoutState==expansionManager.layoutState.INITIALIZE){
super.layoutChildren();
expansionManager.layoutState=expansionManager.layoutState.IDLE;
}else if(expansionManager.layoutState==expansionManager.layoutState.ANIMATING){
super.layoutChildren();
}else if(expansionManager.layoutState==expansionManager.layoutState.REQUEST\u动画){
setCache(false);
setCache(false);
expansionManager.layoutState=expansionManager.layoutState.ANIMATING;
System.out.println(“from:“+expansionManager.fromWidth+”,“+expansionManager.fromHeight”);
System.out.println(“to:“+expansionManager.toWidth+”,“+expansionManager.toHeight”);
时间线=新时间线();
timeline.getKeyFrames().addAll(
新关键帧(Duration.ZERO,
新的键值(writableHeight、expansionManager.fromHeight),
新的键值(writableWidth,expansionManager.fromWidth)),
新关键帧(持续时间.毫秒(100),
新的键值(writableHeight、expansionManager.toHeight),
新键值(writableWidth、expansionManager.toWidth))
);
timeline.play();
timeline.setOnFinished((完成)->{
系统输出打印项次(“完成”);
expansionManager.layoutState=expansionManager.layoutState.IDLE;
时间线=空;
});
}否则{
系统输出打印项次(“空闲”);
super.layoutChildren();
}
}
@凌驾
受保护的双计算参考高度(双宽度){
if(expansionManager.layoutState==expansionManager.layoutState.INITIALIZE){
expansionManager.fromHeight=super.computePrefHeight(宽度);
返回expansionManager.fromHeight;
}else if(expansionManager.layoutState==expansionManager.layoutState.ANIMATING){
返回expansionManager.stepHeight;
}else if(expansionManager.layoutState==expansionManager.layoutState.REQUEST\u动画){
expansionManager.fromHeight=getHeight();
expansionManager.stepHeight=expansionManager.fromHeight;
expansionManager.toHeight=super.computePrefHeight(宽度);
返回expansionManager.fromHeight;
}否则{
返回expansionManager.toHeight;
}
}
@凌驾
受保护的双computePrefWidth(双高){
if(expansionManager.layoutState==expansionManager.layoutState.INITIALIZE){
expansionManager.fromWidth=super.computePrefWidth(高度);
返回expansionManager.fromWidth;
}else if(expansionManager.layoutState==ExpansionMan
timeline.setDelay(Duration.millis(1000));
private void expand() {
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
// this works...
listView = new ListView<>(listItem);
this.getChildren().setAll(title,listView);
expanded = true;
}
private void expand() {
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
// this will avoid seeing the unresized listView
listView.setOpacity(0);
this.getChildren().setAll(title,listView);
expanded = true;
}
timeline.getKeyFrames().setAll(
new KeyFrame(Duration.ZERO,
new KeyValue(listView.opacityProperty(), 0),
new KeyValue(writableHeight, expansionManager.fromHeight.get()),
new KeyValue(writableWidth, expansionManager.fromWidth.get())),
new KeyFrame(Duration.millis(300),
new KeyValue(listView.opacityProperty(), 1),
new KeyValue(writableHeight, expansionManager.toHeight.get()),
new KeyValue(writableWidth, expansionManager.toWidth.get()))
);
Double minWidth = 0.0;
Double minHeight = 0.0;
@Override
protected double computePrefHeight(double width) {
...
if (expansionManager.layoutState == ExpansionManager.LayoutState.REQUEST_ANIMATION) {
if(expansionManager.minHeight==0d){
expansionManager.minHeight=getHeight();
}
expansionManager.fromHeight = getHeight();
expansionManager.stepHeight = expansionManager.fromHeight;
expansionManager.toHeight = expanded?super.computePrefHeight(width):
expansionManager.minHeight;
return expansionManager.fromHeight;
}
}
@Override
protected double computePrefWidth(double height) {
...
if (expansionManager.layoutState == ExpansionManager.LayoutState.REQUEST_ANIMATION) {
if(expansionManager.minWidth==0d){
expansionManager.minWidth=getWidth();
}
expansionManager.fromWidth = getWidth();
expansionManager.stepWidth = expansionManager.fromWidth;
expansionManager.toWidth = expanded?super.computePrefWidth(height):
expansionManager.minWidth;
return expansionManager.fromWidth;
}
}
@Override
protected void layoutChildren() {
timeline.setOnFinished((done) -> {
expansionManager.layoutState = ExpansionManager.LayoutState.IDLE;
listView.setVisible(expanded);
timeline = null;
});
}
private void expand() {
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
expanded = true;
listView.setVisible(true);
if(this.getChildren().size()==1){
this.getChildren().add(listView);
}
requestLayout();
}
private void contract() {
expansionManager.layoutState = ExpansionManager.LayoutState.REQUEST_ANIMATION;
expanded = false;
requestLayout();
}