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 Teması Oluşturma üzerine kurulmuştur. Materyal Teması Oluşturma, Materyal Tasarım'ı ürününüzün markasını daha iyi yansıtacak şekilde özelleştirmenin sistematik bir yoludur. 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ıza tema uygulamak için MaterialTheme'ya ilettiğiniz parametreleri yapılandırın.

Birbiriyle çelişen iki ekran görüntüsü. İlkinde varsayılan MaterialTheme stili, ikincisinde ise değiştirilmiş stil kullanılıyor.
Şekil 1. İlk ekran görüntüsünde, `MaterialTheme` yapılandırmayan ve bu nedenle varsayılan stili kullanan bir uygulama gösteriliyor. İkinci ekran görüntüsünde, stili özelleştirmek için `MaterialTheme` işlevine parametreler ileten bir uygulama gösteriliyor.

Renk

Renkler, Compose'da veri tutma 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, tekil bir öğe içinde veya satır içi olarak tanımlanmış şekilde). Ancak renkleri temanızda belirtmenizi ve renkleri oradan almanızı şiddetle öneririz. Bu yaklaşım, koyu tema ve iç içe temaların desteklenmesini mümkün kılar.

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

Compose, Material renk sistemini modellemek için Colors sınıfını sağlar. Colors, açık veya koyu renk kümeleri 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ı MaterialTheme'ye iletebilirsiniz:

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

Tema renklerini kullanma

MaterialTheme composable'ına sağlanan Colors değerini almak için MaterialTheme.colors kullanabilirsiniz.

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

Yüzey ve içerik rengi

Birçok bileşen, 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, bir composable'ın rengini ayarlayabilir ve aynı zamanda içerik 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 tonunu ayarlamak için kullanır.

Aynı banner'ın farklı renklerdeki iki örneği
Şekil 3. Farklı arka plan renkleri ayarladığınızda farklı metin ve simge renkleri elde edersiniz.

contentColorFor() yöntemi, tüm tema renkleri için uygun "açık" rengi alır. Örneğin, Surface üzerinde primary arka plan rengi ayarlarsanız bu işlev, içerik rengini onPrimary olarak ayarlamak için kullanılı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

Genellikle, içeriğin önemini iletmek ve görsel hiyerarşi sağlamak için içeriği ne kadar vurguladığınızı değiştirmek istersiniz. Materyal Tasarım'daki metin okunabilirliğiyle ilgili öneriler, farklı önem seviyelerini belirtmek için farklı opaklık seviyelerinin kullanılmasını tavsiye eder.

Jetpack Compose, bunu LocalContentAlpha kullanarak uygular. Bu CompositionLocal için bir değer sağlayarak hiyerarşideki içerik alfası belirleyebilirsiniz. İç içe yerleştirilmiş composable'lar, içeriklerine alfa işlemi uygulamak için bu değeri kullanabilir. Örneğin, Text ve Icon varsayılan olarak LocalContentColor ile LocalContentAlpha'ün kullanılacak şekilde ayarlanmış kombinasyonunu kullanır. Malzeme, ContentAlpha nesnesiyle 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 Locally scoped data with CompositionLocal başlıklı makaleyi inceleyin.

Farklı metin vurgu 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. İlk metin satırı, başlık olup en önemli bilgileri içerir ve bu nedenle ContentAlpha.high kullanılır. İkinci satırda daha az önemli meta veriler bulunur ve bu nedenle ContentAlpha.medium kullanılır.

Koyu tema

Compose'da, MaterialTheme composable'a 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, kendi composable işlevine sarmalanmıştır. Bu işlev, koyu tema kullanılıp kullanılmayacağını belirten bir parametre kabul eder. Bu durumda işlev, cihaz teması ayarı sorgulanarak darkTheme için varsayılan değeri alır.

Mevcut Colors öğelerinin açık veya koyu olup olmadığını 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"
)

Rakım yer paylaşımları

Material'da, koyu temalardaki daha yüksek rakımlı yüzeyler, arka planlarını aydınlatan yükseklik katmanları alır. Bir yüzeyin yüksekliği (varsayılan bir ışık kaynağına yaklaştırılması) arttıkça yüzey daha açık renkli olur.

Surface composable, koyu renkler kullanılırken bu kaplamaları 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
    /*...*/
) { /*...*/ }

Bir uygulamanın ekran görüntüsü. Farklı yükseklik seviyelerindeki öğeler için kullanılan, birbirinden biraz farklı renkler gösteriliyor.
Ş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, alt gezinme ise kartlardan daha açık renklidir.

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 katmanlarını devre dışı bırakmak için bir composable hiyerarşisinde seçilen noktada null sağlayın:

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

Sınırlı renk vurguları

Material, çoğu durumda surface rengi yerine primary renginin kullanılmasını tercih ederek koyu temalarda sınırlı renk vurguları uygulanmasını önerir. TopAppBar ve BottomNavigation gibi Material composable'ları bu davranışı varsayılan olarak uygular.

Sınırlı renk vurguları için birincil renk yerine yüzey renginin kullanıldığı üst uygulama çubuğunu gösteren bir Material koyu tema ekran görüntüsü
Şekil 6. Sınırlı renk vurgularına sahip Material koyu teması. Ü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, tür sistemi tanımlayarak az sayıda, anlamsal olarak adlandırılmış stil kullanmanızı teşvik eder.

Çeşitli stillerdeki birkaç farklı yazı tipi örneği
Şekil 7. Malzeme türü sistemi.

Compose, Typography, TextStyle ve font ile ilgili sınıflarla tür sistemini uygular. Typography oluşturucusu, her stil için varsayılan değerler sunar. Bu sayede, ö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ı tipini kullanmak istiyorsanız defaultFontFamily parametresini belirtin ve fontFamily değerini tüm TextStyle öğelerinden çıkarı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 karışımı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, şekil sistemi tanımlayarak büyük, orta ve küçük bileşenler için şekiller tanımlamanıza olanak tanır.

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

Compose, Shapes sınıfıyla şekil sistemini uygular. Bu sınıf, her boyut kategorisi için 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, ModalDrawer ise varsayılan olarak büyük olur. Tam eşleme için şekil şeması referansına bakın.

Şekil kullanma

Shape öğelerine MaterialTheme.shapes kullanılarak erişilir. Aşağıdaki gibi bir kodla Shape öğelerini 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 Views'daki varsayılan stiller, Compose'da eşdeğer bir kavrama sahip değildir. 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, doğrudan değiştirmek istediğiniz veya değiştirmeniz gereken parametreleri ayarlayın ve diğerlerini kapsayan composable'a parametre olarak sunun.

@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ı iç içe yerleştirerek Compose'daki Android Views'da tema katmanlarına eşdeğer bir görünüm elde edebilirsiniz. MaterialTheme, renkleri, tipografiyi ve şekilleri varsayılan olarak geçerli tema değerine ayarladığından, bir tema yalnızca bu parametrelerden birini ayarladığında diğer tüm parametreler varsayılan değerlerini korur.

Ayrıca, görüntülemeye dayalı ekranları Compose'a geçirirken android:theme özelliğinin kullanımlarına dikkat edin. Oluşturma kullanıcı arayüzü ağacının ilgili bölümünde yeni bir MaterialTheme oluşturmanız gerekebilir.

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

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

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

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

Bileşen durumları

Etkileşimde bulunulabilen (tıklanan, açılıp kapatılan vb.) Material bileşenleri farklı görsel durumlarda olabilir. Durumlar arasında etkin, devre dışı, basılı vb. yer alır.

Composable'lar genellikle bir enabled parametresine sahiptir. false olarak ayarladığınızda etkileşim engellenir ve renk ile yükseklik gibi özellikler, bileşen durumunu görsel olarak aktaracak şekilde değiştirilir.

Biri etkin, biri 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ğ) simgeli düğme.

Çoğu durumda renk ve yükseklik gibi değerler için varsayılan ayarlara güvenebilirsiniz. Farklı durumlarda kullanılan değerleri yapılandırmanız gerekiyorsa sınıflar ve kolaylık işlevleri 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 renk ve yüksekliği ayarlanmış iki düğmenin ekran görüntüsü
Şekil 13. Ayarlanmış renk ve yükseklik değerleriyle enabled = true (sol) ve enabled = false (sağ) düğmesi.

Dalgalar

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

Ç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 simgesini kullanabilirsiniz.

RippleTheme süresini uzatabilir, defaultRippleColor ve defaultRippleAlpha yardımcı işlevlerinden yararlanabilirsiniz. Ardından, LocalRippleTheme kullanarak hiyerarşinizde özel dalgalanma 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ı dalgalanma efektleri gösteren düğmelerin yer aldığı hareketli GIF
Şekil 14. RippleConfiguration kullanılarak farklı dalgalanma değerlerine sahip düğmeler sağlanır.

Daha fazla bilgi

Compose'da Materyal Teması Oluşturma hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara göz atın.

Codelab uygulamaları

Videolar