本文是仿微信聊天程序专栏的第八篇文章,主要记录了【聊天窗口】的界面实现。
界面设计
聊天窗口是整个聊天程序的核心控件,比较复杂,大致可以分为上中下三个部分,上面显示用户昵称以及一些操作菜单,中间是聊天内容显示区域,下面的信息发送的区域,总体界面设计如下:
界面布局
根据界面设计的划分,将整个聊天窗口布局划分为上中下三个部分,中间使用WebView用于显示聊天内容,完整的fxml布局代码如下:
<StackPane prefHeight="610.0"
prefWidth="546.0" stylesheets="@ChatMainController.css"
xmlns:fx="http://javafx.com/fxml"
fx:controller="michong.javafx.wx.view.chat.ChatMainController">
<SplitPane dividerPositions="0.65" orientation="VERTICAL" styleClass="chat-main-pane">
<items>
<VBox>
<children>
<HBox alignment="CENTER" prefHeight="40.0" styleClass="chat-main-menu">
<children>
<Label fx:id="nicknameLabel" styleClass="name-label"/>
<Pane HBox.hgrow="ALWAYS"/>
<MenuButton styleClass="chat-main-menu-more">
<items>
<MenuItem text="清空" styleClass="chat-main-menu-item" onAction="#onClearClick"/>
<MenuItem text="关闭" styleClass="chat-main-menu-item" onAction="#onCloseClick"/>
</items>
</MenuButton>
</children>
<padding>
<Insets left="20.0" right="5.0"/>
</padding>
</HBox>
<Separator styleClass="wx-separator"/>
<!--<Pane VBox.vgrow="ALWAYS"/>-->
<WebView fx:id="chatWebView" VBox.vgrow="ALWAYS"/>
</children>
</VBox>
<VBox alignment="TOP_RIGHT" styleClass="chat-main-input">
<children>
<HBox spacing="10.0">
<children>
<Button styleClass="face-button"/>
<Button styleClass="message-button"/>
<Pane HBox.hgrow="ALWAYS"/>
<Button styleClass="audio-button"/>
<Button styleClass="video-button"/>
</children>
<padding>
<Insets bottom="5.0" left="20.0" right="20.0" top="5.0"/>
</padding>
</HBox>
<StackPane VBox.vgrow="ALWAYS">
<children>
<TextArea fx:id="messageTextArea" wrapText="true"/>
</children>
<padding>
<Insets bottom="5.0" left="20.0" right="20.0" top="5.0"/>
</padding>
</StackPane>
<ButtonBar prefHeight="80.0">
<buttons>
<Button styleClass="wx-btn-send" text="发送(S)" onAction="#onSendClick"/>
</buttons>
<padding>
<Insets bottom="5.0" right="20.0" top="5.0"/>
</padding>
</ButtonBar>
</children>
</VBox>
</items>
</SplitPane>
</StackPane>
样式美化
跟其他界面一样,JavaFX默认提供的控件样式风格跟聊天程序并不搭,所以聊天窗口仍需要进行样式美化,完整的CSS代码如下:
.chat-main-pane {
-fx-background-color: #fafafa;
-fx-border-color: transparent;
}
.chat-main-pane .button {
-fx-cursor: hand;
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-pref-width: 30px;
-fx-pref-height: 30px;
-fx-background-size: 30px 30px;
}
.chat-main-menu {
-fx-background-color: #fafafa;
}
.name-label {
-fx-font-size: 20px;
-fx-text-fill: black;
}
.chat-main-menu-more {
-fx-cursor: hand;
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-pref-width: 44px;
-fx-pref-height: 30px;
-fx-background-size: 44px 30px;
-fx-background-image: url("/icon/more.png");
}
.chat-main-menu-item {
-fx-padding: 5 0 5 5;
}
.chat-main-menu-item:hover,
.chat-main-menu-item:focused {
-fx-cursor: hand;
-fx-background-color: #dbd9d8;
}
.chat-main-menu-item:hover .label,
.chat-main-menu-item:focused .label {
-fx-text-fill: black;
}
.separator .line {
-fx-border-color: derive(#eee9e9, 20%);
-fx-border-width: 1;
}
.chat-main-input > * {
-fx-background-color: #ffffff;
}
.face-button {
-fx-background-image: url("/icon/face_0.png");
}
.face-button:hover {
-fx-background-image: url("/icon/face_1.png");
}
.message-button {
-fx-background-image: url("/icon/message_0.png");
}
.message-button:hover {
-fx-background-image: url("/icon/message_1.png");
}
.audio-button {
-fx-background-image: url("/icon/audio_0.png");
}
.audio-button:hover {
-fx-background-image: url("/icon/audio_0.png");
}
.video-button {
-fx-background-image: url("/icon/video_0.png");
}
.video-button:hover {
-fx-background-image: url("/icon/video_0.png");
}
.send-button {
-fx-padding: 5px 10px;
-fx-font-size: 12px;
-fx-background-color: #f5f5f5;
}
.send-button:hover {
-fx-cursor: hand;
-fx-text-fill: #ffffff;
-fx-background-color: #5cb85c;
-fx-border-color: #4cae4c;
}
.text-area {
-fx-font-size: 14px;
-fx-padding: 0;
-fx-cursor: default;
-fx-background-color: #ffffff;
}
.text-area .content {
-fx-cursor: text;
-fx-background-color: #ffffff;
}
.text-area:focused .content {
-fx-background-color: #ffffff;
}
逻辑控制
调整原来聊天列表的事件控制逻辑,当单击聊天列表项时显示聊天信息界面,这里只是静态显示,动态拉取聊天信息后续功能将继续完善,控制代码如下:
void initializeEvent() {
chatListView.getSelectionModel().selectedItemProperty().addListener((obj, ov, nv) -> {
if (Objects.nonNull(nv)) {
Pane main = FXComponent.mainComponent();
main.getChildren().clear();
main.getChildren().add(FXComponent.chatMainComponent(nv.getId()));
}
});
}
数据填充
跟好友信息的处理方式类似,这里直接给出Controller的代码:
/**
* @author michong
*/
public class ChatMainController implements UserDataController {
public Label nicknameLabel;
public WebView chatWebView;
public TextArea messageTextArea;
private Long contactsId;
@Override
public void initialize(Object data) {
contactsId = (Long) data;
initializeUI();
initializeEvent();
renderDebugData();
}
void initializeUI() {
}
void initializeEvent() {
}
void renderDebugData() {
nicknameLabel.setText("WxID: " + contactsId);
}
public void onClearClick(ActionEvent actionEvent) {
}
public void onCloseClick(ActionEvent actionEvent) {
}
public void onSendClick(ActionEvent actionEvent) {
}
}
更多细节,可以查看第7节【好友信息】的实现。