Eğitim

Jetpack Compose Eğiticisi

Jetpack Compose yerel Android kullanıcı arayüzü oluşturmak için 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şlevlere sahip basit bir kullanıcı arayüzü bileşeni derleyeceksiniz. Herhangi bir XML düzenini düzenlemez veya Düzen Düzenleyici'yi kullanmaz. Bunun yerine, istediğiniz öğeleri tanımlamak için composable işlevleri çağırırsınız ve gerisini Compose derleyici halleder.

Tam Önizleme
Tam Önizleme

1. Ders: Oluşturulabilir işlevler

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

Metin öğesi ekleme

Başlamak için Android Studio'nun en son sürümünü indirin ve Yeni Proje'yi seçerek bir uygulama oluşturun, ardından Telefon ve Tablet kategorisinin altında Etkinlik Boşalt'ı seçin. Uygulamanıza ComposeTutorial adını verin ve Finish'i (Son) tıklayın. Varsayılan şablon zaten bazı Compose öğeleri içerir 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 bloğu, etkinliğin composable işlevlerinin çağrıldığı düzenini tanımlar. Oluşturulabilir işlevler yalnızca diğer composable işlevlerden çağrılabilir.

Jetpack Compose bu composable işlevleri uygulamanın kullanıcı arayüzü öğelerine dönüştürmek için bir Kotlin derleyici eklentisi kullanır. Örneğin, Compose 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

Bestelenebilir bir işlev tanımlayın

Bir işlevi composable hale getirmek için @Composable ek açıklamasını ekleyin. Bunu denemek için, ad iletilen bir MessageCard işlevi tanımlayın ve bunu 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

Android Studio'da işlevinizi önizleme

@Preview ek açıklaması, uygulamayı geliştirip bir Android cihaz veya emülatöre yüklemek zorunda kalmadan composable işlevlerinizi Android Studio'da önizlemenize olanak tanır. Ek açıklama, parametre almayan bir composable işlevde kullanılmalıdır. Bu nedenle, MessageCard işlevini doğrudan önizleyemezsiniz. Bunun yerine, uygun bir parametreyle MessageCard çağrısı yapan PreviewMessageCard adlı ikinci bir işlev oluşturun. @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ığı için 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ş composable işlevler tarafından oluşturulan kullanıcı arayüzü öğelerinin önizlemesi gösterilmektedir. Önizlemeleri istediğiniz zaman güncellemek için önizleme penceresinin üst kısmındaki yenile düğmesini tıklayın.

Android Studio'da composable 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 composable bir işlevin önizlemesi

2. Ders: Düzenler

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

Birden çok metin ekleme

Şu ana kadar ilk composable işlevini oluşturup ö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 kapsamlı hale getirerek başlayın. Öncelikle composable parametresini String yerine bir Message nesnesini kabul edecek şekilde değiştirmeniz ve MessageCard composable içine başka bir Text composable 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 sağlamadığınız için metin öğeleri birbirinin üzerine çizilir ve metin okunamaz hale gelir.

Sütun Kullanma

Column işlevi, öğeleri dikey olarak düzenlemenize olanak tanır. MessageCard işlevine Column ekleyin.
Öğeleri yatay olarak düzenlemek için Row, yığınlar için 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 olmak için Row composable ve içinde bir Image composable'ı 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 doğru şekilde yerleştirilmemiş ve resim çok büyük. Compose'da bir composable'ı süslemek veya yapılandırmak için değiştiriciler kullanılır. Bunlar, composable'ın 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 composable'lar oluşturmak için bunları zincir şeklinde kullanabilirsiniz. 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 Text composable'ın ö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ğu, kullanıma hazır Materyal Tasarım'ı kullanır. Bu derste, Materyal Tasarım widget'larıyla uygulamanızın stilini belirleyeceksiniz.

Materyal Tasarım'ı kullanma

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

Jetpack Compose, Materyal Tasarım 3'ün ve kullanıcı arayüzü öğelerinin kullanıma hazır bir uygulamasını sunar. Materyal Tasarım stilini kullanarak MessageCard composable'ın 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 composable'larınız, uygulamanızın temasında tanımlanan stilleri devralarak uygulamanız genelinde tutarlılık sağlayabilir.

Materyal Tasarım üç temel dayanağın üzerine inşa edilmiştir: Color, Typography ve Shape. Bunları tek tek ekleyeceksiniz.

Not: Boş Oluşturma 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 oluşturmak 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 ile kullanılabilir. Bu stilleri Text composable'ları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, mesaj gövdesi metnini bir Surface composable'ının etrafına sarmalayın. Bunun yapılması, ileti gövdesinin şeklinin ve yüksekliğinin özelleştirilmesine olanak tanır. Daha iyi bir düzen için mesaja dolgu da eklenir.

// ...
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

Koyu tema (veya gece modu), özellikle geceleri parlak bir ekranın görüntülenmemesini sağlamak veya yalnızca cihazın pilinden tasarruf etmek için etkinleştirilebilir. Materyal Tasarım desteği sayesinde Jetpack Compose varsayılan olarak koyu temayı işleyebilir. Materyal Tasarım renkleri, metinler ve arka planlar kullanıldıklarında koyu arka plana otomatik olarak uyum sağlanır.

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

Yeni bir önizleme ek açıklaması ekleyin ve 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ı stillerde bir resim ve iki metin gösteren 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
Hem açık hem de koyu temalı composable'ların gösterildiği önizleme.

4. Ders: Listeler ve animasyonlar

Listeler ve animasyonlar uygulamaların her yerinde. Bu derste, Compose'un liste oluşturmayı nasıl kolaylaştırdığını ve animasyon eklemeyi nasıl daha eğlenceli hale getirdiğini öğreneceksiniz.

Mesaj listesi oluşturma

Tek bir mesaj içeren bir sohbet biraz yalnız hissettirebilir. Bu yüzden sohbeti 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ında Compose'un LazyColumn ve LazyRow komutlarını kullanın. Bu composable'lar yalnızca ekranda görünen öğeleri oluşturduğundan uzun listelerde çok verimli olacak şekilde tasarlanmıştır.

Bu kod snippet'inde, LazyColumn için bir items alt öğesi olduğunu görebilirsiniz. Parametre olarak bir List parametresi alır ve lambda'sı, Message örneği olan message adını verdiğimiz (istediğimiz adı vererek) bir parametre alır. Kısacası, bu lambda sağlanan List öğesinin her bir öğesi için çağrılır. Görüşmenin hızlı bir şekilde 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 gelmektedir. Şimdi animasyonlarla oynama zamanı! Hem içerik boyutunu hem de arka plan rengini canlandırarak mesajı genişletip daha uzun bir mesajı genişletme özelliği ekleyebilirsiniz. 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.

Birleştirilebilir işlevler remember kullanarak yerel durumu belleğe depolayabilir ve mutableStateOf öğesine iletilen değerde yapılan değişiklikleri izleyebilir. Bu durumu kullanan composable'lar (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 üzerinde yapılan değişiklikler 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 mesaj içeriğinin arka planını, tıkladığımız isExpanded özelliğine göre değiştirebilirsiniz. composable'da 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 rengine animasyon eklemek için arka plan rengini MaterialTheme.colorScheme.surface yerine MaterialTheme.colorScheme.primary olacak şekilde kademeli olarak değiştirin. 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.