JavaFX - Verschiedene Layouts in einer benutzerdefinierten ListCell

Ich erstelle eine Chat-App mit JavaFX. Jetzt für die Anzeige von Chat-Nachrichten verwende ich ein einfachesListView vonChatItems mit einer benutzerdefinierten Zellenfactory,ChatCell.

ChatItem könnte ein @ seChatLabel (Serverankündigungen, Statusänderung usw.) oder einChatMessage (Nachricht von sich selbst oder anderen Parteien gesendet). UndChatMessage kann erweitert werden, um verschiedene Inhalte anzuzeigen (nurChatTextMessage undChatImageMessage zur Zeit

Meine benutzerdefinierte Zelle überprüft den Typ / die Merkmale des Elements und bietet die entsprechende Ansicht.

Ich möchte auf jedem @ einen Zeitstempel anzeigChatMessage view in der rechten unteren Ecke der Chat-Blase. ABER wenn der Text nur aus einer Zeile besteht, soll der Zeitstempel in einem zusätzlichen Leerzeichen rechts vom Text angezeigt werden. (ein bisschen wie WhatsApp-Chat oder die meisten Chat-Apps).

Hier ist eine Demo:

Meine aktuelle Implementierung (in der Demo gezeigt) verwendet eine boolesche Eigenschaft inChatMessage das bestimmt, ob die Ansicht mehrzeilig sein soll oder nicht. Es überprüft es bei jedem Update. Ich füge @ auch einen Listener hinListView width und callrefresh() wenn es sich ändert. All dies scheint übertrieben. Und ich denke nicht, dass das Hinzufügen einer "ansichtsbezogenen" Eigenschaft zu einem "Modell" ein gutes Design ist. Ganz zu schweigen davon, dass der Zeitstempel bei der ersten Artikelaktualisierung aus irgendeinem Grund nicht an der richtigen Stelle ist.

Wie kann ich das richtig machen?

UPDATE 1: Ich habe einen Eigenschaftsextraktor für das @ hinzugefüListView items und fügte einen Listener für das @ hinListView width die @ aufruupdateItem bei Breitenänderungen. Jetzt muss ich nicht mehr @ anrufrefresh()

Hier istChatCell Klasse:

public class ChatCell extends ListCell<ChatItem> {

    private ChatItemView view;
    private InvalidationListener listViewListener;
    private InvalidationListener listViewWidthListener;

    public ChatCell() {
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

        listViewWidthListener = e -> {
            updateItem(getItem(), isEmpty());
        };

        listViewListener = e -> {
            if(getView() == null) return;
            getView().unbindWidth();
            if(listViewProperty().get() != null) {
                getView().bindWidth(listViewProperty().get().widthProperty());
                listViewProperty().get().widthProperty().addListener(listViewWidthListener);
                listViewWidthListener.invalidated(listViewProperty().get().widthProperty());
            }
        };

    }

    public ChatItemView getView() {
        return view;
    }

    private void initChatLabelView() {
        view = new ChatLabelView();
    }

    private void initChatMessageView(ChatMessage message) {
        view = new ChatMessageViewWrapper(message);
    }


    private void resetView() {
        if(view == null) return;
        view.unbindWidth();
        listViewProperty().removeListener(listViewListener);
        if(getListView() != null)
            getListView().widthProperty().removeListener(listViewWidthListener);
        view = null;
    }

    private void newViewCreated() {
        listViewProperty().addListener(listViewListener);
        setGraphic(view);
        listViewListener.invalidated(listViewProperty());
    }

    @Override
    protected void updateItem(ChatItem item, boolean empty) {
        super.updateItem(item, empty);
        if(item == null || empty) {
            setGraphic(null);
            setText(null);
            resetView();
        } else {
            // First-level comparison: Label vs. Message
            if(item.getViewType() == ViewType.LABEL) {
                if(view == null || !(view instanceof ChatLabelView)) {
                    resetView();
                    initChatLabelView();
                    newViewCreated();
                }

            }

            else if(item.getViewType() == ViewType.MESSAGE) {
                ChatMessage message = (ChatMessage) item;
                if(view == null || !(view instanceof ChatMessageViewWrapper)) {
                    resetView();
                    initChatMessageView(message);
                    newViewCreated();
                }
                else {
                    ChatMessageViewWrapper bubble = (ChatMessageViewWrapper) view;
                    // Second-level comparison: Self-message vs. other user message,
                    // Text vs. Image (or file), multiline vs. oneline 
                    if(  (bubble.getContentType() != message.getContentType())
                            || (bubble.isSelf() ^ message.isSelf()) 
                            || (bubble.isMultiline() ^ message.isMultiline())) {
                        resetView();
                        initChatMessageView(message);
                        newViewCreated();
                    }

                }

            }

            else {
                return;
            }

            view.setItem(item);
        }
    }

    @Override
    public Orientation getContentBias() {
        return Orientation.HORIZONTAL;
    }

}

Antworten auf die Frage(0)

Ihre Antwort auf die Frage