JavaFX - Различные макеты в пользовательском ListCell

Я создаю приложение чата с использованием JavaFX. Теперь для отображения сообщений чата я использую простуюListView изChatItemс фабрикой пользовательских ячеек,ChatCell.

ChatItem может бытьChatLabel (серверные объявления, изменение статуса и т. д.) илиChatMessage (сообщение отправлено самим или другими сторонами). А такжеChatMessage может быть расширен для показа различного контента (простоChatTextMessage а такжеChatImageMessage теперь)

Моя настраиваемая ячейка проверяет тип / характеристики элемента и соответственно отображает правильный вид.

Я хотел бы показать отметку времени на каждомChatMessage вид в правом нижнем углу пузыря чата. НО, если текст состоит только из одной строки, я хочу, чтобы отметка времени отображалась на дополнительном месте справа от текста. (вроде чата WhatsApp или большинства приложений чата).

Вот демо:

Моя текущая реализация (показанная в демонстрации) использует логическое свойство вChatMessage это определяет, должно ли представление быть многострочным или нет. Он проверяет это при каждом обновлении. Я также добавляю слушателяListView ширина и вызовrefresh() когда это изменится. Все это кажется чрезмерным. И я не думаю, что добавление «связанных с видом» свойств к «модели» - это хороший дизайн. Не говоря уже о том, что при первом обновлении элемента временная метка по какой-то причине находится не в правильном месте.

Как я могу сделать это правильно?

ОБНОВЛЕНИЕ 1: Я добавил экстрактор свойств дляListView элементы, и добавил слушателя дляListView ширина, которая вызываетupdateItem по ширине меняется. Теперь мне не нужно звонитьrefresh()

ВотChatCell учебный класс:

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;
    }

}

Ответы на вопрос(0)

Ваш ответ на вопрос