Materyal Tasarım 2

Jetpack Compose, dijital arayüzler oluşturmaya yönelik kapsamlı bir tasarım sistemi olan Materyal Tasarım'ın bir uygulamasını sunar. Materyal Tasarım bileşenleri (düğmeler, kartlar, anahtarlar vb.), Materyal Tasarım'ı ürününüzün markasını daha iyi yansıtacak şekilde özelleştirmenin sistematik bir yolu olan Materyal Teması Oluşturma üzerine kuruludur. Materyal Teması; renk, tipografi ve şekil özelliklerini içerir. Bu özellikleri özelleştirdiğinizde değişiklikleriniz, uygulamanızı oluşturmak için kullandığınız bileşenlere otomatik olarak yansıtılır.

Jetpack Compose, bu kavramları MaterialTheme composable'ı ile uygular:

MaterialTheme(
    colors = // ...
    typography = // ...
    shapes = // ...
) {
    // app content
}

Uygulamanızı temalandırmak için MaterialTheme parametrelerini yapılandırın.

İki farklı ekran görüntüsü. İlk ekran görüntüsünde varsayılan MaterialTheme stili, ikinci ekran görüntüsünde ise değiştirilmiş stil kullanılıyor.
Şekil 1. İlk ekran görüntüsünde, `MaterialTheme` yapılandırması olmayan ve bu nedenle varsayılan stili kullanan bir uygulama gösterilmektedir. İkinci ekran görüntüsünde, stili özelleştirmek için `MaterialTheme`'e parametreler ileten bir uygulama gösteriliyor.

Renk

Renkler, Compose'da veri tutan bir sınıf olan Color sınıfıyla modellenir.

val Red = Color(0xffff0000)
val Blue = Color(red = 0f, green = 0f, blue = 1f)

Bunları istediğiniz gibi düzenleyebilirsiniz (üst düzey sabitler olarak, bir singleton içinde veya satır içi olarak tanımlanmış). Ancak renkleri temanızda belirtmenizi ve renkleri oradan almanızı kesinlikle öneririz. Bu yaklaşım, koyu temayı ve iç içe yerleştirilmiş temaları desteklemeyi mümkün kılar.

Tema renk paleti örneği
Şekil 2. Material renk sistemi.

Compose, Materyal renk sistemini modellemek için Colors sınıfını sağlar. Colors, açık veya koyu renk grupları oluşturmak için oluşturucu işlevleri sağlar:

private val Yellow200 = Color(0xffffeb46)
private val Blue200 = Color(0xff91a4fc)
// ...

private val DarkColors = darkColors(
    primary = Yellow200,
    secondary = Blue200,
    // ...
)
private val LightColors = lightColors(
    primary = Yellow500,
    primaryVariant = Yellow400,
    secondary = Blue700,
    // ...
)

Colors tanımladıktan sonra bunları bir MaterialTheme öğesine iletebilirsiniz:

MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors
) {
    // app content
}

Tema renklerini kullanma

MaterialTheme.colors kullanarak MaterialTheme composable'ına sağlanan Colors değerini alabilirsiniz.

Text(
    text = "Hello theming",
    color = MaterialTheme.colors.primary
)

Yüzey ve içerik rengi

Birçok bileşen, bir renk ve içerik rengi çiftini kabul eder:

Surface(
    color = MaterialTheme.colors.surface,
    contentColor = contentColorFor(color),
    // ...
) { /* ... */ }

TopAppBar(
    backgroundColor = MaterialTheme.colors.primarySurface,
    contentColor = contentColorFor(backgroundColor),
    // ...
) { /* ... */ }

Bu sayede, hem bir composable'ın rengini ayarlayabilir hem de içerik (içerdiği composable'lar) için varsayılan bir renk sağlayabilirsiniz. Birçok composable, varsayılan olarak bu içerik rengini kullanır. Örneğin, Text rengini üst öğesinin içerik rengine göre belirler ve Icon bu rengi kullanarak tonunu ayarlar.

Aynı banner'ın farklı renklerdeki iki örneği
Şekil 3. Farklı arka plan renkleri ayarlandığında farklı metin ve simge renkleri oluşturulur.

contentColorFor() yöntemi, tüm tema renkleri için uygun "açık" rengi alır. Örneğin, Surface için primary arka plan rengi ayarlarsanız içerik rengini onPrimary olarak ayarlamak için bu işlevi kullanır. Tema dışı bir arka plan rengi ayarlarsanız uygun bir içerik rengi de belirtmeniz gerekir. Hiyerarşideki belirli bir konumda, mevcut arka plan için tercih edilen içerik rengini almak üzere LocalContentColor kullanın.

İçerik alfa

Önemini belirtmek ve görsel hiyerarşi sağlamak için içeriği ne kadar vurguladığınızı değiştirmek isteyebilirsiniz. Materyal Tasarım metin okunabilirliği önerileri, farklı önem seviyelerini iletmek için farklı opaklık seviyeleri kullanmayı önerir.

Jetpack Compose, bunu LocalContentAlpha kullanarak uygular. Bu CompositionLocal için bir değer sağlayarak hiyerarşinin içerik alfa değerini belirtebilirsiniz. İç içe yerleştirilmiş composable'lar, içeriklerine alfa işlemini uygulamak için bu değeri kullanabilir. Örneğin, Text ve Icon varsayılan olarak LocalContentAlpha kullanacak şekilde ayarlanmış LocalContentColor kombinasyonunu kullanır. Material, ContentAlpha nesnesi tarafından modellenen bazı standart alfa değerlerini (high, medium, disabled) belirtir.

// By default, both Icon & Text use the combination of LocalContentColor &
// LocalContentAlpha. De-emphasize content by setting content alpha
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
    Text(
        // ...
    )
}
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
    Icon(
        // ...
    )
    Text(
        // ...
    )
}

CompositionLocal hakkında daha fazla bilgi edinmek için CompositionLocal ile yerel kapsamlı veriler başlıklı makaleyi inceleyin.

Farklı metin vurgulama düzeylerini gösteren bir makale başlığının ekran görüntüsü
Şekil 4. Bilgi hiyerarşisini görsel olarak iletmek için metne farklı vurgu düzeyleri uygulayın. Metnin ilk satırı başlıktır ve en önemli bilgileri içerir. Bu nedenle ContentAlpha.high kullanılır. İkinci satırda daha az önemli meta veriler yer alır ve bu nedenle ContentAlpha.medium kullanılır.

Koyu tema

Compose'da, MaterialTheme composable'ına farklı Colors kümeleri sağlayarak açık ve koyu temaları uygularsınız:

@Composable
fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colors = if (darkTheme) DarkColors else LightColors,
        /*...*/
        content = content
    )
}

Bu örnekte MaterialTheme, koyu tema kullanılıp kullanılmayacağını belirten bir parametreyi kabul eden kendi composable işleviyle sarmalanmıştır. Bu durumda işlev, cihaz tema ayarını sorgulayarak darkTheme için varsayılan değeri alır.

Mevcut Colors açık mı yoksa koyu mu olduğunu kontrol etmek için aşağıdaki gibi bir kod kullanabilirsiniz:

val isLightTheme = MaterialTheme.colors.isLight
Icon(
    painterResource(
        id = if (isLightTheme) {
            R.drawable.ic_sun_24
        } else {
            R.drawable.ic_moon_24
        }
    ),
    contentDescription = "Theme"
)

Yükseklik yer paylaşımları

Material'da, koyu temalarda daha yüksek seviyeli yüzeyler, arka planlarını aydınlatan seviye yer paylaşımları alır. Bir yüzeyin yüksekliği arttıkça (varsayılan ışık kaynağına yaklaştıkça) yüzey daha açık renkli hale gelir.

Surface composable'ı, koyu renkler kullanıldığında bu yer paylaşımlarını otomatik olarak uygular. Yüzey kullanan diğer tüm Material composable'ları da aynı şekilde çalışır:

Surface(
    elevation = 2.dp,
    color = MaterialTheme.colors.surface, // color will be adjusted for elevation
    /*...*/
) { /*...*/ }

Farklı yükseklik seviyelerindeki öğeler için kullanılan hafif farklı renkleri gösteren bir uygulamanın ekran görüntüsü
Şekil 5. Kartlar ve alt gezinme, arka plan olarak surface rengini kullanıyor. Kartlar ve alt gezinme, arka planın üzerinde farklı yükseklik seviyelerinde olduğundan renkleri biraz farklıdır. Kartlar arka plandan daha açık, alt gezinme ise kartlardan daha açıktır.

Surface içermeyen özel senaryolar için Surface bileşenleri tarafından kullanılan ElevationOverlay öğesini içeren bir CompositionLocal olan LocalElevationOverlay öğesini kullanın:

// Elevation overlays
// Implemented in Surface (and any components that use it)
val color = MaterialTheme.colors.surface
val elevation = 4.dp
val overlaidColor = LocalElevationOverlay.current?.apply(
    color, elevation
)

Yükseklik yer paylaşımlarını devre dışı bırakmak için composable hiyerarşisinde seçilen noktada null değerini sağlayın:

MyTheme {
    CompositionLocalProvider(LocalElevationOverlay provides null) {
        // Content without elevation overlays
    }
}

Sınırlı renk vurguları

Material, koyu temalar için sınırlı renk vurguları uygulanmasını ve çoğu durumda primary rengi yerine surface renginin kullanılmasını önerir. TopAppBar ve BottomNavigation gibi Material bileşenleri bu davranışı varsayılan olarak uygular.

Sınırlı renk vurguları için birincil renk yerine yüzey rengini kullanan üst uygulama çubuğunu gösteren Material koyu tema ekran görüntüsü
Şekil 6. Sınırlı renk vurgularına sahip Material koyu tema. Üst uygulama çubuğu, açık temada birincil rengi, koyu temada ise yüzey rengini kullanır.

Özel senaryolar için primarySurface uzantı özelliğini kullanın:

Surface(
    // Switches between primary in light theme and surface in dark theme
    color = MaterialTheme.colors.primarySurface,
    /*...*/
) { /*...*/ }

Yazı biçimi

Material, az sayıda semantik olarak adlandırılmış stil kullanmanızı teşvik eden bir yazı tipi sistemi tanımlar.

Çeşitli stillerde birkaç farklı yazı tipi örneği
Şekil 7. Material yazı tipi sistemi.

Compose, yazı tipi sistemini Typography, TextStyle ve yazı tipiyle ilgili sınıflarla uygular. Typography oluşturucu, her stil için varsayılan değerler sunar. Böylece özelleştirmek istemediğiniz stilleri atlayabilirsiniz:

val raleway = FontFamily(
    Font(R.font.raleway_regular),
    Font(R.font.raleway_medium, FontWeight.W500),
    Font(R.font.raleway_semibold, FontWeight.SemiBold)
)

val myTypography = Typography(
    h1 = TextStyle(
        fontFamily = raleway,
        fontWeight = FontWeight.W300,
        fontSize = 96.sp
    ),
    body1 = TextStyle(
        fontFamily = raleway,
        fontWeight = FontWeight.W600,
        fontSize = 16.sp
    )
    /*...*/
)
MaterialTheme(typography = myTypography, /*...*/) {
    /*...*/
}

Her yerde aynı yazı karakterini kullanmak istiyorsanız defaultFontFamily parametresini belirtin ve TextStyle öğelerinin fontFamily parametresini atlayın:

val typography = Typography(defaultFontFamily = raleway)
MaterialTheme(typography = typography, /*...*/) {
    /*...*/
}

Metin stillerini kullanma

TextStyle öğelerine MaterialTheme.typography kullanılarak erişilir. TextStyle öğelerini aşağıdaki gibi alın:

Text(
    text = "Subtitle2 styled",
    style = MaterialTheme.typography.subtitle2
)

Farklı amaçlar için farklı yazı tiplerinin bir arada kullanıldığını gösteren ekran görüntüsü
Şekil 8. Markanızı ifade etmek için çeşitli yazı tipleri ve stiller kullanın.

Şekil

Material, büyük, orta ve küçük bileşenler için şekiller tanımlamanıza olanak tanıyan bir şekil sistemi tanımlar.

Çeşitli Materyal Tasarım şekilleri gösterir.
Şekil 9. Material şekil sistemi.

Compose, şekil sistemini Shapes sınıfıyla uygular. Bu sınıf, her boyut kategorisi için bir CornerBasedShape belirtmenize olanak tanır:

val shapes = Shapes(
    small = RoundedCornerShape(percent = 50),
    medium = RoundedCornerShape(0f),
    large = CutCornerShape(
        topStart = 16.dp,
        topEnd = 0.dp,
        bottomEnd = 0.dp,
        bottomStart = 16.dp
    )
)

MaterialTheme(shapes = shapes, /*...*/) {
    /*...*/
}

Birçok bileşen varsayılan olarak bu şekilleri kullanır. Örneğin, Button, TextField ve FloatingActionButton varsayılan olarak küçük, AlertDialog varsayılan olarak orta ve ModalDrawer varsayılan olarak büyük olur. Tam eşleme için şekil şeması referansına bakın.

Şekilleri kullanma

Shape öğelerine MaterialTheme.shapes kullanılarak erişilir. Shape öğelerini aşağıdaki gibi bir kodla alın:

Surface(
    shape = MaterialTheme.shapes.medium, /*...*/
) {
    /*...*/
}

Bir öğenin hangi durumda olduğunu belirtmek için Material şekillerini kullanan bir uygulamanın ekran görüntüsü
Şekil 10. Markayı veya durumu ifade etmek için şekiller kullanın.

Varsayılan stiller

Android görünümlerindeki varsayılan stiller kavramının Compose'da eşdeğeri yoktur. Materyal bileşenlerini sarmalayan kendi overload composable işlevlerinizi oluşturarak benzer işlevler sağlayabilirsiniz. Örneğin, bir düğme stili oluşturmak için düğmeyi kendi composable işlevinize sarmalayın, değiştirmek istediğiniz veya değiştirmeniz gereken parametreleri doğrudan ayarlayın ve diğerlerini içeren composable'a parametre olarak gösterin.

@Composable
fun MyButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        colors = ButtonDefaults.buttonColors(
            backgroundColor = MaterialTheme.colors.secondary
        ),
        onClick = onClick,
        modifier = modifier,
        content = content
    )
}

Tema yer paylaşımları

MaterialTheme composable'larını iç içe yerleştirerek Android görünümlerindeki tema yer paylaşımlarının eşdeğerini Compose'da elde edebilirsiniz. MaterialTheme; renkleri, tipografiyi ve şekilleri mevcut tema değerine varsayılan olarak ayarladığından, bir tema bu parametrelerden yalnızca birini ayarladığında diğer tüm parametreler varsayılan değerlerini korur.

Ayrıca, görünüme dayalı ekranları Compose'a taşırken android:theme özelliğinin kullanımına dikkat edin. Compose kullanıcı arayüzü ağacının bu bölümünde yeni bir MaterialTheme kullanmanız gerekebilir.

Bu örnekte, ayrıntılar ekranının büyük bir bölümünde PinkTheme, ilgili bölümde ise BlueTheme kullanılıyor. Aşağıdaki ekran görüntüsü ve kod, bu kavramı göstermektedir:

Ana ekran için pembe, ilgili bölüm için mavi temanın kullanıldığı iç içe yerleştirilmiş temaları gösteren bir uygulamanın ekran görüntüsü
Şekil 11. İç içe yerleştirilmiş temalar.

@Composable
fun DetailsScreen(/* ... */) {
    PinkTheme {
        // other content
        RelatedSection()
    }
}

@Composable
fun RelatedSection(/* ... */) {
    BlueTheme {
        // content
    }
}

Bileşen durumları

Etkileşim kurulabilen (tıklama, açma/kapatma vb.) Material bileşenleri farklı görsel durumlarda olabilir. Durumlar arasında etkin, devre dışı, basılı vb. yer alır.

Birleştirilebilir öğelerde genellikle enabled parametresi bulunur. false olarak ayarlandığında etkileşimi engeller ve bileşen durumunu görsel olarak iletmek için renk ve yükseklik gibi özellikleri değiştirir.

Biri etkin, diğeri devre dışı olan iki düğmenin farklı görsel durumlarını gösteren ekran görüntüsü
Şekil 12. enabled = true (sol) ve enabled = false (sağ) simgelerinin bulunduğu düğme.

Çoğu durumda renk ve yükseklik gibi değerler için varsayılanları kullanabilirsiniz. Farklı durumlarda kullanılan değerleri yapılandırmanız gerekiyorsa sınıflar ve kolaylık sağlayan işlevler mevcuttur. Aşağıdaki düğme örneğini inceleyin:

Button(
    onClick = { /* ... */ },
    enabled = true,
    // Custom colors for different states
    colors = ButtonDefaults.buttonColors(
        backgroundColor = MaterialTheme.colors.secondary,
        disabledBackgroundColor = MaterialTheme.colors.onBackground
            .copy(alpha = 0.2f)
            .compositeOver(MaterialTheme.colors.background)
        // Also contentColor and disabledContentColor
    ),
    // Custom elevation for different states
    elevation = ButtonDefaults.elevation(
        defaultElevation = 8.dp,
        disabledElevation = 2.dp,
        // Also pressedElevation
    )
) { /* ... */ }

Etkin ve devre dışı durumlar için rengi ve yüksekliği ayarlanmış iki düğmenin ekran görüntüsü
Şekil 13. Renk ve yükseklik değerleri ayarlanmış enabled = true (sol) ve enabled = false (sağ) düğmesi.

Dalgalar

Materyal bileşenleri, etkileşimde bulunulduğunu belirtmek için dalgaları kullanır. Hiyerarşinizde MaterialTheme kullanıyorsanız clickable ve indication gibi değiştiricilerin içinde varsayılan Indication olarak Ripple kullanılır.

başlıklı makaleyi inceleyin.

Çoğu durumda varsayılan Ripple değerini kullanabilirsiniz. Görünümlerini yapılandırmanız gerekiyorsa renk ve alfa gibi özellikleri değiştirmek için RippleTheme kullanabilirsiniz.

RippleTheme sınıfını genişletebilir ve defaultRippleColor ile defaultRippleAlpha hizmet işlevlerini kullanabilirsiniz. Ardından, LocalRippleTheme kullanarak hiyerarşinizde özel dalga temanızı sağlayabilirsiniz:

@Composable
fun MyApp() {
    MaterialTheme {
        CompositionLocalProvider(
            LocalRippleTheme provides SecondaryRippleTheme
        ) {
            // App content
        }
    }
}

@Immutable
private object SecondaryRippleTheme : RippleTheme {
    @Composable
    override fun defaultColor() = RippleTheme.defaultRippleColor(
        contentColor = MaterialTheme.colors.secondary,
        lightTheme = MaterialTheme.colors.isLight
    )

    @Composable
    override fun rippleAlpha() = RippleTheme.defaultRippleAlpha(
        contentColor = MaterialTheme.colors.secondary,
        lightTheme = MaterialTheme.colors.isLight
    )
}

Dokunulduğunda farklı dalga efektleri gösteren düğmelerin yer aldığı hareketli GIF
Şekil 14. RippleConfiguration kullanılarak farklı dalga değerleri sağlanan düğmeler.

Daha fazla bilgi

Compose'da Materyal Teması Oluşturma hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynakları inceleyin.

Codelab uygulamaları

Videolar