Eğitim

Jetpack Compose Eğiticisi

Jetpack Compose, yerel Android kullanıcı arayüzü oluşturmak için kullanılan modern bir araç setidir. Jetpack Compose daha az kod, güçlü araçlar ve sezgisel Kotlin API'leri ile Android'de kullanıcı arayüzü geliştirmeyi basitleştirip hızlandırır.

Bu eğiticide, bildirim temelli işlevlerle basit bir kullanıcı arayüzü bileşeni oluşturacaksınız. Herhangi bir XML düzenini düzenlemez veya Düzen Düzenleyici'yi kullanmazsınız. Bunun yerine, istediğiniz öğeleri tanımlamak için composable işlevler çağırırsınız ve Compose derleyici gerisini halleder.

Tam Önizleme
Tam Önizleme

1. Ders: Birleştirilebilir işlevler

Jetpack Compose, oluşturulabilir işlevleri temel alır. Bu işlevler, kullanıcı arayüzünün oluşturulma sürecine (bir öğeyi başlatma, üst öğeye ekleme vb.) odaklanmak yerine nasıl görünmesi gerektiğini açıklayıp veri bağımlılıkları sağlayarak uygulamanızın kullanıcı arayüzünü programatik olarak tanımlamanıza olanak tanır. Oluşturulabilir bir işlev oluşturmak için işlev adına @Composable ek açıklamasını eklemeniz yeterlidir.

Metin öğesi ekle

Başlamak için Android Studio'nun en son sürümünü indirin ve Yeni Proje'yi seçip Telefon ve Tablet kategorisinin altından Etkinlik Boşalt'ı seçerek bir uygulama oluşturun. Uygulamanızı ComposeEğitim olarak adlandırın ve Son'u tıklayın. Varsayılan şablon, zaten bazı Oluşturma öğelerini içermektedir ancak bu eğitimde bu öğeleri adım adım oluşturacaksınız.

Öncelikle onCreate yönteminin içine bir metin öğesi ekleyerek "Merhaba dünya!" metnini görüntüleyin. Bunu, bir içerik bloğu tanımlayarak ve Text composable işlevini çağırarak yaparsınız. setContent bloku, etkinlik işlevlerinin çağrıldığı düzeni tanımlar. Oluşturulabilir işlevler, yalnızca diğer birleştirilebilir işlevlerden çağrılabilir.

Jetpack Compose, bu oluşturulabilir işlevleri uygulamanın kullanıcı arayüzü öğelerine dönüştürmek için bir Kotlin derleyici eklentisi kullanır. Örneğin, Oluştur kullanıcı arayüzü kitaplığı tarafından tanımlanan Text composable işlevi, ekranda bir metin etiketi görüntüler.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
önizlemeyi göster
önizlemeyi gizle

Oluşturulabilir bir işlev tanımlayın

Bir işlevi oluşturulabilir hale getirmek için @Composable ek açıklamasını ekleyin. Bunu denemek için, ad ileten bir MessageCard işlevi tanımlayın ve bu işlevi metin öğesini yapılandırmak için kullanın.

// ...
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
önizlemeyi göster
önizlemeyi gizle

İşlevinizi Android Studio'da önizleme

@Preview ek açıklaması, uygulamayı oluşturup bir Android cihaz veya emülatöre yüklemek zorunda kalmadan Android Studio'da oluşturulabilir işlevlerinizi önizlemenize olanak tanır. Ek açıklama, parametre almayan bir şekilde oluşturulabilir işlevde kullanılmalıdır. Bu nedenle, MessageCard işlevini doğrudan önizleyemezsiniz. Bunun yerine, PreviewMessageCard adlı ikinci bir işlev oluşturun. Bu işlev, MessageCard öğesini uygun bir parametreyle çağırır. @Preview ek açıklamasını @Composable ifadesinden önce ekleyin.

// ...
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
önizlemeyi göster
önizlemeyi gizle

Projenizi yeniden oluşturun. Yeni PreviewMessageCard işlevi herhangi bir yerde çağrılmadığından uygulamanın kendisi değişmez, ancak Android Studio, bölme (tasarım/kod) görünümünü tıklayarak genişletebileceğiniz bir önizleme penceresi ekler. Bu pencerede, @Preview ek açıklamasıyla işaretlenmiş oluşturulabilir işlevler tarafından oluşturulan kullanıcı arayüzü öğelerinin önizlemesi gösterilir. Önizlemeleri istediğiniz zaman güncellemek için önizleme penceresinin üst kısmındaki yenile düğmesini tıklayın.

Android Studio'da oluşturulabilir bir işlevin önizlemesi
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Text("Hello world!")
        }
    }
}
  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.runtime.Composable

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard("Android")
        }
    }
}

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MessageCard(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard("Android")
}
  
önizlemeyi göster
önizlemeyi gizle
Android Studio'da oluşturulabilir bir işlevin önizlemesi

2. Ders: Düzenler

Kullanıcı arayüzü öğeleri hiyerarşiktir ve öğeler diğer öğelerde yer alır. Compose'da, diğer oluşturulabilecek işlevlerden birleştirilebilir işlevleri çağırarak bir kullanıcı arayüzü hiyerarşisi oluşturursunuz.

Birden çok metin ekleme

Şu ana kadar ilk bir oluşturma işlevinizi ve önizlemenizi oluşturdunuz. Jetpack Compose'un diğer özelliklerini keşfetmek için bazı animasyonlarla genişletilebilen mesajların bir listesini içeren basit bir mesajlaşma ekranı oluşturacaksınız.

Yazarın adını ve ileti içeriğini görüntüleyerek mesajı daha zengin hale getirerek başlayın. İlk olarak, oluşturulabilir parametreyi String yerine bir Message nesnesini kabul edecek şekilde değiştirmeniz ve MessageCard kompozisyonunun içine başka bir Text öğesi eklemeniz gerekir. Önizlemeyi de güncellediğinizden emin olun.

// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
önizlemeyi göster
önizlemeyi gizle

Bu kod, içerik görünümü içinde iki metin öğesi oluşturur. Ancak, bunların nasıl düzenleneceği hakkında bilgi vermediğiniz için metin öğeleri birbirinin üzerine çizilir ve metin okunamaz hale gelir.

Sütun Kullanma

Column işlevi, öğeleri dikey olarak düzenlemenizi sağlar. MessageCard işlevine Column ekleyin.
Öğeleri yatay olarak düzenlemek için Row, gruplandırmak için ise Box kullanabilirsiniz.

// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

önizlemeyi göster
önizlemeyi gizle

Resim öğesi ekleme

Gönderenin profil resmini ekleyerek mesaj kartınızı zenginleştirin. Fotoğraf kitaplığınızdan bir resmi içe aktarmak için Resource Manager'ı veya bu resmi kullanın. İyi yapılandırılmış bir tasarıma sahip olacak şekilde ekleyebileceğiniz ve içine Image yerleştirilebilecek bir Row ekleyin.

// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
önizlemeyi göster
önizlemeyi gizle

Düzeninizi yapılandırın

Mesaj düzeniniz doğru yapıya sahip, ancak öğeleri iyi aralıklı değil ve resim çok büyük. Oluşturulan bir besteyi süslemek veya yapılandırmak için değiştiriciler kullanılır. Oluşturulan öğenin boyutunu, düzenini ve görünümünü değiştirmenize veya bir öğeyi tıklanabilir hale getirmek gibi üst düzey etkileşimler eklemenize olanak tanır. Daha zengin kompozisyonlar oluşturmak için zincir halinde ekleyebilirsiniz. Düzeni iyileştirmek için bunlardan bazılarını kullanacaksınız.

// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
önizlemeyi göster
önizlemeyi gizle
// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MessageCard(Message("Android", "Jetpack Compose"))
        }
    }
}

data class Message(val author: String, val body: String)

@Composable
fun MessageCard(msg: Message) {
    Text(text = msg.author)
    Text(text = msg.body)
}

@Preview
@Composable
fun PreviewMessageCard() {
    MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
    )
}

  
önizlemeyi göster
önizlemeyi gizle
Örtüşen iki metin oluşturulabilmesinin önizlemesi
// ...
import androidx.compose.foundation.layout.Column

@Composable
fun MessageCard(msg: Message) {
    Column {
        Text(text = msg.author)
        Text(text = msg.body)
    }
}

önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.ui.res.painterResource

@Composable
fun MessageCard(msg: Message) {
    Row {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
        )
    
       Column {
            Text(text = msg.author)
            Text(text = msg.body)
        }
  
    }
  
}
  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp

@Composable
fun MessageCard(msg: Message) {
    // Add padding around our message
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = "Contact profile picture",
            modifier = Modifier
                // Set image size to 40 dp
                .size(40.dp)
                // Clip image to be shaped as a circle
                .clip(CircleShape)
        )

        // Add a horizontal space between the image and the column
        Spacer(modifier = Modifier.width(8.dp))

        Column {
            Text(text = msg.author)
            // Add a vertical space between the author and message texts
            Spacer(modifier = Modifier.height(4.dp))
            Text(text = msg.body)
        }
    }
}
  
önizlemeyi göster
önizlemeyi gizle

3. Ders: Materyal Tasarım

Oluşturma, Materyal Tasarım ilkelerini destekleyecek şekilde oluşturulmuştur. Kullanıcı arayüzü öğelerinin çoğunda Materyal Tasarım kullanıma hazırdır. Bu derste, uygulamanızın stilini Materyal Tasarım widget'larıyla belirleyeceksiniz.

Materyal Tasarım'ı kullanma

Mesaj tasarımınız artık bir düzene sahip, ancak henüz düzgün görünmüyor.

Jetpack Compose, Materyal Tasarım 3'ün ve kullanıcı arayüzü öğelerinin kullanıma hazır bir şekilde uygulanmasını sağlar. Materyal Tasarım stilini kullanarak, oluşturulan MessageCard öğenizin görünümünü iyileştireceksiniz.

Başlamak için MessageCard işlevini, ComposeTutorialTheme projenizde oluşturulan Materyal teması ve Surface ile sarmalayın. Bu işlemi hem @Preview hem de setContent işlevinde yapın. Böylece bestelerinizin, uygulamanızın temasında tanımlandığı gibi stilleri devralabilir, uygulamanız genelinde tutarlılık sağlayabilirsiniz.

Materyal Tasarım üç temel temel üzerine kurulmuştur: Color, Typography ve Shape. Öğeleri tek tek ekleyeceksiniz.

Not: Boş Yazma Etkinliği şablonu, projeniz için MaterialTheme öğesini özelleştirmenize olanak tanıyan varsayılan bir tema oluşturur. Projenize ComposeTutorial'dan farklı bir ad verdiyseniz özel temanızı ui.theme alt paketindeki Theme.kt dosyasında bulabilirsiniz.

// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        Surface {
            MessageCard(
                msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
            )
        }
    }
}


  
önizlemeyi göster
önizlemeyi gizle

Renk

Sarmalanmış temadaki renklerle stil belirlemek için MaterialTheme.colorScheme kullanın. Bu değerleri temada rengin gerekli olduğu her yerde kullanabilirsiniz. Bu örnekte dinamik tema renkleri kullanılmaktadır (cihaz tercihleri tarafından tanımlanır). Bunu değiştirmek için MaterialTheme.kt dosyasında dynamicColor değerini false olarak ayarlayabilirsiniz.

Başlığın stilini belirleyin ve resme kenarlık ekleyin.

// ...
import androidx.compose.foundation.border
import androidx.compose.material3.MaterialTheme

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle

Yazı biçimi

Materyal Tipografi stilleri MaterialTheme içinde kullanılabilir. Bunları Text beste dosyalarına eklemeniz yeterlidir.

// ...

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.bodyMedium
           )
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle

Şekil

Shape ile son rötuşları yapabilirsiniz. İlk olarak, ileti gövde metnini Surface e-postasının etrafına sarmalayın. Böylece mesaj gövdesinin şeklinin ve yüksekliğinin özelleştirilmesi sağlanır. Daha iyi bir düzen için iletiye de dolgu eklenmiştir.

// ...
import androidx.compose.material3.Surface

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.bodyMedium
               )
           }
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle

Koyu temayı etkinleştir

Özellikle geceleri parlak bir görüntüden kaçınmak veya sadece cihazın pilinden tasarruf etmek için koyu tema (veya gece modu) etkinleştirilebilir. Materyal Tasarım desteği sayesinde Jetpack Compose, varsayılan olarak koyu temayı işleyebilir. Materyal Tasarım renkleri, metinleri ve arka planları kullanıldığında koyu arka plana otomatik olarak uyum sağlar.

Dosyanızda ayrı işlevler olarak birden çok önizleme oluşturabilir veya aynı işleve birden fazla ek açıklama ekleyebilirsiniz.

Yeni bir önizleme ek açıklaması ekleyip gece modunu etkinleştirin.

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
önizlemeyi göster
önizlemeyi gizle

Açık ve koyu temalarla ilgili renk seçenekleri, IDE tarafından oluşturulan Theme.kt dosyasında tanımlanmıştır.

Şimdiye kadar, farklı stillere sahip bir resim ve iki metin görüntüleyen bir mesaj kullanıcı arayüzü öğesi oluşturdunuz. Bu öğe, hem açık hem de koyu temalarda iyi görünüyor!

// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
önizlemeyi göster
önizlemeyi gizle
// ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTutorialTheme {
                Surface(modifier = Modifier.fillMaxSize()) {
                    MessageCard(Message("Android", "Jetpack Compose"))
                }
            }
        }
    }
}

@Preview
@Composable
fun PreviewMessageCard() {
    ComposeTutorialTheme {
        Surface {
            MessageCard(
                msg = Message("Lexi", "Take a look at Jetpack Compose, it's great!")
            )
        }
    }
}


  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.foundation.border
import androidx.compose.material3.MaterialTheme

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )

       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary
           )

           Spacer(modifier = Modifier.height(4.dp))
           Text(text = msg.body)
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Text(
               text = msg.body,
               style = MaterialTheme.typography.bodyMedium
           )
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.material3.Surface

@Composable
fun MessageCard(msg: Message) {
   Row(modifier = Modifier.padding(all = 8.dp)) {
       Image(
           painter = painterResource(R.drawable.profile_picture),
           contentDescription = null,
           modifier = Modifier
               .size(40.dp)
               .clip(CircleShape)
               .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
       )
       Spacer(modifier = Modifier.width(8.dp))

       Column {
           Text(
               text = msg.author,
               color = MaterialTheme.colorScheme.secondary,
               style = MaterialTheme.typography.titleSmall
           )

           Spacer(modifier = Modifier.height(4.dp))

           Surface(shape = MaterialTheme.shapes.medium, shadowElevation = 1.dp) {
               Text(
                   text = msg.body,
                   modifier = Modifier.padding(all = 4.dp),
                   style = MaterialTheme.typography.bodyMedium
               )
           }
       }
   }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import android.content.res.Configuration

@Preview(name = "Light Mode")
@Preview(
    uiMode = Configuration.UI_MODE_NIGHT_YES,
    showBackground = true,
    name = "Dark Mode"
)
@Composable
fun PreviewMessageCard() {
   ComposeTutorialTheme {
    Surface {
      MessageCard(
        msg = Message("Lexi", "Hey, take a look at Jetpack Compose, it's great!")
      )
    }
   }
}
  
önizlemeyi göster
önizlemeyi gizle
Açık ve koyu temalı bestelerin gösterildiği önizleme.

4. Ders: Listeler ve animasyonlar

Listeler ve animasyonlar uygulamalarda her yerdedir. Bu derste, Compose'un liste oluşturmayı nasıl kolay hale getirdiğini ve animasyon eklemeyi nasıl eğlenceli hale getirdiğini öğreneceksiniz.

Mesaj listesi oluşturma

Tek mesajlık sohbet biraz yalnız hissettirir. Bu yüzden, konuşmayı birden fazla mesaj içerecek şekilde değiştireceğiz. Birden çok mesaj gösteren bir Conversation işlevi oluşturmanız gerekir. Bu kullanım alanı için Compose'un LazyColumn ve LazyRow özelliklerini kullanın. Bu besteler yalnızca ekranda görünen öğeleri oluşturduğundan uzun listelerde çok verimli olacak şekilde tasarlanmıştır.

Bu kod snippet'inde LazyColumn öğesinin items alt öğesi olduğunu görebilirsiniz. Parametre olarak bir List parametresi alır ve lambda'sı, message adını verdiğimiz (istediğimiz adı verebiliriz) bir parametre alır. Bu parametre, Message örneğidir. Kısacası, bu lambda, sağlanan List öğesinin her bir öğesi için çağrılır. Görüşmenin hızla başlatılması için örnek veri kümesini projenize kopyalayın.

// ...
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
önizlemeyi göster
önizlemeyi gizle

Genişletirken mesajları canlandır

Sohbet daha ilginç hale geliyor. Animasyonlarla oynama zamanı geldi! Hem içerik boyutunu hem de arka plan rengini animasyon ekleyerek daha uzun bir mesajı genişletme özelliği ekleyeceksiniz. Bu yerel kullanıcı arayüzü durumunu depolamak için bir mesajın genişletilip genişletilmediğini takip etmeniz gerekir. Bu durum değişikliğini takip etmek için remember ve mutableStateOf işlevlerini kullanmanız gerekir.

Oluşturulabilir işlevler, remember kullanarak yerel durumu bellekte depolayabilir ve mutableStateOf öğesine iletilen değerde yapılan değişiklikleri izleyebilir. Bu durumu kullanan besteler (ve alt öğeleri), değer güncellendiğinde otomatik olarak yeniden çizilir. Buna yeniden oluşturma adı verilir.

Compose'un remember ve mutableStateOf gibi durum API'leri kullanıldığında durum değişiklikleri, kullanıcı arayüzünü otomatik olarak günceller.

Not: Kotlin'in yetki verilmiş mülk söz dizimini (by anahtar kelimesi) doğru şekilde kullanmak için aşağıdaki içe aktarmaları eklemeniz gerekir. Alt+Enter veya Option+Enter tuşlarını sizin için ekler.
import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue

// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
önizlemeyi göster
önizlemeyi gizle

Artık mesajları tıkladığımızda mesaj içeriğinin arka planını isExpanded göre değiştirebilirsiniz. Oluşturulabilir öğedeki tıklama etkinliklerini işlemek için clickable değiştiricisini kullanacaksınız. Yalnızca Surface öğesinin arka plan rengini değiştirmek yerine arka plan rengini animasyon eklemek için MaterialTheme.colorScheme.surface değerini yavaş yavaş MaterialTheme.colorScheme.primary (veya tam tersi) şeklinde değiştirirsiniz. Bunun için animateColorAsState işlevini kullanırsınız. Son olarak, mesaj kapsayıcı boyutunu yumuşak bir şekilde canlandırmak için animateContentSize değiştiricisini kullanırsınız:

// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor by animateColorAsState(
            if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items

@Composable
fun Conversation(messages: List<Message>) {
    LazyColumn {
        items(messages) { message ->
            MessageCard(message)
        }
    }
}

@Preview
@Composable
fun PreviewConversation() {
    ComposeTutorialTheme {
        Conversation(SampleData.conversationSample)
    }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.foundation.clickable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           ComposeTutorialTheme {
               Conversation(SampleData.conversationSample)
           }
       }
   }
}

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.primary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
önizlemeyi göster
önizlemeyi gizle
// ...
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize

@Composable
fun MessageCard(msg: Message) {
    Row(modifier = Modifier.padding(all = 8.dp)) {
        Image(
            painter = painterResource(R.drawable.profile_picture),
            contentDescription = null,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .border(1.5.dp, MaterialTheme.colorScheme.secondary, CircleShape)
        )
        Spacer(modifier = Modifier.width(8.dp))

        // We keep track if the message is expanded or not in this
        // variable
        var isExpanded by remember { mutableStateOf(false) }
        // surfaceColor will be updated gradually from one color to the other
        val surfaceColor by animateColorAsState(
            if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surface,
        )

        // We toggle the isExpanded variable when we click on this Column
        Column(modifier = Modifier.clickable { isExpanded = !isExpanded }) {
            Text(
                text = msg.author,
                color = MaterialTheme.colorScheme.secondary,
                style = MaterialTheme.typography.titleSmall
            )

            Spacer(modifier = Modifier.height(4.dp))

            Surface(
                shape = MaterialTheme.shapes.medium,
                shadowElevation = 1.dp,
                // surfaceColor color will be changing gradually from primary to surface
                color = surfaceColor,
                // animateContentSize will change the Surface size gradually
                modifier = Modifier.animateContentSize().padding(1.dp)
            ) {
                Text(
                    text = msg.body,
                    modifier = Modifier.padding(all = 4.dp),
                    // If the message is expanded, we display all its content
                    // otherwise we only display the first line
                    maxLines = if (isExpanded) Int.MAX_VALUE else 1,
                    style = MaterialTheme.typography.bodyMedium
                )
            }
        }
    }
}

  
önizlemeyi göster
önizlemeyi gizle

Sonraki adımlar

Tebrikler, Oluşturma eğiticisini tamamladınız. Materyal Tasarım ilkeleri kullanılarak tasarlanmış koyu tema ve önizlemeler kullanılarak tasarlanan, resim ve metin içeren genişletilebilir ve animasyonlu mesajların bir listesini verimli bir şekilde gösteren basit bir sohbet ekranı oluşturdunuz ve bunların hepsi 100 satırdan kısa kodda yer alıyor.

Şimdiye kadar öğrendikleriniz:

  • Birleştirilebilir işlevleri tanımlama
  • Oluşturulabilir öğenize farklı öğeler ekleme
  • Oluşturulan düzen öğelerini kullanarak kullanıcı arayüzü bileşeninizi yapılandırma
  • Değiştirici kullanarak kompozisyonları genişletme
  • Verimli bir liste oluşturma
  • Durumu takip etme ve değiştirme
  • Oluşturulabilir bir dosyaya kullanıcı etkileşimi ekleme
  • İletileri genişletirken canlandırma

Bu adımlardan bazılarını daha ayrıntılı şekilde incelemek isterseniz aşağıdaki kaynaklara göz atabilirsiniz.

Sonraki adımlar

Kurulum
Oluşturma eğitimini tamamladığınıza göre, artık Oluştur ile derleme yapmaya hazırsınız.
Yol
Jetpack Compose'u öğrenmenize ve ustalaşmanıza yardımcı olacak codelab'ler ve videolardan oluşan özel seçkimize göz atın.