Aller au contenu principal

Recette — Card sticky + contenu scrollable

Un écran avec une card d'informations épinglée en haut (toujours visible) et une zone de contenu scrollable en dessous. Modèle typique : profil avec onglets et historique long, tableau de bord avec stats fixes et logs défilants.


Ce que tu vas construire

┌─────────────────────────────┐
│ Titre du panneau │
│─────────────────────────────│
│ ┌─────────────────────┐ │ ← Card sticky (toujours visible)
│ │ Clan : Les Loups │ │
│ │ Rang : #2 │ │
│ └─────────────────────┘ │
│ ┌─────────────────────┐ │ ← ScrollableColumn (défile)
│ │ [Action 1] │ │
│ │ [Action 2] │ │
│ │ [Action 3] │ │
│ │ [Action 4] │ │
│ │ [Action 5] │ │
│ └─────────────────────┘ │
│ ░░░░░░░░░░░░░░░░░░░░░░░░░ │ ← contenu caché, accessible à la molette
└─────────────────────────────┘

La Card est partie de la Column root (donc toujours visible). La ScrollableColumn a une hauteur fixe — seul son contenu défile.


Code complet

package ca.monmod.client.screen;

import ca.tawess123.apocalyinterface.api.data.DataSource;
import ca.tawess123.apocalyinterface.api.layout.Card;
import ca.tawess123.apocalyinterface.api.layout.Column;
import ca.tawess123.apocalyinterface.api.layout.Row;
import ca.tawess123.apocalyinterface.api.layout.ScrollableColumn;
import ca.tawess123.apocalyinterface.api.layout.Spacer;
import ca.tawess123.apocalyinterface.api.screen.ApocalyScreen;
import ca.tawess123.apocalyinterface.api.theme.ApocalyDimensions;
import ca.tawess123.apocalyinterface.api.widget.Button;
import ca.tawess123.apocalyinterface.api.widget.KeyValueRow;
import ca.tawess123.apocalyinterface.api.widget.Label;
import ca.tawess123.apocalyinterface.api.widget.TabBar;
import net.minecraft.network.chat.Component;

public final class ClanDashboardScreen extends ApocalyScreen {

// Données reçues du serveur
private final String clanName;
private final String rang;
private final int points;
private final int membres;

// Onglet actif (0 = actions, 1 = stats)
private int activeTab = 0;

// Zone défilante — construite une seule fois dans le constructeur
private final ScrollableColumn actionsScroll;
private final ScrollableColumn statsScroll;

// fixedHeight = 5 éléments × 20 px + 4 gaps × 4 px = 116 px
private static final int SCROLL_H =
5 * ApocalyDimensions.BUTTON_HEIGHT + 4 * Column.DEFAULT_GAP;

public ClanDashboardScreen(String clanName, String rang, int points, int membres) {
super(Component.translatable("monmod.screen.dashboard"), 260);
this.clanName = clanName;
this.rang = rang;
this.points = points;
this.membres = membres;

// ── Zone d'actions (onglet 0) ──────────────────────────────────────
actionsScroll = ScrollableColumn.builder().fixedHeight(SCROLL_H).build();
actionsScroll.add(Button.builder().text("monmod.btn.info").command("clan info").build());
actionsScroll.add(Button.builder().text("monmod.btn.banque").command("clan bank").build());
actionsScroll.add(Button.builder().text("monmod.btn.rewards").command("clan rewards").build());
actionsScroll.add(Button.builder().text("monmod.btn.claim").command("clan claim").build());
actionsScroll.add(Button.builder().text("monmod.btn.upgrades").command("clan upgrade").build());
actionsScroll.add(Button.builder().text("monmod.btn.rallye").command("clan rally").build());
actionsScroll.add(Button.builder().text("monmod.btn.admin").command("clanadmin zone gui").build());

// ── Zone de stats (onglet 1) ────────────────────────────────────────
statsScroll = ScrollableColumn.builder().fixedHeight(SCROLL_H).build();
statsScroll.add(buildStatRow("monmod.row.kills", "128"));
statsScroll.add(buildStatRow("monmod.row.morts", "34"));
statsScroll.add(buildStatRow("monmod.row.zones", "3"));
statsScroll.add(buildStatRow("monmod.row.victoires","21"));
statsScroll.add(buildStatRow("monmod.row.defaites", "9"));
statsScroll.add(buildStatRow("monmod.row.kd", "3.76"));
}

@Override
protected void buildLayout(Column root) {
// ── Card épinglée : toujours visible ──────────────────────────────
root.add(Card.create()
.add(Label.builder()
.text("monmod.label.clan")
.value(DataSource.of(clanName))
.title()
.build())
.add(Row.create()
.add(Label.builder()
.text("monmod.label.rang")
.value(DataSource.of(rang))
.build())
.add(Label.builder()
.text("monmod.label.membres")
.value(DataSource.of(membres + " membres"))
.build()))
.add(Label.builder()
.text("monmod.label.points")
.value(DataSource.of(points + " pts"))
.muted()
.build()));

root.add(Spacer.of(4));

// ── TabBar ─────────────────────────────────────────────────────────
root.add(TabBar.builder()
.tab("monmod.tab.actions", () -> { activeTab = 0; init(); })
.tab("monmod.tab.stats", () -> { activeTab = 1; init(); })
.activeTab(activeTab)
.build());

root.add(Spacer.of(4));

// ── Zone défilante selon l'onglet actif ────────────────────────────
root.add(actionsScroll.visibleIf(activeTab == 0));
root.add(statsScroll .visibleIf(activeTab == 1));
}

private static KeyValueRow buildStatRow(String key, String value) {
return KeyValueRow.builder()
.key(key)
.value(DataSource.of(value))
.build();
}
}
ScrollableColumn.visibleIf() après build()

Dans l'exemple ci-dessus, .visibleIf() est appelé sur l'instance après build() (pas dans le builder). Vérifie que l'implémentation expose cette méthode d'instance — sinon, enveloppe dans une Column avec .visible().


Ouvrir l'écran

Minecraft.getInstance().execute(() ->
Minecraft.getInstance().setScreen(
new ClanDashboardScreen("Les Loups", "#2", 4200, 8)
)
);

Clés i18n requises

{
"monmod.screen.dashboard": "Dashboard de Clan",
"monmod.label.clan": "Clan : %s",
"monmod.label.rang": "Rang : %s",
"monmod.label.membres": "%s",
"monmod.label.points": "Points : %s",
"monmod.tab.actions": "Actions",
"monmod.tab.stats": "Statistiques",
"monmod.btn.info": "Mon Clan",
"monmod.btn.banque": "Banque",
"monmod.btn.rewards": "Récompenses",
"monmod.btn.claim": "Capturer zone",
"monmod.btn.upgrades": "Améliorations",
"monmod.btn.rallye": "Ralliement",
"monmod.btn.admin": "Admin zone",
"monmod.row.kills": "Kills",
"monmod.row.morts": "Morts",
"monmod.row.zones": "Zones contrôlées",
"monmod.row.victoires": "Victoires",
"monmod.row.defaites": "Défaites",
"monmod.row.kd": "K/D"
}

Variante — sans onglets (card + liste unique)

Si tu n'as pas besoin d'onglets, simplifier directement :

@Override
protected void buildLayout(Column root) {
root.add(infoCard);
root.add(Spacer.of(4));
root.add(actionsList); // ScrollableColumn construite dans le constructeur
}

C'est la version la plus simple — c'est aussi ce que fait la recette hub à boutons.


Voir aussi