Jetpack Compose için Kotlin

Jetpack Compose, Kotlin etrafında geliştirildi. Kotlin bazı durumlarda özel daha kolay bir şekilde yazabileceğiniz deyimler. Farklı bir projenizin Kotlin'e çevirirseniz bile, programlama dilinin büyük olasılıkla Compose'un gücünden yararlanma fırsatından yararlanabilecektir ve anlamak zordur. Daha fazla kazanıyorum Kotlin’in tarzına aşina olmak bu tehlikelerden kaçınmanıza yardımcı olabilir.

Varsayılan bağımsız değişkenler

Bir Kotlin işlevi yazarken, işlev için varsayılan değerler belirtebilirsiniz bağımsız değişkenlerin çağrı yapan kullanıcı bu değerleri açıkça iletmezse kullanılır. Bu özellik, Bu da, aşırı yüklenmiş işlevler ihtiyacını ortadan kaldırır.

Örneğin, kare çizen bir işlev yazmak istediğinizi varsayalım. O fonksiyonunun uzunluğunun belirtildiği sideLength adlı tek bir gerekli parametresi olabilir temsil eder. Bu parametrede thickness gibi isteğe bağlı parametreler kullanılabilir. edgeColor vb.; arayan kişi bunları belirtmezse işlevi varsayılan değerleri kullanır. Diğer dillerde ise bir veya daha fazla çeşitli işlevler:

// We don't need to do this in Kotlin!
void drawSquare(int sideLength) { }

void drawSquare(int sideLength, int thickness) { }

void drawSquare(int sideLength, int thickness, Color edgeColor) { }

Kotlin'de tek bir işlev yazabilir ve şunları sağlar:

fun drawSquare(
    sideLength: Int,
    thickness: Int = 2,
    edgeColor: Color = Color.Black
) {
}

Bu, sizi gereksiz birden fazla işlev yazma zahmetinden kurtarmanın yanı sıra, özelliği, kodunuzun daha kolay okunmasını sağlar. Arayan kişi bir varsayılan değeri kullanmak istediklerini gösteren bir bağımsız değişken için değer. Ayrıca adlandırılmış parametreler, değişikliklerinizin ve performansın beklemeye gerek yoktur. Koda baktığınızda bunun gibi bir işlev çağrısı görürseniz, drawSquare() kodunu kontrol etmeden parametrelerin ne anlama geldiğini öğrenebilirsiniz:

drawSquare(30, 5, Color.Red);

Bunun aksine, bu kod kendini belgelemektedir:

drawSquare(sideLength = 30, thickness = 5, edgeColor = Color.Red)

Çoğu Compose kitaplığı varsayılan bağımsız değişkenleri kullanır ve aynı işlevi görür. Bu sayede, composable'ları özelleştirilebilir, ancak yine de varsayılan davranışın çağrılmasını basitleştirir. Dolayısıyla, örneğin, şunun gibi basit bir metin öğesi oluşturabilirsiniz:

Text(text = "Hello, Android!")

Bu kod aşağıdakiyle aynı etkiye sahiptir. Çok daha ayrıntılı olan bu kod, hakkında daha fazla Text Parametreler açık bir şekilde ayarlanır:

Text(
    text = "Hello, Android!",
    color = Color.Unspecified,
    fontSize = TextUnit.Unspecified,
    letterSpacing = TextUnit.Unspecified,
    overflow = TextOverflow.Clip
)

İlk kod snippet'i çok daha basit ve okunması kolay olmasının yanı sıra kendi belgeleme sürecidir. Yalnızca text parametresini belirterek diğer tüm parametreleri istiyorsanız varsayılan değerleri kullanmanız gerekir. Buna karşın ikinci snippet, bu etiketler için değerleri açıkça ayarlamak istediğinizi diğer parametreleri kullanabilirsiniz, ancak ayarladığınız değerler işleve geri dönelim.

Üst düzey işlevler ve lambda ifadeleri

Kotlin, üst sırayı destekler işlevlerinin parametre olarak diğer işlevleri alırlar. Compose bu yaklaşımı temel alır. Örneğin, Örneğin, Button composable işlevi bir onClick lambda parametresi sağlar. Değer parametresi bir fonksiyondur ve kullanıcı tıkladığında düğme tarafından çağrılır:

Button(
    // ...
    onClick = myClickFunction
)
// ...

Daha yüksek düzeydeki işlevler lambda ifadeleri ve ifadelerle doğal bir şekilde eşlenir. bu da bir fonksiyona dönüşüyor. İşleve yalnızca bir kez ihtiyaç duyarsanız üst düzey işleve aktarmak üzere başka bir yerde tanımlamak için kullanılır. Bunun yerine fonksiyonu bir lambda ifadesiyle tanımlamanız yeterlidir. Önceki örnek myClickFunction() parametresinin başka bir yerde tanımlandığını varsayar. Ancak yalnızca fonksiyonunu bir lambda ile satır içi olarak tanımlamak daha basittir ifade:

Button(
    // ...
    onClick = {
        // do something
        // do something else
    }
) { /* ... */ }

Sondaki lambdalar

Kotlin, son parametresi bir lambda parametresidir. Bu şekilde bir lambda ifadesi iletmek parametresini kullanmak için trailing lambda söz dizimini kullanın. Lambda ifadesini parantez içine almak yerine bu ifadeyi daha fazla bilgi edineceksiniz. Bu durum, Compose'da sık karşılaşılan bir durumdur. ile uyumlu hale getirebilirsiniz.

Örneğin, tüm düzenlerin son parametresi; Column() composable işlev, content, alt kullanıcı arayüzünü yayan bir işlevdir öğeler. Üç metin öğesi içeren bir sütun oluşturmak istediğinizi varsayalım, ve biraz biçimlendirme uygulamanız gerekir. Bu kod çalışır ancak zahmetli:

Column(
    modifier = Modifier.padding(16.dp),
    content = {
        Text("Some text")
        Text("Some more text")
        Text("Last text")
    }
)

content parametresi, fonksiyon imzasındaki son parametre olduğundan ve bunun değerini bir lambda ifadesi olarak iletirsek, parantez:

Column(modifier = Modifier.padding(16.dp)) {
    Text("Some text")
    Text("Some more text")
    Text("Last text")
}

İki örneğin anlamı tamamen aynıdır. Küme ayraçları lambda'yı tanımlar content parametresine aktarılan bir ifadedir.

Aslında ilettiğiniz tek parametre sondaki lambda ise yani son parametre bir lambda ise ve parantezleri tamamen çıkarabilirsiniz. Örneğin, Arkadaş Bitkiler projenizde Column öğesine bir değiştirici iletmeniz gerekmiyordu. Kodu şöyle yazabilirsiniz: bu:

Column {
    Text("Some text")
    Text("Some more text")
    Text("Last text")
}

Bu söz dizimi, Compose'da oldukça yaygındır. Özellikle Column Son parametre, öğenin alt öğeleri (alt öğeler) ise fonksiyon çağrısından sonra küme ayraçları içinde belirtilir.

Nişan dürbünleri ve alıcılar

Bazı yöntemler ve özellikler yalnızca belirli bir kapsamda kullanılabilir. Sınırlı kapsam, gerektiğinde işlevsellik sunmanızı ve kazara erişimi önlemenizi sağlar. o işlevin uygun olmadığı durumlarda kullanmayı düşünebilirsiniz.

Compose'da kullanılan bir örneği düşünün. Row düzenini çağırdığınızda composable, içeriğinizin lambda değeri bir RowScope içinde otomatik olarak çağrılır. Bu sayede Row, yalnızca Row içinde geçerli olan işlevleri sunabilir. Aşağıdaki örnekte, Row öğesinin bir satıra özgü değeri nasıl gösterdiği align değiştiricisi:

Row {
    Text(
        text = "Hello world",
        // This Text is inside a RowScope so it has access to
        // Alignment.CenterVertically but not to
        // Alignment.CenterHorizontally, which would be available
        // in a ColumnScope.
        modifier = Modifier.align(Alignment.CenterVertically)
    )
}

Bazı API'ler alıcı kapsamında çağrılan lambda'ları kabul eder. Bu lambda'lar veya başka bir yerde tanımlanan özellik ve işlevlere parametre bildirimi:

Box(
    modifier = Modifier.drawBehind {
        // This method accepts a lambda of type DrawScope.() -> Unit
        // therefore in this lambda we can access properties and functions
        // available from DrawScope, such as the `drawRectangle` function.
        drawRect(
            /*...*/
            /* ...
        )
    }
)

Daha fazla bilgi için şunu içeren işlev değişmez değerleri: alıcı hakkındaki makalemizi incelemenizi öneririz.

Yetki verilen mülkler

Kotlin, Google'dan yetki verilmiş özellikleri hakkında daha fazla bilgi edinin. Bu özelliklere alanlar gibi çağrılır ancak değerleri dinamik olarak belirlenir. Bunları tanıyabilirsiniz özelliklerini kullanarak by söz dizimini kullanır:

class DelegatingClass {
    var name: String by nameGetterFunction()

    // ...
}

Diğer kodlar aşağıdaki gibi bir kodla mülke erişebilir:

val myDC = DelegatingClass()
println("The name property is: " + myDC.name)

println() yürütüldüğünde, değeri döndürmek için nameGetterFunction() çağrılır seçin.

Bu yetki verilmiş özellikler özellikle devlet destekli mülkler:

var showDialog by remember { mutableStateOf(false) }

// Updating the var automatically triggers a state change
showDialog = true

Veri sınıflarını imha etme

Bir verileri tanımlarsanız sınıfına girip bu verilere erişimi indirim aracı beyan başlıklı makaleyi inceleyin. Örneğin, Örneğin, bir Person sınıfı tanımladığınızı varsayalım:

data class Person(val name: String, val age: Int)

Bu türde bir nesneniz varsa değerlerine aşağıdaki gibi kodla erişebilirsiniz: bu:

val mary = Person(name = "Mary", age = 35)

// ...

val (name, age) = mary

Oluşturma işlevlerinde genellikle bu tür bir kod görürsünüz:

Row {

    val (image, title, subtitle) = createRefs()

    // The `createRefs` function returns a data object;
    // the first three components are extracted into the
    // image, title, and subtitle variables.

    // ...
}

Veri sınıfları, birçok başka faydalı işlev sunar. Örneğin, bir veri sınıfı tanımlarsanız derleyici, equals() ve copy(). Daha fazla bilgiyi veriler sınıfları dokümanlarına göz atın.

Singleton nesneleri

Kotlin, her zaman bir ve yalnızca bir örnek. Bu single'lar, object anahtar kelimesiyle belirtilir. Oluşturma işleminde genellikle bu tür nesneler kullanılır. Örneğin, MaterialTheme tek bir nesne olarak tanımlanır; MaterialTheme.colors, shapes ve typography özelliklerinin tümü geçerli temanın değerlerini içerir.

Tür güvenli derleyiciler ve DSL'ler

Kotlin, alana özgü diller (DSL'ler) oluşturulmasına olanak tanır Google'a güveniyorlar. DSL'ler karmaşık hiyerarşik verilerin oluşturulmasına olanak tanır daha sürdürülebilir ve okunabilir bir şekilde sunabilirsiniz.

Jetpack Compose, LazyRow ve LazyColumn.

@Composable
fun MessageList(messages: List<Message>) {
    LazyColumn {
        // Add a single item as a header
        item {
            Text("Message List")
        }

        // Add list of messages
        items(messages) { message ->
            Message(message)
        }
    }
}

Kotlin, aşağıdakileri kullanarak tür güvenli derleyiciler oluşturur: alıcıyla işlev değişmez değerini kontrol edin. Canvas composable, DrawScope alıcı onDraw: DrawScope.() -> Unit olarak görünür ve kod bloğunun DrawScope içinde tanımlanan üye işlevlerini çağırın.

Canvas(Modifier.size(120.dp)) {
    // Draw grey background, drawRect function is provided by the receiver
    drawRect(color = Color.Gray)

    // Inset content by 10 pixels on the left/right sides
    // and 12 by the top/bottom
    inset(10.0f, 12.0f) {
        val quadrantSize = size / 2.0f

        // Draw a rectangle within the inset bounds
        drawRect(
            size = quadrantSize,
            color = Color.Red
        )

        rotate(45.0f) {
            drawRect(size = quadrantSize, color = Color.Blue)
        }
    }
}

Tür güvenli derleyiciler ve DSL'ler hakkında daha fazla bilgi için Kotlin belgeleri.

Kotlin eş yordamları

Eş yordamlar, Kotlin. Eş yordamlar, ileti dizilerini engellemeden yürütmeyi askıya alabilir. CEVAP duyarlı kullanıcı arayüzü, doğası gereği eşzamansızdır ve Jetpack Compose bu sorunu eş yordamları API düzeyinde benimsemek

Jetpack Compose, kullanıcı arayüzü katmanında eş yordamların güvenli bir şekilde kullanılmasını sağlayan API'ler sunar. rememberCoroutineScope işlevi, etkinlik işleyicilerde veCoroutineScope Askıya alma API'leri oluşturun. Şunu kullanarak aşağıdaki örneğe bakın: ScrollState animateScrollTo API.

// Create a CoroutineScope that follows this composable's lifecycle
val composableScope = rememberCoroutineScope()
Button(
    // ...
    onClick = {
        // Create a new coroutine that scrolls to the top of the list
        // and call the ViewModel to load data
        composableScope.launch {
            scrollState.animateScrollTo(0) // This is a suspend function
            viewModel.loadData()
        }
    }
) { /* ... */ }

Eş yordamlar, kod bloğunu varsayılan olarak sırayla yürütür. Koşu askıya alma işlevini çağıran eş yordam, askıya alma işlevi geri gelir. Askıya alma işlevi farklı bir CoroutineDispatcher çalıştırmasını sağlayın. Önceki örnekte, loadData, animateScrollTo askıya alma işlevine kadar yürütülmeyecek belirtir.

Kodu eşzamanlı olarak yürütmek için yeni eş yordamların oluşturulması gerekir. Örnekte ekranın üst kısmına doğru kaydırmak ve viewModel, iki eş yordam gerekli.

// Create a CoroutineScope that follows this composable's lifecycle
val composableScope = rememberCoroutineScope()
Button( // ...
    onClick = {
        // Scroll to the top and load data in parallel by creating a new
        // coroutine per independent work to do
        composableScope.launch {
            scrollState.animateScrollTo(0)
        }
        composableScope.launch {
            viewModel.loadData()
        }
    }
) { /* ... */ }

Eş yordamlar, eşzamansız API'lerin birleştirilmesini kolaylaştırır. Sonraki örneğin, pointerInput değiştiricisini animasyon API'leriyle birleştirerek Kullanıcı ekrana dokunduğunda bir öğenin konumuna animasyon uygulayın.

@Composable
fun MoveBoxWhereTapped() {
    // Creates an `Animatable` to animate Offset and `remember` it.
    val animatedOffset = remember {
        Animatable(Offset(0f, 0f), Offset.VectorConverter)
    }

    Box(
        // The pointerInput modifier takes a suspend block of code
        Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                // Create a new CoroutineScope to be able to create new
                // coroutines inside a suspend function
                coroutineScope {
                    while (true) {
                        // Wait for the user to tap on the screen
                        val offset = awaitPointerEventScope {
                            awaitFirstDown().position
                        }
                        // Launch a new coroutine to asynchronously animate to
                        // where the user tapped on the screen
                        launch {
                            // Animate to the pressed position
                            animatedOffset.animateTo(offset)
                        }
                    }
                }
            }
    ) {
        Text("Tap anywhere", Modifier.align(Alignment.Center))
        Box(
            Modifier
                .offset {
                    // Use the animated offset as the offset of this Box
                    IntOffset(
                        animatedOffset.value.x.roundToInt(),
                        animatedOffset.value.y.roundToInt()
                    )
                }
                .size(40.dp)
                .background(Color(0xff3c1361), CircleShape)
        )
    }

Eş yordamlar hakkında daha fazla bilgi edinmek için Android'de Kotlin eş yordamları rehberi.

ziyaret edin.