本文是仿微信聊天程序专栏的第五篇文章,主要记录了【聊天列表】的界面实现。
界面设计
聊天列表在主界面左边,主要显示最近的聊天记录,以及添加好友的信息等,总体界面设计如下:
界面布局
聊天列表的布局分为两部,列表布局和列表中的每一行的布局,其中列表布局的完整fxml如下:
<HBox prefHeight="640.0"
prefWidth="250.0" xmlns:fx="http://javafx.com/fxml"
stylesheets="@ChatListController.css"
fx:controller="michong.javafx.wx.view.chat.ChatListController">
<children>
<VBox prefWidth="250.0">
<children>
<HBox prefHeight="70.0" prefWidth="200.0" spacing="10.0">
<children>
<TextField prefHeight="30.0" HBox.hgrow="ALWAYS" promptText="聊天搜索"/>
<Button prefHeight="30.0" prefWidth="30.0" text="+" onAction="#onApplyClick"/>
</children>
<padding>
<Insets left="10.0" right="10.0" top="20.0"/>
</padding>
</HBox>
<ListView fx:id="chatListView" VBox.vgrow="ALWAYS"/>
</children>
</VBox>
</children>
</HBox>
列表项的布局完整fxml如下:
<HBox xmlns:fx="http://javafx.com/fxml" stylesheets="@ChatRowController.css" alignment="CENTER" prefHeight="60.0"
prefWidth="235.0"
spacing="5.0"
fx:id="chatRowHBox">
<children>
<Pane prefHeight="60.0" prefWidth="48.0">
<children>
<ImageView fx:id="avatarImageView" fitHeight="40.0" fitWidth="40.0" layoutX="5.0" layoutY="10.0"/>
<Label fx:id="messageCountLabel" layoutX="35.0" prefHeight="20.0" styleClass="message-count-label"/>
</children>
</Pane>
<VBox prefWidth="116.0" spacing="4.0" HBox.hgrow="ALWAYS">
<children>
<Label fx:id="nicknameLabel" styleClass="name-label"/>
<Label fx:id="messageLabel" styleClass="message-label"/>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="8.0"/>
</padding>
</VBox>
<VBox alignment="TOP_RIGHT" prefWidth="85.0">
<children>
<Label fx:id="timestampLabel" styleClass="timestamp-label"/>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="10.0"/>
</padding>
</VBox>
</children>
</HBox>
构建控件
从上面的界面布局中可以看到列表项并没有直接关联Controller,因为这里我实现动态构建,所以在初始化的时候绑定Controller,具体实现如下:
/**
* @author michong
*/
public class ChatRowController extends ListCell<MessageVO> {
public HBox chatRowHBox;
public ImageView avatarImageView;
public Label messageCountLabel;
public Label nicknameLabel;
public Label messageLabel;
public Label timestampLabel;
FXMLLoader loader;
@Override
protected void updateItem(MessageVO item, boolean empty) {
super.updateItem(item, empty);
if (empty || Objects.isNull(item)) {
setGraphic(null);
return;
}
if (Objects.isNull(loader)) {
loader = new FXMLLoader(getClass().getResource("/" + getClass().getName().replace(".", "/") + ".fxml"));
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (item.getSource() == MessageSource.APPLY) {
avatarImageView.setImage(FXAvatar.apply());
nicknameLabel.setText("新朋友");
messageLabel.setText(item.getNickname() + " 申请添加你为好友。");
} else {
avatarImageView.setImage(FXAvatar.load(item.getAvatar()));
nicknameLabel.setText(item.getNickname());
messageLabel.setText(item.getMessage());
}
timestampLabel.setText(new SimpleDateFormat("yy/MM/dd").format(new Date(item.getTimestamp())));
messageCountLabel.setText(item.getMessageCount() > 99 ? "99+" : String.valueOf(item.getMessageCount()));
messageCountLabel.setLayoutX(item.getMessageCount() > 0 ? 35 : -35);
setGraphic(chatRowHBox);
}
}
样式美化
聊天列表使用的是JavaFX的ListView控件,默认情况下,这个控件不是很美观,所以需要对其进行样式美化,完整的css如下:
* {
-fx-font-family: "微软雅黑", "sans-serif";
-fx-font-size: 14px;
-fx-border-radius: 0;
-fx-background-radius: 0;
}
.list-view {
-fx-background-color: transparent;
}
.list-cell {
-fx-background-color: #f4f4f4;
-fx-text-fill: black;
}
.list-cell:empty {
visibility: hidden;
}
.list-cell:hover {
-fx-background-color: derive(#c8c8c8, 50%);
}
.list-cell:filled:selected:focused {
-fx-background-color: #c8c8c8;
-fx-text-fill: black;
}
.split-pane > .split-pane-divider {
-fx-background-color: transparent;
}
.menu-button > .arrow-button {
-fx-padding: 0;
}
.menu-button > .arrow-button > .arrow {
-fx-padding: 0;
}
.track {
-fx-background-color: transparent;
}
.thumb {
-fx-pref-width: 10px;
-fx-background-color: derive(#969696, 50%);
-fx-background-radius: 0em;
}
.increment-arrow,
.decrement-arrow {
-fx-padding: 0;
}
.increment-button,
.decrement-button {
-fx-padding: 0 0 0 0;
}
.scroll-bar {
-fx-opacity: 0;
}
:hover .scroll-bar {
-fx-opacity: 1;
}
.list-view .scroll-bar,
.text-area .scroll-bar {
-fx-background-color: transparent;
}
.list-view .decrement-button {
-fx-padding: 0 10 0 0;
}
事件处理
重新实现第四篇【主界面】中的切换列表事件:
public void onChatClick(ActionEvent actionEvent) {
listVBox.getChildren().clear();
listVBox.getChildren().add(FXComponent.chatListController());
chatButton.setDisable(true);
contactsButton.setDisable(false);
}
缓存控件逻辑:
public static Parent chatListController() {
return cache.computeIfAbsent("chatListController", k -> FX.fxml(ChatListController.class));
}