Bir ürünün kullanıcı etkileşiminin yüksek olması, ürünün kullanılmaya devam edilmesi açısından her zaman çok önemli olmuştur.
Bu makale de Jetpack Compose ile kullanıcının ürün deneyimini kolaylaştırmasını sağlayan OnBoarding tasarım yapısının oluşturulmasını örnekleyeceğim.
Dilerseniz Jetpack Compose ile Adım Adım Tasarım makalemi okuyarak Jetpack Compose hakkında detaylı bilgi edinebilirsiniz.
Örnek projemizin ekran görüntüsü:
Proje kodlarına github linkinden, kodlarla ilgili açıklamalarada makaleden ulaşabilirsiniz.
1-Compose Proje Oluşturma
Compose kullanabilmek için ilk önce Android Studio Arctic Fox sürümünü indirmeniz gerekir. Android Studio’da File > New yolunu takip edip New Project ekranında Empty Compose Activity arayüz taslağını seçmelisiniz. Next yapıp projenizi oluşturun.
2-Projede Gerekli Bazı Ayarlar
Projenizin ana dizinindeki build.gradle dosyasını açmalısınız. dependencies blogları arasına aşağıdaki kodu ekleyerek Accompanist kütüphanesini yükleyelim.
1 2 3 |
implementation "com.google.accompanist:accompanist-systemuicontroller:0.17.0" implementation "com.google.accompanist:accompanist-pager:0.12.0" implementation "com.google.accompanist:accompanist-pager-indicators:0.12.0" |
3-İçeriklerin Bulunduğu Sınıfı Oluşturma
İlk önce örnek de kullandığım görselleri erişmek için dosya linkinden indirmelisiniz. Bunlar vector xml dosyalarıdır. Bu xml dosyalarını res->drawable dizinin içine yerleştirmelisiniz. Örneğimizde birden fazla ekran olduğu için ekrandaki resim, başlık ve açıklama bölümlerini bir sınıfta tanımlamayı uygun gördüm. Bunu Kotlin’de data class yapısıyla oluşturmaktayız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import com.smality.jetpackcomposeonboarding.R data class OnBoardingData(val titleR: Int, val textR: Int, val imageR: Int) fun getData(): List<OnBoardingData> { return listOf( OnBoardingData( titleR = R.string.onBoardingTitle1, textR = R.string.onBoardingText1, imageR = R.drawable.on_boarding1 ), OnBoardingData( titleR = R.string.onBoardingTitle2, textR = R.string.onBoardingText2, imageR = R.drawable.on_boarding2 ), OnBoardingData( titleR = R.string.onBoardingTitle3, textR = R.string.onBoardingText3, imageR = R.drawable.on_boarding3 ), ) } |
4- OnBoarding Yapısını Oluşturma
OnBoarding adında bir kotlin dosyası oluşturdum. Bu dosya içinde OnBoarding adında bir tane compose fonksiyonu tanımladım. Bu fonksiyon ana gövde olarak planladım. TopSection, OnBoardingItem, BottomSection vb.oluşturduğum fonksyonları, OnBoarding fonksiyonunda çağırarak kullandım. Son olarak OnBoardingData sınıfında resim, yazı gibi içerikleri kullanarak OnBoarding yapımı oluşturdum. Kodların detaylı açıklamasını, yorum satırlarında bulabilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.spring import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.* import androidx.compose.runtime.* import androidx.compose.ui.* import androidx.compose.ui.draw.clip import androidx.compose.ui.res.* import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.* import com.google.accompanist.pager.* import kotlinx.coroutines.launch @OptIn(ExperimentalPagerApi::class) @Composable @Preview fun OnBoarding() { val scope = rememberCoroutineScope() Column(modifier = Modifier.fillMaxSize()) { //Top alanını oluşturan compose çağırıyoruz TopSection() //OnBoardingData sınıfından OnBoarding ekran sayısını alıyoruz val item = getData() val state = rememberPagerState(pageCount = item.size) //OnBoardingItem'a item resim ve yazıları arayüz elementlerine aktarmasını //sağlıyoruz HorizontalPager( state = state, modifier = Modifier .fillMaxSize() .weight(0.8f) ) { page -> OnBoardingItem(item = item[page]) } //Ekran sayısını BottomSection compose da kullanarak pager ve scrool işlemi BottomSection(size = item.size, index = state.currentPage) { if (state.currentPage+1 < item.size) scope.launch { state.scrollToPage(page = state.currentPage+1) } } } } //Top alanını oluşturan compose @Composable @Preview fun TopSection() { //Padding 12dp olan kutu oluşturuyoruz Box( modifier = Modifier .fillMaxWidth() .padding(12.dp) ) { //Sol köşedeki ok simgeli butonu oluturma IconButton( onClick = {}, modifier = Modifier.align(Alignment.CenterStart) ) { //iconu atama Icon(Icons.Outlined.KeyboardArrowLeft, contentDescription = null) } //Skip adlı text buttonunu oluşturma TextButton( onClick = { /*TODO*/ }, modifier = Modifier.align(Alignment.CenterEnd) ) { Text( text = "Skip", color = MaterialTheme.colors.onBackground ) } } } //Pager görselini ekran sayısı kadar çoğaltan compose @Composable fun BoxScope.Indicators(size: Int, index: Int) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier.align(Alignment.CenterStart) ) { repeat(size) { Indicator(isSelected = it == index) } } } //Bottom alanındaki FloatingActionButton ve Pager göstergesini oluşturma @Composable fun BottomSection(size: Int, index: Int, onNextClicked: () -> Unit) { Box( modifier = Modifier .fillMaxWidth() .padding(12.dp) ) {//Pager bölümünü oluşturan compose çağırıyoruz Indicators(size = size, index = index) //Sağdaki FloatingActionButton rengini, iconunu tanımalama FloatingActionButton( onClick = onNextClicked, modifier = Modifier.align(Alignment.CenterEnd), backgroundColor = MaterialTheme.colors.primary, contentColor = MaterialTheme.colors.onPrimary ) { Icon(Icons.Outlined.KeyboardArrowRight, null) } } } //Bir tane Circle şeklinde pager oluşturma @Composable fun Indicator(isSelected: Boolean) { //pager arasında geçiş yaparkenki animasyonu sağlayan bölüm val width = animateDpAsState( targetValue = if (isSelected) 25.dp else 10.dp, animationSpec = spring(dampingRatio = Spring.DampingRatioHighBouncy) ) //Pager alanı için yükseklik, şekil vb görsel özelliklerini tanımlama Box( modifier = Modifier .height(10.dp) .width(width = width.value) .clip(shape = CircleShape) .background( if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.onBackground.copy( alpha = 0.5f ) ) ) { } } //OnBoardingData sınıfından gelen resim ve yazıların arayüz elementlerine aktarılması @Composable fun OnBoardingItem(item: OnBoardingData) { //İçereklerin konumu belirleniyorz Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxSize() ) { //Resim, image özelliğine atanıyor Image(painter = painterResource(id = item.imageR), contentDescription = null) //Bold ana başlık Text özelliğine atanıyor Text( text = stringResource(id = item.titleR), fontSize = 24.sp, color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold ) //Açıklama yazısı Text özelliğine atanıyor Text( text = stringResource(id = item.textR), color = MaterialTheme.colors.onBackground.copy(alpha = 0.8f), textAlign = TextAlign.Center ) } } |
Son olarak uygulama açılır açılmaz oluşturduğumuz yapının gösterilmesi için MainActivity sınıfında OnBoarding dosyamızdaki OnBoarding fonksiyonumuzu çağırma kodunu yazmalıyız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import com.smality.jetpackcomposeonboarding.onBoarding.OnBoarding import com.smality.jetpackcomposeonboarding.ui.theme.JetpackComposeOnboardingTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { JetpackComposeOnboardingTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { OnBoarding() } } } } } @Preview(showBackground = true) @Composable fun DefaultPreview() { JetpackComposeOnboardingTheme { OnBoarding() } } |
Proje kodlarına github linkinden ulaşabilirsiniz.