Simge düğmeleri

Simge düğmeleri, kullanıcıların yapabileceği işlemleri gösterir. Simge düğmelerinde anlamı net olan bir simge kullanılmalı ve genellikle yaygın veya sık kullanılan işlemler temsil edilmelidir.

İki tür simge düğmesi vardır:

  • Varsayılan: Bu düğmeler, menü veya arama gibi diğer öğeleri açabilir.
  • Açma/kapatma: Bu düğmeler, "favori" veya "yer işareti" gibi açılıp kapatılabilen ikili işlemleri temsil edebilir.
Farklı simgeler (ayarlar, daha fazla vb.) içeren 5 simge düğmesi. Bazıları seçimi belirtmek için doldurulmuş, bazıları ise ana hatlarıyla gösterilmiştir.
Şekil 1. Bazıları içi dolu (seçimi gösterir) ve dış çizgili olan simge düğmeleri.

API yüzeyi

Standart simge düğmeleri uygulamak için IconButton composable'ını kullanın. Dolgulu, dolgulu tonlu veya ana hatlı gibi farklı görsel stiller oluşturmak için sırasıyla FilledIconButton, FilledTonalIconButton ve OutlinedIconButton kullanın.

IconButton için temel parametreler şunlardır:

  • onClick: Kullanıcı simge düğmesine dokunduğunda yürütülen bir lambda işlevi.
  • enabled: Düğmenin etkinleştirilme durumunu kontrol eden bir boole değeri. false olduğunda düğme, kullanıcı girişine yanıt vermiyor.
  • content: Düğmenin içindeki birleştirilebilir içerik (genellikle Icon).

Temel örnek: Açma/kapatma simge düğmesi

Bu örnekte, açma/kapatma simgesi düğmesinin nasıl uygulanacağı gösterilmektedir. Açma/kapatma simgesi düğmesi, seçili olup olmamasına göre görünümünü değiştirir.

@Preview
@Composable
fun ToggleIconButtonExample() {
    // isToggled initial value should be read from a view model or persistent storage.
    var isToggled by rememberSaveable { mutableStateOf(false) }

    IconButton(
        onClick = { isToggled = !isToggled }
    ) {
        Icon(
            painter = if (isToggled) painterResource(R.drawable.favorite_filled) else painterResource(R.drawable.favorite),
            contentDescription = if (isToggled) "Selected icon button" else "Unselected icon button."
        )
    }
}

Kodla ilgili önemli noktalar

  • ToggleIconButtonExample composable'ı, açılıp kapatılabilen bir IconButton tanımlar.
    • mutableStateOf(false), başlangıçta false olan bir boole değeri barındıran MutableState nesnesi oluşturur. Bu sayede isToggled, durum bilgisi depolayıcı olur. Yani Compose, değeri her değiştiğinde kullanıcı arayüzünü yeniden oluşturur.
    • rememberSaveable, ekran döndürme gibi yapılandırma değişikliklerinde isToggled durumunun korunmasını sağlar.
  • IconButton öğesinin onClick lambda'sı, tıklandığında düğmenin davranışını tanımlayarak durumu true ile false arasında değiştirir.
  • Icon composable'ının painter parametresi, isToggled durumuna göre koşullu olarak farklı bir painterResource yükler. Bu işlem, simgenin görsel görünümünü değiştirir.
    • isToggled, true ise içi dolu kalp çizilebilir öğesini yükler.
    • isToggled, false ise içi boş kalp çizimini yükler.
  • Icon öğesinin contentDescription değeri de uygun erişilebilirlik bilgilerini sağlamak için isToggled durumuna göre güncellenir.

Sonuç

Aşağıdaki resimde, önceki snippet'teki açma/kapatma simgesi düğmesinin seçili olmayan durumu gösterilmektedir:

Seçili olmayan durumda (içi boş) bir favori açma/kapatma simgesi düğmesi (kalp).
Şekil 2. "Favori" açma/kapatma simge düğmesi, seçili değil.

Gelişmiş örnek: Basıldığında tekrarlanan işlemler

Bu bölümde, kullanıcıların yalnızca bir kez tıklamak yerine basılı tutarak sürekli olarak bir işlemi tetikleyen simge düğmelerinin nasıl oluşturulacağı gösterilmektedir.

@Composable
fun MomentaryIconButton(
    unselectedImage: Int,
    selectedImage: Int,
    contentDescription: String,
    modifier: Modifier = Modifier,
    stepDelay: Long = 100L, // Minimum value is 1L milliseconds.
    onClick: () -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    val isPressed by interactionSource.collectIsPressedAsState()
    val pressedListener by rememberUpdatedState(onClick)

    LaunchedEffect(isPressed) {
        while (isPressed) {
            delay(stepDelay.coerceIn(1L, Long.MAX_VALUE))
            pressedListener()
        }
    }

    IconButton(
        modifier = modifier,
        onClick = onClick,
        interactionSource = interactionSource
    ) {
        Icon(
            painter = if (isPressed) painterResource(id = selectedImage) else painterResource(id = unselectedImage),
            contentDescription = contentDescription,
        )
    }
}

Kodla ilgili önemli noktalar

  • MomentaryIconButton, düğmeye basılmadığında simgenin drawable kaynak kimliği olan unselectedImage: Int ve düğmeye basıldığında simgenin drawable kaynak kimliği olan selectedImage: Int değerlerini alır.
  • Kullanıcının "basma" etkileşimlerini özel olarak izlemek için interactionSource kullanır.
  • isPressed, düğmeye basıldığında doğru, aksi takdirde yanlış değerini alır. isPressed, true olduğunda LaunchedEffect bir döngüye girer.
    • Bu döngüde, tetikleme işlemleri arasında duraklamalar oluşturmak için delay (stepDelay ile) kullanılır. coerceIn, sonsuz döngüleri önlemek için gecikmenin en az 1 ms olmasını sağlar.
    • pressedListener, döngüdeki her gecikmeden sonra çağrılır. Bu işlem, eylemin tekrarlanmasını sağlar.
  • pressedListener, onClick lambda'nın (gerçekleştirilecek işlem) her zaman en son oluşturmadan gelen en güncel lambda olmasını sağlamak için rememberUpdatedState kullanır.
  • Icon, görüntülenen resmini düğmenin basılı olup olmamasına göre değiştirir.
    • isPressed doğruysa selectedImage gösterilir.
    • Aksi takdirde unselectedImage gösterilir.

Şimdi bu MomentaryIconButton kelimesini örnek cümle içinde kullanın. Aşağıdaki snippet'te, bir sayacı kontrol eden iki simge düğmesi gösterilmektedir:

@Preview()
@Composable
fun MomentaryIconButtonExample() {
    var pressedCount by remember { mutableIntStateOf(0) }

    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_rewind,
            selectedImage = R.drawable.fast_rewind_filled,
            stepDelay = 100L,
            onClick = { pressedCount -= 1 },
            contentDescription = "Decrease count button"
        )
        Spacer(modifier = Modifier)
        Text("advanced by $pressedCount frames")
        Spacer(modifier = Modifier)
        MomentaryIconButton(
            unselectedImage = R.drawable.fast_forward,
            selectedImage = R.drawable.fast_forward_filled,
            contentDescription = "Increase count button",
            stepDelay = 100L,
            onClick = { pressedCount += 1 }
        )
    }
}

Kodla ilgili önemli noktalar

  • MomentaryIconButtonExample composable'ı, iki MomentaryIconButton örneği ve bir Text composable'ı içeren bir Row göstererek sayacı artırıp azaltmak için bir kullanıcı arayüzü oluşturur.
  • remember ve mutableIntStateOf kullanarak pressedCount değişken durum değişkenini korur ve 0 olarak başlatılır. pressedCount değiştiğinde, bunu gözlemleyen tüm composable'lar (ör. Text composable'ı) yeni değeri yansıtacak şekilde yeniden oluşturulur.
  • İlk MomentaryIconButton, tıklandığında veya basılı tutulduğunda pressedCount değerini azaltır.
  • İkinci MomentaryIconButton, tıklandığında veya basılı tutulduğunda pressedCount artırır.
  • Her iki düğme de 100 milisaniyelik bir stepDelay kullanır. Yani düğme basılı tutulurken onClick işlemi her 100 milisaniyede bir tekrarlanır.

Sonuç

Aşağıdaki videoda, simge düğmeleri ve sayaç içeren kullanıcı arayüzü gösterilmektedir:

Şekil 3. İki simge düğmesi (artı ve eksi) bulunan bir sayaç kullanıcı arayüzü. Bu düğmeler sayacı artırır ve azaltır.

Ek kaynaklar