After a long time I am back again with new stuffs. I have seen that JavaFX has got so many demand nowadays. Lots of people are requesting for something new something wow effect. In the same way one of my colleagues told me what if we have listview got some effects on scrolling the list. I got some dig around JavaFX Animation API and did some animation with ListCell but I thought it would be great if I share my works to you guys.
First We got to revamp what is the Listcell. ListCell are designed for making user to display text content in list format. But we can override these and make our own like displaying images,shapes and other controls as well.
ListCell inherits the character of Labeled so in default ListCell only displays the text content.If you want some control in your listcell other than label then there are some bunch of cellfactory in javafx.scene.control.cell package.
Every ListCell are being rendered according to the cellFactory implementation so you are free to implement your own cellFactory to make the listcell even more customizable. I had posted about TableCell customization which utilizes use of cellFactory (TableView Cell Modify)
Lets roll with the ListCell customization.
——————————————————————————————————————————————————————
public class AnimatedListCell<T> extends AbstractAnimatedListCell<T> { //... other codes ... /** * Get cellfactory of AbstractAnimatedListCell for ListView * * @param type * @return */ public static Callback<ListView<String>, ListCell<String>> forListView(final AnimationType... type) { return new Callback<ListView<String>, ListCell<String>>() { @Override public ListCell<String> call( ListView<String> p) { return new AnimatedListCell<>(new DefaultStringConverter(), type); } }; } /** * Get cellfactory of AbstractAnimatedListCell for ListView with StringConverter * * @param <T> * @param sc * @param type * @return */ public static <T extends Object> Callback<ListView<T>, ListCell<T>> forListView( final StringConverter<T> sc, final AnimationType... type) { return new Callback<ListView<T>, ListCell<T>>() { @Override public ListCell<T> call( ListView<T> p) { return new AnimatedListCell<>(sc, type); } }; } /** * For getting the KeyFrames of specific AnimationType * * @param types * @return */ @Override protected KeyFrame[] getKeyFrames(AnimationType[] types) { if (types == null) { return null; } KeyFrame[] frames = null; for (AnimationType type : types) { switch (type) { case FADE_OUT: frames = anim.getFadeOut(frames); break; case FLAP_RIGHT: frames = anim.getFlapRight(frames); break; case FLATTERN_OUT: frames = anim.getFlatternOut(frames); break; case FLY_FROM_DOWN: frames = anim.getFlyFromDown(frames); break; case FLY_FROM_UP: frames = anim.getFlyFromUp(frames); break; case ROTATE_RIGHT: frames = anim.getRotateYRight(frames); break; case SPEED_LEFT: frames = anim.getSpeedLeft(frames); break; case SPEED_RIGHT: frames = anim.getSpeedRight(frames); break; case TRANSITION_DOWN: frames = anim.getTransitionDown(frames); break; case TRANSITION_LEFT: frames = anim.getTransitionLeft(frames); break; case TRANSITION_RIGHT: frames = anim.getTransitionRight(frames); break; case TRANSITION_TOP: frames = anim.getTransitionTop(frames); break; case ZOOM_IN: frames = anim.getZoomIn(0, frames); break; case POP_OUT: frames = anim.getPopOut(frames); break; } } return frames; } @Override protected void updateItem(T t, boolean bln) { //overriding the super interface super.updateItem(t, bln); } }
Above Class is subclass of AbstractAnimatedListCell so you can implement this in your cellFactory. Currently AbstractAnimatedListCell is subclass of ListCell which helps to make the animation possible. Now Lets directly move to the animation implementation.
/** * * @author Narayan G. Maharjan <me@ngopal.com.np> */ public class ListViewAnimation extends Application { ObservableList list = FXCollections.observableArrayList(); ListView<String> listView; ComboBox<AnimationType> box; HBox hbox; AnchorPane root; Button btn; /** * For initializing Containers */ public void initContainers() { root = new AnchorPane(); hbox = new HBox(10); AnchorPane.setBottomAnchor(listView, 50d); AnchorPane.setTopAnchor(listView, 10d); AnchorPane.setLeftAnchor(listView, 10d); AnchorPane.setRightAnchor(listView, 10d); AnchorPane.setBottomAnchor(hbox, 10d); AnchorPane.setLeftAnchor(hbox, 10d); } /** * For initializing controls */ public void initControls() { listView = new ListView<>(); listView.setCellFactory(AnimatedListCell.forListView(AnimationType.ROTATE_RIGHT, AnimationType.FADE_OUT)); box = new ComboBox<>(); box.valueProperty().addListener(new ChangeListener<AnimationType>() { @Override public void changed( ObservableValue<? extends AnimationType> ov, AnimationType t, AnimationType t1) { if (!t1.equals(t)) { listView.setCellFactory(AnimatedListCell.forListView(t1)); } } }); btn = new Button("Add New"); btn.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { list.add("Added New"); } }); } @Override public void start(Stage stage) throws Exception { //Loading custom fonts Font.loadFont(getClass().getResource("fonts/segoesc.ttf").toExternalForm(), 12); //adding values to list for (int i = 0; i < 10; i++) { list.add("" + i); } //Initializing Controls initControls(); initContainers(); //Adding Values listView.setItems(list); box.getItems().addAll(AnimationType.values()); //Adding controls to container hbox.getChildren().addAll(new Label("Animation Type:"), box, btn); root.getChildren().addAll(listView, hbox); Scene scene = new Scene(root); scene.getStylesheets().add(getClass().getResource("css/style.css").toExternalForm()); scene.setCamera(new PerspectiveCamera()); stage.setTitle("List Animation!"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
Well after implementing those Animation you can get animation instantly on list cell update . However I have added some few styling to make it even more better.
If you want to try out yourself . Grab the source code from here: