Snackbar
state'in snackbar'larını ekrana teker teker getirir: uygulamanın az önce yaptığı şeyi söyleyen kısa mesajlar, her biri en fazla bir eylemle ve nötr, birincil ya da anlam taşıyan bir tonda.
import com.pantrixui.components.overlay.snackbar.PantrixSnackbarHost
- Sırayla, teker teker. Ekranda tek bir snackbar olur; ötekiler istendikleri sırayla bekler.
showaskıda bekleyen bir fonksiyondur: snackbar gidince, nasıl gittiğini döndürür. - Bir eylem.
actionLabelsnackbar'a tek bir eylem koyar: "Geri al". Sonuç, eyleme basıldıysaSnackbarResult.ActionPerformed, değilseDismissedolur. - Süre. Eylemsiz snackbar dört saniyede gider (
Short);Longon saniyedir. Eylemli olan, eylem yapılana ya da kapatılana kadar kalır (UntilDismissed) ve bir kapatma düğmesi taşır. Fare üstündeyken ve odak içindeyken süre bekler, sonra baştan başlar. - Altı ton.
tonerengi, ikonu ve duyuruluşu birlikte seçer. Anlam taşıyan dört tonun (Info,Success,Warning,Danger) ikonu vardır;Primaryve varsayılanNeutralikonsuzdur. - Gitmenin yolları. Süresi dolar, eylemine ya da kapatma düğmesine basılır, yana kaydırılır, odak içindeyken Escape'e basılır, ekran okuyucunun kapatma eylemi kullanılır ya da uygulama onu kaldırır (
SnackbarData.dismiss). - Yeri platforma göre. Android'de alt kenarın ortasında, iOS'ta üstte, masaüstünde ve web'de alt son köşede çıkar:
SnackbarStyle.placement. Pencerenin güvenli alanının içinde kalır. - Renk sunucunundur.
SnackbarColorssnackbar'a değil sunucuya verilir ve o sunucunun her snackbar'ını boyar; ikon ve duyuruluş yine tondan gelir. - Dialog ve sheet'in altında. Snackbar uygulamanındır: sunucunun üstüne açılan bir dialog ya da sheet onu örter.
Örnekler
Bir mesaj
En az yazılan: bir mesaj. Kuyruk buraya parametreyle gelmez; scaffold onu LocalPantrixSnackbars ile içindeki her ekrana verir. show askıda bekleyen bir fonksiyondur, bu yüzden bir coroutine'in içinde çağrılır. Eylemsiz snackbar dört saniyede kendiliğinden gider.
Scope bu örneğindir (rememberCoroutineScope): sayfadan çıkılınca iptal olur ve ekrandaki snackbar'ı da götürür. Ekran değişse de kalması gereken bir snackbar, ekrandan uzun yaşayan bir scope'ta istenir. Scaffold'un dışında, kuyruğu veren kimse yokken, LocalPantrixSnackbars.current null'dır ve düğme bir şey yapmaz.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
PantrixButton(
text = "Taslağı kaydet",
onClick = { scope.launch { snackbars?.show(message = "Taslak kaydedildi", tagKey = "draft_saved") } },
variant = ButtonVariant.Outline,
tagKey = "save_draft"
)
Tonlar
Snackbar'ın altı tonu: her düğme uygulamanın kuyruğundan o tonda bir snackbar ister. tone temanın bir rolünün rengini, anlam taşıyan dört tonda bir ikonu ve duyuruluşu seçer: Danger ekran okuyucunun o an okuduğunu keser, ötekiler kesmeden duyurulur. Snackbar her tonda dolu çizilir: rolün soluk container'ı ile değil, color ve onColor'ı ile.
Eylemli olanlar eylem yapılana ya da kapatılana kadar kalır, eylemsizler dört saniyede kendiliğinden gider. Art arda basılan düğmelerin snackbar'ları sırayla, teker teker gelir. Her birinin nasıl gittiği düğmelerin altına yazılır.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
var lastResult by remember { mutableStateOf<String?>(null) }
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
SAMPLES.forEach { sample ->
PantrixButton(
text = sample.tone.name,
onClick = {
scope.launch {
val result = snackbars?.show(
message = sample.message,
actionLabel = sample.action,
tone = sample.tone,
tagKey = sample.tone.name.lowercase()
)
if (result != null) lastResult = "${sample.tone.name}: ${result.name}"
}
},
variant = ButtonVariant.Outline,
tagKey = "show_${sample.tone.name}"
)
}
}
lastResult?.let { result ->
PantrixText(
text = "Son snackbar → $result",
style = PantrixTheme.typography.footnote,
color = PantrixTheme.colors.textSecondary
)
}
private class SnackbarSample(
val tone: SnackbarTone,
val message: String,
val action: String?
)
private val SAMPLES = listOf(
SnackbarSample(SnackbarTone.Neutral, "Konuşma arşivlendi", "Geri al"),
SnackbarSample(SnackbarTone.Primary, "Yeni sürüm hazır", "Güncelle"),
SnackbarSample(SnackbarTone.Info, "Mobil veride senkronizasyon duraklar", null),
SnackbarSample(SnackbarTone.Success, "Değişiklikler kaydedildi", null),
SnackbarSample(SnackbarTone.Warning, "Depolama alanı dolmak üzere", "Yönet"),
SnackbarSample(SnackbarTone.Danger, "Yükleme başarısız oldu", "Tekrar dene")
)
Eylem ve sonucu
actionLabel snackbar'a tek bir eylem koyar. show, snackbar gidince nasıl gittiğini döndürür: eyleme basıldıysa SnackbarResult.ActionPerformed; süresi dolduysa, kapatıldıysa ya da uygulama onu kaldırdıysa Dismissed. "Geri al"a basılınca konuşma gelen kutusuna döner.
Eylemli snackbar kendiliğinden gitmez: birkaç saniye, bazı kullanıcıların eyleme ulaşmasına yetmez. Varsayılan süresi bu yüzden UntilDismissed'dır ve bir kapatma düğmesi taşır.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
var inbox by rememberSaveable { mutableIntStateOf(5) }
PantrixButton(
text = "Bir konuşmayı arşivle",
onClick = {
inbox -= 1
scope.launch {
val result = snackbars?.show(
message = "Konuşma arşivlendi",
actionLabel = "Geri al",
tagKey = "archived"
)
if (result == SnackbarResult.ActionPerformed) inbox += 1
}
},
enabled = inbox > 0,
variant = ButtonVariant.Outline,
tagKey = "archive"
)
PantrixText(text = "Gelen kutusu: $inbox konuşma", color = PantrixTheme.colors.textSecondary)
Süre ve kapatma düğmesi
duration, kimse bir şey yapmadığında snackbar'ın ne kadar kalacağını söyler: Short dört, Long on saniye; UntilDismissed kapatılana kadar. Platform, daha çok zamana ihtiyacı olan kullanıcı için süreyi uzatabilir. Kapatılana kadar kalan snackbar bir kapatma düğmesi taşır; closeButton = true onu kısa bir snackbar'a da koyar.
Fareyi snackbar'ın üstünde tut: süre bekler, fare çekilince baştan başlar. Klavye odağı içindeyken de bekler. Snackbar'ı yana kaydırmak onu süresini beklemeden gönderir.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
PantrixButton(
text = "Short",
onClick = {
scope.launch {
snackbars?.show(
message = "Bağlantı kopyalandı",
duration = SnackbarDuration.Short,
tagKey = "short"
)
}
},
variant = ButtonVariant.Outline,
tagKey = "show_short"
)
PantrixButton(
text = "Long",
onClick = {
scope.launch {
snackbars?.show(
message = "Dışa aktarma tamamlandı: dosya İndirilenler klasöründe",
duration = SnackbarDuration.Long,
tagKey = "long"
)
}
},
variant = ButtonVariant.Outline,
tagKey = "show_long"
)
PantrixButton(
text = "UntilDismissed",
onClick = {
scope.launch {
snackbars?.show(
message = "Güncelleme indirildi: yeniden başlatınca kurulacak",
duration = SnackbarDuration.UntilDismissed,
tagKey = "until_dismissed"
)
}
},
variant = ButtonVariant.Outline,
tagKey = "show_until_dismissed"
)
PantrixButton(
text = "Short, kapatma düğmesiyle",
onClick = {
scope.launch {
snackbars?.show(message = "Dosya çöp kutusuna taşındı", closeButton = true, tagKey = "with_close")
}
},
variant = ButtonVariant.Outline,
tagKey = "show_with_close"
)
}
Sırayla gelen snackbar'lar
Üç snackbar art arda istenir; ekrana istendikleri sırayla, teker teker gelirler. show kendi sırası gelene kadar askıda bekler. Sırayı uygulamanın tek kuyruğu tutar: başka bir örneğin istediği snackbar da aynı sıraya girer.
"Kalanlardan vazgeç" bu örneğin coroutine'lerini iptal eder: show'u çağıran coroutine iptal edilince ekrandaki snackbar gider, sırası gelmemiş olanlar hiç gösterilmez.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
PantrixButton(
text = "Üç dosya yükle",
onClick = {
listOf("Rapor.pdf", "Bütçe.xlsx", "Sunum.key").forEach { file ->
scope.launch {
snackbars?.show(message = "$file yüklendi", tone = SnackbarTone.Success, tagKey = "uploaded")
}
}
},
variant = ButtonVariant.Outline,
tagKey = "upload_three"
)
PantrixButton(
text = "Kalanlardan vazgeç",
onClick = { scope.coroutineContext.cancelChildren() },
variant = ButtonVariant.Text,
tagKey = "cancel_uploads"
)
}
Uygulamanın kaldırdığı snackbar
Kimi snackbar'ı kullanıcı değil uygulama kaldırır: bağlantı geri geldiğinde "Çevrimdışısın" demenin anlamı kalmaz. PantrixSnackbarState.current ekrandaki snackbar'dır, yoksa null; dismiss() onu götürür ve show, SnackbarResult.Dismissed döndürür. "Bağlantı geldi" yalnızca bu örneğin snackbar'ı ekrandayken açıktır.
Bu snackbar kapatılana kadar kalır ve kapatma düğmesi yoktur (closeButton = false); yana kaydırmak onu yine de gönderir.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
val onScreen = snackbars?.current
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
PantrixButton(
text = "Bağlantıyı kes",
onClick = {
scope.launch {
snackbars?.show(
message = "Çevrimdışısın: değişiklikler bağlantı gelince eşitlenecek",
duration = SnackbarDuration.UntilDismissed,
closeButton = false,
tone = SnackbarTone.Warning,
tagKey = "offline"
)
}
},
variant = ButtonVariant.Outline,
tagKey = "go_offline"
)
PantrixButton(
text = "Bağlantı geldi",
onClick = { onScreen?.dismiss() },
enabled = onScreen?.tagKey == "offline",
variant = ButtonVariant.Outline,
tagKey = "back_online"
)
}
Sunucuya verilen renk
Renk snackbar'a değil, onu gösteren sunucuya verilir: PantrixSnackbarHost(state, colors = SnackbarColors(container = …, content = …)). Uygulamanın sunucusu kökte durduğu için anahtarın durumu da oradadır, uygulamanın ayarlarında; sunucu ona bakar. Açıkken her snackbar aynı dolguyla çizilir; ikonu ve nasıl duyurulduğu yine tonundan gelir.
Anahtarı çevir, sonra buradan ya da "Tonlar"dan bir snackbar iste. Anahtar, snackbar'ın çıktığı kenardan uzak uçta durur: snackbar üstte çıkıyorsa (iOS) düğmenin altında, altta çıkıyorsa üstünde.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
val snackbarsAtTheTop = PantrixTheme.style(SnackbarStyle).placement == SnackbarPlacement.Top
if (!snackbarsAtTheTop) SnackbarOwnColorsSwitch()
PantrixButton(
text = "Yedeklemeyi bitir",
onClick = {
scope.launch {
snackbars?.show(message = "Yedekleme tamamlandı", tone = SnackbarTone.Success, tagKey = "backed_up")
}
},
variant = ButtonVariant.Outline,
tagKey = "back_up"
)
if (snackbarsAtTheTop) SnackbarOwnColorsSwitch()
@Composable
private fun SnackbarOwnColorsSwitch() {
val settings = LocalDemoSettings.current
PantrixSwitchButton(
checked = settings.ownSnackbarColors,
onCheckedChange = { settings.ownSnackbarColors = it },
label = "Uygulamanın kendi renginde",
supportingText = "Açıkken snackbar'lar tonlarının değil, sunucularına verilen rengin dolgusuyla çizilir",
tagKey = "own_snackbar_colors"
)
}
Kendi sunucusu: yer, stil ve renk
Sunucu çoğunlukla uygulamanın kökünde tek bir tanedir. Burada, parametrelerinin ne yaptığını göstermek için, bir kutunun içinde kendi kuyruğuyla ikinci bir sunucu var: rememberPantrixSnackbarState kuyruğu verir, PantrixSnackbarHost onu gösterir. Sunucu kutunun son çocuğudur: verilen yeri doldurur ve içeriğin üstünde durur.
style yeri ve geometriyi değiştirir: placement dört yerden birini seçer, maxWidth snackbar'ı 320dp'de tutar. Dar bir kutuda snackbar kutuyu doldurur; baş, orta ve son yalnızca geniş bir kutuda ayrılır. colors bu sunucunun her snackbar'ını boyar: dolgu uygulamanın kendi moru, ikon yine tonun.
Sunucu pencerenin güvenli alanının içinde kalır. Bu kutu pencerenin ortasında durduğu için o payları kendisi tüketir (consumeWindowInsets); kökteki bir sunucuda buna gerek yoktur.
Kuyruğun gösterdiği snackbar current'tır (SnackbarData): kutunun altındaki satır mesajını yazar ve "Kaldır" onu dismiss() ile kapatır, süresini beklemeden.
val snackbars = rememberPantrixSnackbarState()
val scope = rememberCoroutineScope()
val own = ownColors()
var placement by rememberSaveable { mutableStateOf(SnackbarPlacement.BottomCenter) }
PantrixSegmentButton(
options = PLACEMENTS,
selected = placement,
onSelect = { placement = it },
tagKey = "placement"
)
PantrixSurface(
modifier = Modifier
.fillMaxWidth()
.height(220.dp)
.consumeWindowInsets(WindowInsets.safeDrawing),
border = PantrixTheme.colors.divider
) {
PantrixButton(
text = "Bu kutuda göster",
onClick = {
scope.launch {
snackbars.show(message = "Kutunun kendi snackbar'ı", tone = SnackbarTone.Success, tagKey = "boxed")
}
},
modifier = Modifier.align(Alignment.Center),
variant = ButtonVariant.Outline,
tagKey = "show_boxed"
)
PantrixSnackbarHost(
state = snackbars,
style = SnackbarStyle(placement = placement, maxWidth = 320.dp),
colors = SnackbarColors(container = own.color, content = own.onColor)
)
}
val shown: SnackbarData? = snackbars.current
PantrixText(
text = shown?.let { "Kutuda: ${it.message}" } ?: "Kutuda snackbar yok",
style = PantrixTheme.typography.footnote,
color = PantrixTheme.colors.textSecondary
)
if (shown != null) {
PantrixButton(
text = "Kaldır",
onClick = shown::dismiss,
variant = ButtonVariant.Outline,
size = ButtonSize.Small,
tagKey = "dismiss_boxed"
)
}
private val PLACEMENTS = listOf(
SegmentOption(value = SnackbarPlacement.Top, label = "Üst", tagKey = "top"),
SegmentOption(value = SnackbarPlacement.BottomStart, label = "Alt baş", tagKey = "bottom_start"),
SegmentOption(value = SnackbarPlacement.BottomCenter, label = "Alt orta", tagKey = "bottom_center"),
SegmentOption(value = SnackbarPlacement.BottomEnd, label = "Alt son", tagKey = "bottom_end")
)
API
state
state'in snackbar'larını ekrana teker teker getirir: uygulamanın az önce yaptığı şeyi söyleyen kısa mesajlar, her biri en fazla bir eylemle ve nötr, birincil ya da anlam taşıyan bir tonda.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
state | PantrixSnackbarState | Gösterilecek snackbar'lar; PantrixSnackbarState.show bir tane ister. | |
modifier | Modifier | Modifier | Sunucunun modifier'ı. Sunucu kendisine verilen yeri doldurur. |
style | SnackbarStyle? | null | Bu çağrının kendi stili: çevresindeki her stili ezer, yoğunluk ona da uygulanır. Yalnızca verdiği alanlar değişir ve her platformda değişir. |
colors | SnackbarColors? | null | Bu sunucunun gösterdiği her snackbar'ın renkleri, tonlarınınki kullanılmayacaksa: burada verilenler kullanılır, gerisi tonun kalır. |
SnackbarStyle
PantrixSnackbarHost'un snackbar'larını gösterdiği yer ve o snackbar'ların geometrisi.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
placement | SnackbarPlacement? | null | Sunucunun snackbar'larını gösterdiği yer: Android'de alt kenarın ortasında, iOS'ta üstte, masaüstünde ve web'de alt son köşede. |
shape | ShapeSpec | ShapeSpec.Unspecified | Snackbar'ın köşeleri: Android'de, masaüstünde ve web'de en küçük, iOS'ta büyük. |
maxWidth | Dp | Dp.Unspecified | Bir snackbar'ın en çok genişliği. Daha dar bir sunucuda, kenar payı dışında sunucunun tamamına yayılır. |
minHeight | Dp | Dp.Unspecified | Mesajı tek satıra sığan bir snackbar'ın yüksekliği. |
margin | Dp | Dp.Unspecified | Snackbar ile sunucunun kenarları arasında, pencerenin güvenli alanının içinde açık bırakılan pay. |
elevation | Dp | Dp.Unspecified | Snackbar'ın, uygulamanın üstünde ne kadar yüksekte durduğu, yani gölgesinin ne kadar büyük olduğu. |
SnackbarColors
Tonlarının renklerini almayan bir sunucu için, bir PantrixSnackbarHost'un snackbar'larının boyandığı renkler: verilen renk sunucunun her snackbar'ında kullanılır, verilmeyen tonun kalır.
| Parametre | Tür | Varsayılan | Ne olduğu |
|---|---|---|---|
container | Color | Color.Unspecified | Snackbar'ın dolgusu. Tonunun rolünün color'ı. |
content | Color | Color.Unspecified | Mesaj, ikon, eylemin etiketi ve kapatma düğmesinin çarpısı: container'ın üstünde okunan renk. Tonunun rolünün onColor'ı. |
Erişilebilirlik
- Ekran okuyucu. Snackbar, okunanı kesmeden duyurulur; yalnızca
Dangertonu araya girer.