Oluşturma değiştiriciler

Değiştiriciler, composable'ları süslemenize veya geliştirmenize olanak tanır. Değiştiriciler, aşağıdaki gibi şeyleri yapmanıza olanak tanır:

  • composable'ın boyutunu, düzenini, davranışını ve görünümünü değiştirin
  • Erişilebilirlik etiketleri gibi bilgiler ekleyin
  • Kullanıcı girişini işle
  • Bir öğeyi tıklanabilir, kaydırılabilir, sürüklenebilir veya yakınlaştırılabilir hale getirmek gibi üst düzey etkileşimler ekleme

Değiştiriciler standart Kotlin nesneleridir. Modifier sınıf işlevlerinden birini çağırarak bir değiştirici oluşturun:

@Composable
private fun Greeting(name: String) {
    Column(modifier = Modifier.padding(24.dp)) {
        Text(text = "Hello,")
        Text(text = name)
    }
}

Metnin etrafına dolgulu, renkli bir arka plan üzerinde iki satırlık metin.

Bu işlevleri oluşturmak için zincir halinde kullanabilirsiniz:

@Composable
private fun Greeting(name: String) {
    Column(
        modifier = Modifier
            .padding(24.dp)
            .fillMaxWidth()
    ) {
        Text(text = "Hello,")
        Text(text = name)
    }
}

Metnin arkasındaki renkli arka plan artık cihazın tam genişliğini kaplar.

Yukarıdaki kodda, farklı değiştirici işlevlerinin birlikte kullanıldığına dikkat edin.

  • padding bir öğenin etrafına boşluk yerleştirir.
  • fillMaxWidth, composable'ın üst öğesinden kendisine verilen maksimum genişliği doldurmasını sağlar.

En iyi uygulama olarak tüm composable'larınızın bir modifier parametresini kabul etmesi ve bu değiştiriciyi, kullanıcı arayüzü yayınlayan ilk alt öğesine iletmeniz önerilir. Bu, kodunuzu daha fazla yeniden kullanılabilir hale getirir ve davranışını daha tahmin edilebilir ve sezgisel hale getirir. Daha fazla bilgi için Compose API yönergelerine bakın ve Öğeler Değiştirici parametreyi kabul eder ve bu parametreyi dikkate alır.

Değiştiricilerin sırası önemlidir

Değiştirici işlevlerin sırası anlamlıdır. Her işlev, önceki işlev tarafından döndürülen Modifier üzerinde değişiklikler yaptığından, sıra nihai sonucu etkiler. Bunun bir örneğini inceleyelim:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

Kenarların çevresindeki dolgu da dahil olmak üzere alanın tamamı tıklamalara yanıt verir

Yukarıdaki kodda, padding değiştiricisi clickable değiştiriciden sonra uygulandığından alanın tamamını çevreleyen dolgu da dahil olmak üzere tıklanabilir özelliktedir. Değiştiricilerin sırası ters çevrilirse padding tarafından eklenen boşluk, kullanıcı girişine tepki vermez:

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .padding(padding)
            .clickable(onClick = onClick)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

Düzenin kenarının çevresindeki dolgu artık tıklamalara yanıt vermez

Yerleşik değiştiriciler

Jetpack Compose bir composable'ı süslemenize veya geliştirmenize yardımcı olacak yerleşik değiştiricilerin bir listesini sunar. Düzenlerinizi ayarlamak için kullanacağınız bazı yaygın değiştiricileri aşağıda bulabilirsiniz.

padding ve size

Varsayılan olarak, Compose'da sağlanan düzenler alt öğelerini sarmalar. Bununla birlikte, size değiştiricisini kullanarak bir boyut ayarlayabilirsiniz:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(/*...*/)
        Column { /*...*/ }
    }
}

Belirttiğiniz boyutun, düzenin üst öğesinden gelen kısıtlamaları karşılamıyorsa dikkate alınmayabileceğini unutmayın. composable boyutunun gelen kısıtlamalardan bağımsız olarak sabitlenmesini istiyorsanız requiredSize değiştiricisini kullanın:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.requiredSize(150.dp)
        )
        Column { /*...*/ }
    }
}

Alt resim, üst öğesinden gelen kısıtlamalardan daha büyük

Bu örnekte, height üst öğesi 100.dp olarak ayarlanmış olsa bile requiredSize değiştiricisi öncelikli olduğu için Image yüksekliği 150.dp olur.

Bir alt düzenin üst öğe tarafından izin verilen tüm kullanılabilir yüksekliği doldurmasını istiyorsanız fillMaxHeight değiştiricisini ekleyin (Oluşturma fillMaxSize ve fillMaxWidth değerlerini de sağlar):

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.fillMaxHeight()
        )
        Column { /*...*/ }
    }
}

Resmin yüksekliği üst öğesi kadar yüksek

Bir öğenin etrafına dolgu eklemek için bir padding değiştiricisi ayarlayın.

Düzenin tepesinden referans değere kadar belirli bir mesafeye ulaşmak için metin referans çizgisinin üstüne dolgu eklemek isterseniz paddingFromBaseline değiştiricisini kullanın:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(
                text = artist.name,
                modifier = Modifier.paddingFromBaseline(top = 50.dp)
            )
            Text(artist.lastSeenOnline)
        }
    }
}

Üzerinde dolgu bulunan metin

Zaman farkı

Bir düzeni orijinal konumuna göre konumlandırmak için offset değiştiricisini ekleyip ofseti x ve y eksenlerine ayarlayın. Başlangıçlar pozitif de olmayabilir de. padding ile offset arasındaki fark, bir composable'a offset eklemenin ölçümlerini değiştirmemesidir:

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(artist.name)
            Text(
                text = artist.lastSeenOnline,
                modifier = Modifier.offset(x = 4.dp)
            )
        }
    }
}

Metin, üst kapsayıcısının sağ tarafına kaydırıldı

offset değiştiricisi, düzenin yönüne göre yatay olarak uygulanır. Soldan sağa bir bağlamda pozitif offset, öğeyi sağa, sağdan sola bağlamda ise sola kaydırır. Düzen yönünü dikkate almadan bir ofset ayarlamanız gerekiyorsa pozitif bir ofset değerinin öğeyi her zaman sağa kaydırdığı absoluteOffset değiştiricisine bakın.

offset değiştiricisi, ofsetleri parametre olarak alan offset ve lambda alan offset olmak üzere iki aşırı yükleme sağlar. Bunların her birinin ne zaman kullanılacağı ve performans için nasıl optimize edileceği hakkında daha ayrıntılı bilgi için Performansı oluşturun - Mümkün olduğunca uzun süre okur bölümünü okuyun.

Compose'da kapsam güvenliği

Compose'da yalnızca belirli composable'ların alt öğelerine uygulandığında kullanılabilen değiştiriciler vardır. Oluşturma işlemi bunu özel kapsamlar aracılığıyla uygular.

Örneğin, Box boyutunu etkilemeden Box üst öğesi kadar büyük bir alt öğe yapmak istiyorsanız matchParentSize değiştiricisini kullanın. matchParentSize yalnızca BoxScope dilinde kullanılabilir. Bu nedenle, yalnızca Box ebeveyni olan çocuklarda kullanılabilir.

Kapsam güvenliği, diğer composable'lar ve kapsamlarda işe yaramayacak değiştiriciler eklemenizi engeller ve deneme yanılma süreçlerinden size zaman kazandırır.

Kapsamlı değiştiriciler, üst yayıncının alt öğe hakkında bilmesi gereken bazı bilgiler hakkında üst tarafa bilgi verir. Bunlara genellikle üst veri değiştiriciler de denir. Dahili öğeleri genel amaçlı değiştiricilerden farklıdır, ancak kullanım açısından bakıldığında bu farklılıklar önemli değildir.

Box dahilinde matchParentSize tarihinde başlıyor

Yukarıda belirtildiği gibi, Box boyutunu etkilemeden üst Box ile aynı boyutta bir alt düzen olmasını istiyorsanız matchParentSize değiştiricisini kullanın.

matchParentSize öğesinin yalnızca Box kapsamında kullanılabildiğini, yani yalnızca Box composable'ın doğrudan alt öğeleri için geçerli olduğunu unutmayın.

Aşağıdaki örnekte Spacer alt öğesi, boyutunu üst Box öğesinden alır. Bu da boyutunu en büyük alt öğeden (bu örnekte ArtistCard) alır.

@Composable
fun MatchParentSizeComposable() {
    Box {
        Spacer(
            Modifier
                .matchParentSize()
                .background(Color.LightGray)
        )
        ArtistCard()
    }
}

Kabı dolduran gri arka plan

matchParentSize yerine fillMaxSize kullanıldıysa Spacer, üst öğe için izin verilen tüm alanı kaplar ve bunun sonucunda üst öğenin genişletilip kullanılabilir tüm alanı doldurmasına neden olur.

Ekranı dolduran gri arka plan

Row ve Column içinde weight

Dolgu ve boyut hakkındaki önceki bölümde gördüğünüz gibi, varsayılan olarak composable boyut, sarmaladığı içeriğe göre tanımlanır. Yalnızca RowScope ve ColumnScope ürünlerinde kullanılabilen weight Değiştirici'yi kullanarak bir composable boyutunu üst öğesi içinde esnek olacak şekilde ayarlayabilirsiniz.

İki adet Box composable içeren bir Row ele alalım. Birinci kutuya ikincinin weight değerinin iki katı olarak genişliğin iki katı verilir. Row, 210.dp genişliğinde olduğundan ilk Box 140.dp, ikincisi ise 70.dp genişliğindedir:

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            /*...*/
            modifier = Modifier.weight(2f)
        )
        Column(
            modifier = Modifier.weight(1f)
        ) {
            /*...*/
        }
    }
}

Resim genişliği metin genişliğinin iki katı

Değiştiricileri çıkarma ve yeniden kullanma

Birden çok değiştirici bir composable'ı süslemek veya güçlendirmek için birbirine zincirlenebilir. Bu zincir, tek bir Modifier.Elements öğesinin sıralı ve sabit bir listesini temsil eden Modifier arayüzü aracılığıyla oluşturulur.

Her Modifier.Element; düzen, çizim ve grafik davranışları, hareketle ilgili, odak ve anlamsal davranışlar ve cihaz giriş etkinlikleri gibi bağımsız bir davranışı temsil eder. Bunların sıralaması önemlidir: İlk eklenen değiştirici öğeler önce uygulanır.

Bazen aynı değiştirici zinciri örneklerini birden fazla composable'da ayıklamak ve daha yüksek kapsamlara çekmek yoluyla kullanmak faydalı olabilir. Birkaç nedenden dolayı kod okunabilirliğini iyileştirebilir veya uygulamanızın performansının iyileştirilmesine yardımcı olabilir:

  • Düzenleyicileri kullanan composable'lar için yeniden oluşturma gerçekleştiğinde değiştiricilerin yeniden tahsisi tekrarlanmaz
  • Değiştirici zincirler potansiyel olarak çok uzun ve karmaşık olabilir. Bu nedenle, aynı zincir örneğinin yeniden kullanılması, Compose çalışma zamanının bu zincirleri karşılaştırırken yapması gereken iş yükünü hafifletebilir
  • Bu ayıklama işlemi, kod tabanı genelinde kod temizliğini, tutarlılığını ve bakımını sağlar.

Değiştiricileri yeniden kullanmayla ilgili en iyi uygulamalar

Kendi Modifier zincirlerinizi oluşturun ve bunları birden fazla composable bileşende yeniden kullanmak için ayıklayın. Bir değiştiricinin kaydedilmesinde bir sakınca yoktur, çünkü bunlar veri benzeri nesnelerdir:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

Sık sık değişen durumu gözlemlerken değiştiricileri çıkarma ve yeniden kullanma

Animasyon durumları veya scrollState gibi composable'ların içinde sık sık değişen durumlar gözlemlenirken, önemli miktarda yeniden oluşturma işlemi yapılmış olabilir. Bu durumda, değiştiricileriniz her yeniden oluşturmada ve potansiyel olarak her karede ayrılır:

@Composable
fun LoadingWheelAnimation() {
    val animatedState = animateFloatAsState(/*...*/)

    LoadingWheel(
        // Creation and allocation of this modifier will happen on every frame of the animation!
        modifier = Modifier
            .padding(12.dp)
            .background(Color.Gray),
        animatedState = animatedState
    )
}

Bunun yerine, aynı değiştirici örneğini oluşturabilir, ayıklayabilir ve yeniden kullanabilir, aşağıdaki şekilde composable'a aktarabilirsiniz:

// Now, the allocation of the modifier happens here:
val reusableModifier = Modifier
    .padding(12.dp)
    .background(Color.Gray)

@Composable
fun LoadingWheelAnimation() {
    val animatedState = animateFloatAsState(/*...*/)

    LoadingWheel(
        // No allocation, as we're just reusing the same instance
        modifier = reusableModifier,
        animatedState = animatedState
    )
}

Kapsamlı olmayan değiştiricileri çıkarma ve yeniden kullanma

Değiştiricilerin kapsamı belirli bir composable'a ayarlanabilir veya belirli bir composable'a ayarlanabilir. Kapsam dışı değiştiriciler söz konusu olduğunda, bunları herhangi bir composable'ın dışına basit değişkenler olarak kolayca çıkarabilirsiniz:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

@Composable
fun AuthorField() {
    HeaderText(
        // ...
        modifier = reusableModifier
    )
    SubtitleText(
        // ...
        modifier = reusableModifier
    )
}

Bu, özellikle geç düzenlerle birlikte kullanıldığında faydalı olabilir. Çoğu durumda, potansiyel olarak önemli olan tüm öğelerinizin tam olarak aynı değiştiricilere sahip olmasını istersiniz:

val reusableItemModifier = Modifier
    .padding(bottom = 12.dp)
    .size(216.dp)
    .clip(CircleShape)

@Composable
private fun AuthorList(authors: List<Author>) {
    LazyColumn {
        items(authors) {
            AsyncImage(
                // ...
                modifier = reusableItemModifier,
            )
        }
    }
}

Kapsamlı değiştiricileri çıkarma ve yeniden kullanma

Kapsamı belirli composable'lara ayarlanmış değiştiricileri işlerken bunları mümkün olan en üst düzeye çıkarabilir ve gerektiğinde yeniden kullanabilirsiniz:

Column(/*...*/) {
    val reusableItemModifier = Modifier
        .padding(bottom = 12.dp)
        // Align Modifier.Element requires a ColumnScope
        .align(Alignment.CenterHorizontally)
        .weight(1f)
    Text1(
        modifier = reusableItemModifier,
        // ...
    )
    Text2(
        modifier = reusableItemModifier
        // ...
    )
    // ...
}

Ayıklanan, kapsamlı değiştiricileri yalnızca aynı kapsamlı, doğrudan alt öğelere iletmelisiniz. Bu konunun neden önemli olduğu hakkında daha fazla referans için Oluşturma işleminde kapsam güvenliği bölümüne bakın:

Column(modifier = Modifier.fillMaxWidth()) {
    // Weight modifier is scoped to the Column composable
    val reusableItemModifier = Modifier.weight(1f)

    // Weight will be properly assigned here since this Text is a direct child of Column
    Text1(
        modifier = reusableItemModifier
        // ...
    )

    Box {
        Text2(
            // Weight won't do anything here since the Text composable is not a direct child of Column
            modifier = reusableItemModifier
            // ...
        )
    }
}

Ayıklanan değiştiricilerin daha fazla zincirlenmesi

.then() işlevini çağırarak ayıklanan değiştirici zincirlerinizi başka zincirlere dahil edebilir veya ekleyebilirsiniz:

val reusableModifier = Modifier
    .fillMaxWidth()
    .background(Color.Red)
    .padding(12.dp)

// Append to your reusableModifier
reusableModifier.clickable { /*...*/ }

// Append your reusableModifier
otherModifier.then(reusableModifier)

Değiştiricilerin sırasının önemli olduğunu unutmayın!

Daha fazla bilgi

Parametreleri ve kapsamlarıyla birlikte değiştiricilerin tam listesini sunuyoruz.

Değiştiricilerin nasıl kullanılacağıyla ilgili daha fazla alıştırma yapmak için Compose codelab'deki temel düzenler üzerinden veya Now in Android deposuna da bakabilirsiniz.

Özel değiştiriciler ve bunları nasıl oluşturacağınız hakkında daha fazla bilgi için Özel düzenler - Düzen değiştiriciyi kullanma konulu dokümanlara göz atın.