1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
package extended;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.css.*;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.util.Duration;
import java.util.List;
/**
* @author Gerrit Grunwald
* Here are the things we need to do...
*
* 1.Extend the JavaFX TextField
* 2.Add a Text to it that can be set using the promptTextProperty
* 3.Add animation of the Text dependent on the focus state
* 4.Add some CSS styling
*/
public class ExtendedControl extends TextField {
private static final StyleablePropertyFactory<ExtendedControl> FACTORY
= new StyleablePropertyFactory<>(TextField.getClassCssMetaData());
private static final double STD_FONT_SIZE = 13;
private static final double SMALL_FONT_SIZE = 10;
private static final double TOP_OFFSET_Y = 4;
private static final int ANIMATION_DURATION = 60;
/** 组件 **/
private Text promptText;
private HBox promptTextBox;
/** paint **/
private static final Color DEFAULT_MATERIAL_DESIGN_COLOR = Color.web("#009688");
private static final Color DEFAULT_PROMPT_TEXT_COLOR = Color.web("#757575");
/** 动画时间线 **/
private Timeline timeline;
/** Properties **/
private final StyleableProperty<Color> materialDesignColor;
private final StyleableProperty<Color> promptTextColor;
private DoubleProperty fontSize;
/** 用户代理样式表 **/
private static String userAgentStyleSheet;
/** css样式属性 **/
private static final CssMetaData<ExtendedControl, Color> MATERIAL_DESIGN_COLOR
= FACTORY.createColorCssMetaData
("-material-design-color", s -> s.materialDesignColor, DEFAULT_MATERIAL_DESIGN_COLOR, false);
private static final CssMetaData<ExtendedControl, Color> PROMPT_TEXT_COLOR
= FACTORY.createColorCssMetaData
("-prompt-text-color", s -> s.promptTextColor, DEFAULT_PROMPT_TEXT_COLOR, false);
public ExtendedControl() {
this("");
}
public ExtendedControl(final String promptTextBox) {
super(promptTextBox);
materialDesignColor = new SimpleStyleableObjectProperty<>(MATERIAL_DESIGN_COLOR, this, "materialDesignColor");
promptTextColor = new SimpleStyleableObjectProperty<>(PROMPT_TEXT_COLOR, this, "promptTextColor");
fontSize = new SimpleDoubleProperty(ExtendedControl.this, "fontSize", getFont().getSize());
timeline = new Timeline();
initGraphics();
registerListeners();
}
/**
* 初始化
*/
private void initGraphics() {
getStyleClass().addAll("material-field");
final String fontFamily = getFont().getFamily();
final int length = getText().length();
promptText = new Text(getPromptText());
promptText.getStyleClass().add("prompt-text");
promptTextBox = new HBox(promptText);
promptTextBox.getStyleClass().add("material-field");
if (!isEditable() || isDisabled() || length > 0) {
promptText.setFont(Font.font(fontFamily, SMALL_FONT_SIZE));
promptTextBox.setTranslateY(-STD_FONT_SIZE - TOP_OFFSET_Y);
} else {
promptText.setFont(Font.font(fontFamily, STD_FONT_SIZE));
}
getChildren().addAll(promptTextBox);
}
/**
* 注册监听器
*/
private void registerListeners() {
textProperty().addListener(o -> handleTextAndFocus(isFocused()));
promptTextProperty().addListener(o -> promptText.setText(getPromptText()));
focusedProperty().addListener(o -> handleTextAndFocus(isFocused()));
promptTextColorProperty().addListener(o -> promptText.setFill(getPromptTextColor()));
fontSize.addListener(o -> promptText.setFont(Font.font(fontSize.get())));
timeline.setOnFinished(evt -> {
final int length = null == getText() ? 0 : getText().length();
if (length > 0 && promptTextBox.getTranslateY() >= 0) {
promptTextBox.setTranslateY(-STD_FONT_SIZE - TOP_OFFSET_Y);
fontSize.set(SMALL_FONT_SIZE);
}
});
}
/**
* css样式属性
*/
public Color getMaterialDesignColor() {
return materialDesignColor.getValue();
}
public Color getPromptTextColor() {
return promptTextColor.getValue();
}
public ObjectProperty<Color> promptTextColorProperty() {
return (ObjectProperty<Color>) promptTextColor;
}
/**
* style related
*/
@Override
public String getUserAgentStylesheet() {
if (null == userAgentStyleSheet) {
userAgentStyleSheet = getClass().getResource("/extended.css").toExternalForm();
}
return userAgentStyleSheet;
}
@Override
public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
return FACTORY.getCssMetaData();
}
/**
* function method
*/
private void handleTextAndFocus(final boolean isFocused) {
final int length = null == getText() ? 0 : getText().length();
KeyFrame kf0;
KeyFrame kf1;
KeyValue kvTextY0;
KeyValue kvTextY1;
KeyValue kvTextFontSize0;
KeyValue kvTextFontSize1;
KeyValue kvPromptTextFill0;
KeyValue kvPromptTextFill1;
if (isFocused | length > 0 || isDisabled() || !isEditable()) {
if (Double.compare(promptTextBox.getTranslateY(), -STD_FONT_SIZE - TOP_OFFSET_Y) != 0) {
kvTextY0 = new KeyValue(promptTextBox.translateYProperty(), 0);
kvTextY1 = new KeyValue(promptTextBox.translateYProperty(), -STD_FONT_SIZE - TOP_OFFSET_Y);
kvTextFontSize0 = new KeyValue(fontSize, STD_FONT_SIZE);
kvTextFontSize1 = new KeyValue(fontSize, SMALL_FONT_SIZE);
kvPromptTextFill0 = new KeyValue(promptTextColorProperty(), DEFAULT_PROMPT_TEXT_COLOR);
kvPromptTextFill1 = new KeyValue
(promptTextColorProperty(), isFocused ? getMaterialDesignColor() : DEFAULT_PROMPT_TEXT_COLOR);
kf0 = new KeyFrame(Duration.ZERO, kvTextY0, kvTextFontSize0, kvPromptTextFill0);
kf1 = new KeyFrame(Duration.millis(ANIMATION_DURATION), kvTextY1, kvTextFontSize1, kvPromptTextFill1);
timeline.getKeyFrames().setAll(kf0, kf1);
timeline.play();
}
promptText.setFill(isFocused ? getMaterialDesignColor() : DEFAULT_PROMPT_TEXT_COLOR);
} else {
if (Double.compare(promptTextBox.getTranslateY(), 0) != 0) {
kvTextY0 = new KeyValue(promptTextBox.translateYProperty(), promptTextBox.getTranslateY());
kvTextY1 = new KeyValue(promptTextBox.translateYProperty(), 0);
kvTextFontSize0 = new KeyValue(fontSize, SMALL_FONT_SIZE);
kvTextFontSize1 = new KeyValue(fontSize, STD_FONT_SIZE);
kvPromptTextFill0 = new KeyValue(promptTextColorProperty(), getMaterialDesignColor());
kvPromptTextFill1 = new KeyValue(promptTextColorProperty(), DEFAULT_PROMPT_TEXT_COLOR);
kf0 = new KeyFrame(Duration.ZERO, kvTextY0, kvTextFontSize0, kvPromptTextFill0);
kf1 = new KeyFrame(Duration.millis(ANIMATION_DURATION), kvTextY1, kvTextFontSize1, kvPromptTextFill1);
timeline.getKeyFrames().setAll(kf0, kf1);
timeline.play();
}
}
}
}
|