<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Howtodoandroid - Medium]]></title>
        <description><![CDATA[best android developers medium publication focused on beginners to learn the android concepts very easily. In this publication having android examples that explained in detail. - Medium]]></description>
        <link>https://medium.com/android-beginners?source=rss----4e0b28298434---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Howtodoandroid - Medium</title>
            <link>https://medium.com/android-beginners?source=rss----4e0b28298434---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 17:09:30 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/android-beginners" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Easy animation on splash screen In android using jetpack compose]]></title>
            <link>https://medium.com/android-beginners/easy-animation-on-splash-screen-in-android-using-jetpack-compose-1294f30c7cde?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/1294f30c7cde</guid>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[splash-screen]]></category>
            <category><![CDATA[splash-animation]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Mon, 10 Oct 2022 06:46:23 GMT</pubDate>
            <atom:updated>2022-10-10T06:46:23.793Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*a7_Wq5EjvBH94D5_.png" /></figure><p>Every android application contains a splash screen to display the app name and app version at the launch of the application. Also, it’s used to load initial data for the application in the background. So the data will be ready before moving to the main screen.</p><p>The splash screen is one of the main screens that every android application is having it. So, let’s see the steps to create the splash screen on our jetpack compose the project.</p><p>Also, I have created a tutorial on jetpack compose basic, I strongly recommend you learn before creating the project on jetpack compose.</p><p><a href="https://howtodoandroid.com/jetpack-compose-components/"><strong>Getting started with jetpack compose — Basic components</strong></a></p><p><a href="https://howtodoandroid.com/jetpack-compose-layouts/"><strong>Getting started with jetpack compose — Layouts</strong></a></p><p><a href="https://howtodoandroid.com/jetpack-compose-modifiers/"><strong>Getting started with jetpack compose — Modifiers</strong></a></p><p><a href="https://howtodoandroid.com/jetpack-compose-theming/"><strong>Getting started with jetpack compose — Theming</strong></a></p><h3>Dependencies</h3><p>In the beginning, we need to add the dependencies for the project. Splash screens don’t have any dependencies. But, after displaying the splash screen, we need to navigate to different screens. For the navigation, we need to add navigation dependency.</p><pre>implementation &quot;androidx.navigation:navigation-compose:2.6.0-alpha02&quot;</pre><h3>Implementation</h3><p>let’s get started with the implementing splash screen with animation on the jetpack compose.</p><h3>Setup navigation controls</h3><p>First, create a new jetpack compose the project. After that, we need to set up the navigation control for the screen available on the application. create screens.kt file and add all the screen names for better navigation.</p><p><strong>screens.kt</strong></p><pre>object Screens {<br>    const val Splash = &quot;Splash&quot;<br>    const val Dashboard = &quot;Dashboard&quot;<br>}</pre><p>Add navigation code in <strong><em>MainAcitivity.kt</em></strong>.</p><pre>val navController = <em>rememberNavController</em>()<br><em>NavHost</em>(navController = navController, startDestination = Screens.Splash) <strong>{<br>    </strong><em>composable</em>(route = Screens.Splash) <strong>{<br>        </strong><em>SplashScreen</em>(navController = navController)<br>    <strong>}<br><br>    </strong><em>composable</em>(route = Screens.Dashboard) <strong>{<br>        </strong><em>DashBoardScreen</em>(navController = navController)<br>    <strong>}<br>}</strong></pre><h3>Create Splash screen UI</h3><p>In the example, I have created splash and dashboard screens. On the splash screen, we need to create an image view to animate and text to display application information.</p><pre>@Composable<br>fun SplashScreen(navController: NavController) = <em>Box</em>(<br>    Modifier<br>        .<em>fillMaxWidth</em>()<br>        .<em>fillMaxHeight</em>()<br>) <strong>{<br>   </strong><em>Image</em>(<br>        painter = <em>painterResource</em>(id = R.drawable.<em>app_icon</em>),<br>        contentDescription = &quot;&quot;,<br>        alignment = Alignment.Center, modifier = Modifier<br>            .<em>fillMaxSize</em>().<em>padding</em>(40.<em>dp</em>)<br>            .<em>scale</em>(scale.value)<br>    )<br><br>    <em>Text</em>(<br>        text = &quot;Version - ${BuildConfig.<em>VERSION_NAME</em>}&quot;,<br>        textAlign = TextAlign.Center,<br>        fontSize = 24.<em>sp</em>,<br>        modifier = Modifier.<em>align</em>(Alignment.BottomCenter).<em>padding</em>(16.<em>dp</em>)<br>    )<br><strong>}</strong></pre><p>And, the preview of the above code,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DyWTdAIVgaXllXgyLJIbjw.png" /></figure><h3>Animate the image on the splash screen</h3><p>Already, we have created the splash UI design the next step is to animate the splash image and navigate to the dashboard screen.</p><pre>@Composable<br>fun SplashScreen(navController: NavController) = <em>Box</em>(<br>    Modifier<br>        .<em>fillMaxWidth</em>()<br>        .<em>fillMaxHeight</em>()<br>) <strong>{<br><br>    </strong>val scale = <em>remember </em><strong>{<br>        </strong>androidx.compose.animation.core.<em>Animatable</em>(0.0f)<br>    <strong>}<br><br>    </strong><em>LaunchedEffect</em>(key1 = true) <strong>{<br>        </strong>scale.animateTo(<br>            targetValue = 0.7f,<br>            animationSpec = <em>tween</em>(800, easing = <strong>{<br>                </strong>OvershootInterpolator(4f).getInterpolation(<strong>it</strong>)<br>            <strong>}</strong>)<br>        )<br>        delay(1000)<br>        navController.navigate(Screens.Dashboard) <strong>{<br>            </strong>popUpTo(Screens.Splash) <strong>{<br>                </strong>inclusive = true<br>            <strong>}<br>        }<br>    }<br><br>    </strong><em>Image</em>(<br>        painter = <em>painterResource</em>(id = R.drawable.<em>app_icon</em>),<br>        contentDescription = &quot;&quot;,<br>        alignment = Alignment.Center, modifier = Modifier<br>            .<em>fillMaxSize</em>().<em>padding</em>(40.<em>dp</em>)<br>            .<em>scale</em>(scale.value)<br>    )<br><br>    <em>Text</em>(<br>        text = &quot;Version - ${BuildConfig.<em>VERSION_NAME</em>}&quot;,<br>        textAlign = TextAlign.Center,<br>        fontSize = 24.<em>sp</em>,<br>        modifier = Modifier.<em>align</em>(Alignment.BottomCenter).<em>padding</em>(16.<em>dp</em>)<br>    )<br><strong>}</strong></pre><p>In the above code, started the image animation at the start of the splash screen. after the 1000ms it will navigate to the dashboard screen.</p><p>also, I have added code to the popup splash screen. So that when pressing the back button it won’t come to the splash screen again.</p><pre>navController.navigate(Screens.Dashboard) <strong>{<br>    </strong>popUpTo(Screens.Splash) <strong>{<br>        </strong>inclusive = true<br>    <strong>}<br>}</strong></pre><h3>Conclusion</h3><p>The splash screen is the most needed screen for all the applications to load initial data or set up the app configurations. So, try this example and let me know your feedback in the comments.</p><p>You can download this example on <strong>Github</strong>.</p><p><a href="https://github.com/velmurugan-murugesan/Android-Example/tree/master/SplashScreenExample"><strong>Android-Example/SplashScreenExample at master · velmurugan-murugesan/Android-Example (github.com)</strong></a></p><p><em>Originally published at </em><a href="https://howtodoandroid.com/animated-splash-screen-in-android-jetpack-compose/"><em>https://howtodoandroid.com</em></a><em> on October 10, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1294f30c7cde" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/easy-animation-on-splash-screen-in-android-using-jetpack-compose-1294f30c7cde">Easy animation on splash screen In android using jetpack compose</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating android app using MVVM + Coroutines + Flow + Hilt]]></title>
            <link>https://medium.com/android-beginners/creating-android-app-using-mvvm-coroutines-flow-hilt-a8acf7f57630?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/a8acf7f57630</guid>
            <category><![CDATA[coroutine]]></category>
            <category><![CDATA[flow]]></category>
            <category><![CDATA[android-example]]></category>
            <category><![CDATA[mvvm]]></category>
            <category><![CDATA[retrofit]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Tue, 26 Jul 2022 07:37:23 GMT</pubDate>
            <atom:updated>2022-07-26T07:37:23.075Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jA2EBb6QyGgizm0reHqbKg.png" /></figure><p>In this tutorial, I will explain the MVVM architecture with kotlin coroutines and kotlin flow with hilt dependency injection. Also, I will explain the Room database with the flow in this tutorial.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/973/1*zgURZZJd4L9M_nEnyODXxg.png" /></figure><p>let’s begin with a short introduction about the features I will use in this tutorial.</p><h3>What is MVVM?</h3><p>MVVM (Model-View-ViewModel) pattern helps to separate the business and presentation logic from the UI completely, and the business logic and UI can be separated for easier testing and maintenance. Let’s take a look at View, ViewModel, and Model.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*AW9NVFBAkhMOl3lLtIm5NQ.png" /></figure><h3>View</h3><p>The view is responsible for the layout structure displayed on the screen. You can also execute UI logic.</p><h3>ViewModel</h3><p>The ViewModel implements the data and commands connected to the View to notify the View of state changes via change notification events. Then, the View that receives the state change notification determines whether to apply the change.</p><h3>Model</h3><p>Model is a non-visual class that has the data to use. Examples include DTO (Data Transfer Objects), POJO (Plain Old Java Objects), and entity objects. It is a commonly used service or repository that needs to access or cache data.</p><p>If you want to learn more about MVVM, check the below tutorials,</p><p><a href="https://howtodoandroid.com/mvvm-kotlin-coroutines-retrofit/">MVVM with Kotlin Coroutines and Retrofit [Example] — Howtodoandroid</a></p><p><a href="https://howtodoandroid.com/mvvm-retrofit-recyclerview-kotlin/">MVVM With Retrofit and Recyclerview in Kotlin [Example] (howtodoandroid.com)</a></p><h3>Basic of Kotlin Coroutines</h3><p>A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages.</p><p>The main advantages of using Coroutines</p><ul><li>They are<strong> light-weight</strong></li><li>Built-in <strong>cancellation</strong> support</li><li>Lower chances for<strong> memory leaks</strong></li><li><strong>Jetpack</strong> libraries provide coroutines support</li></ul><p>To know more about the kotlin coroutines,</p><p><a href="https://howtodoandroid.com/mvvm-kotlin-coroutines-retrofit/">MVVM with Kotlin Coroutines and Retrofit [Example] — Howtodoandroid</a></p><p><a href="https://howtodoandroid.com/mvvm-retrofit-recyclerview-kotlin/">MVVM With Retrofit and Recyclerview in Kotlin [Example] (howtodoandroid.com)</a></p><h3>Introduction to Kotlin flow</h3><ul><li>The Flow is a type that can emit multiple values sequentially, as opposed to suspending functions that return only a single value. For example, you can use a flow to receive live updates from a database.</li><li>Flows are built on top of coroutines and can provide multiple values.</li><li>A flow is conceptually a <em>stream of data</em> that can be computed asynchronously.</li><li>The emitted values must be of the same type.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*f2RXL7uDL9Jn6v5q" /></figure><h3>Hilt dependency injection</h3><p>The hilt is a dependency injection library for Android that reduces the boilerplate of doing manual dependency injection in your project. Hilt provides a standard way to use DI in your application by automatically providing containers for every Android class in your project and managing their lifecycles.</p><p>Also, check the below link to know more about the hilt,</p><p><a href="https://howtodoandroid.com/android-hilt-dependency-injection/">Dependency injection on Android with Hilt[Example] — Howtodoandroid</a></p><p>Enough theory, let’s start with creating an android application using MVVM, kotlin coroutines, and flow.</p><h3>MVVM + Coroutines + Flow + Hilt Example</h3><p>The first step is to add dependencies for the components, like ViewModel, Coroutines, Hilt, Flow, Room, Retrofit, etc.</p><pre>//coroutines<br>    implementation &#39;org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2&#39;</pre><pre>//hilt<br>    implementation &quot;com.google.dagger:hilt-android:2.38.1&quot;<br>    kapt &quot;com.google.dagger:hilt-compiler:2.38.1&quot;</pre><pre>// retrofit<br>    implementation &#39;com.squareup.retrofit2:retrofit:2.9.0&#39;<br>    implementation &quot;com.squareup.okhttp3:okhttp:4.7.2&quot;<br>    implementation &quot;com.squareup.okhttp3:logging-interceptor:4.7.2&quot;<br>    implementation &#39;com.squareup.retrofit2:converter-gson:2.9.0&#39;</pre><pre>//ktx<br>    implementation &quot;androidx.activity:activity-ktx:1.4.0&quot;<br>    implementation &quot;androidx.fragment:fragment-ktx:1.4.1&quot;<br>    implementation &quot;androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1&quot;<br>    implementation &quot;androidx.lifecycle:lifecycle-runtime-ktx:2.4.1&quot;<br>    // glide<br>    implementation &#39;com.github.bumptech.glide:glide:4.13.0&#39;<br>    annotationProcessor &#39;com.github.bumptech.glide:compiler:4.13.0&#39;</pre><h3>Hilt Dependency injection setup</h3><p>Set the application as HiltAndroidApp.</p><pre><a href="http://twitter.com/HiltAndroidApp">@HiltAndroidApp</a><br>class MyApplication: Application() {</pre><pre>override fun onCreate() {<br>        super.onCreate()<br>    }<br>}</pre><p>Also, don’t forget to add the application class and internet permission to the <strong>AndroidManifest.xml </strong>file.</p><pre>&lt;manifest xmlns:android=&quot;<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>&quot;<br>    xmlns:tools=&quot;<a href="http://schemas.android.com/tools">http://schemas.android.com/tools</a>&quot;<br>    package=&quot;com.example.mvvmwithretrofitandflow&quot;&gt;</pre><pre>&lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;/&gt;</pre><pre>&lt;application<br>        android:name=&quot;.MyApplication&quot;<br>        android:allowBackup=&quot;true&quot;<br>        android:dataExtractionRules=&quot;<a href="http://twitter.com/xml/data_extraction_rules">@xml/data_extraction_rules</a>&quot;<br>        android:fullBackupContent=&quot;<a href="http://twitter.com/xml/backup_rules">@xml/backup_rules</a>&quot;<br>        android:icon=&quot;<a href="http://twitter.com/mipmap/ic_launcher">@mipmap/ic_launcher</a>&quot;<br>        android:label=&quot;<a href="http://twitter.com/string/app_name">@string/app_name</a>&quot;<br>        android:roundIcon=&quot;<a href="http://twitter.com/mipmap/ic_launcher_round">@mipmap/ic_launcher_round</a>&quot;<br>        android:supportsRtl=&quot;true&quot;<br>        android:usesCleartextTraffic=&quot;true&quot;<br>        android:theme=&quot;<a href="http://twitter.com/style/Theme">@style/Theme</a>.MVVMWithRetrofitAndFlow&quot;<br>        tools:targetApi=&quot;31&quot;&gt;<br>        &lt;activity<br>            android:name=&quot;.ui.MainActivity&quot;<br>            android:exported=&quot;true&quot;&gt;<br>            &lt;intent-filter&gt;<br>                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;</pre><pre>&lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;<br>            &lt;/intent-filter&gt;<br>        &lt;/activity&gt;<br>    &lt;/application&gt;</pre><pre>&lt;/manifest&gt;</pre><p>create the network module for retrofit setup.</p><p><strong>NetworkModule.kt</strong></p><pre><a href="http://twitter.com/Module">@Module</a><br><a href="http://twitter.com/InstallIn">@InstallIn</a>(SingletonComponent::class)<br>object NetworkModule {<br>    <br>    <a href="http://twitter.com/Singleton">@Singleton</a><br>    <a href="http://twitter.com/Provides">@Provides</a><br>    fun provideOkHttp() : OkHttpClient{<br>        return OkHttpClient.Builder()<br>            .build()<br>    }</pre><pre><a href="http://twitter.com/Singleton">@Singleton</a><br>    <a href="http://twitter.com/Provides">@Provides</a><br>    <a href="http://twitter.com/Named">@Named</a>(&quot;loggingInterceptor&quot;)<br>    fun provideLoggingInterceptor(): HttpLoggingInterceptor {<br>        return HttpLoggingInterceptor().apply {<br>            this.level = HttpLoggingInterceptor.Level.BODY<br>        }<br>    }</pre><pre><a href="http://twitter.com/Provides">@Provides</a><br>    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {<br>        return Retrofit.Builder()<br>            .baseUrl(&quot;<a href="https://imdb-api.com/en/">https://imdb-api.com/en/</a>&quot;)<br>            .addConverterFactory(GsonConverterFactory.create())<br>            .client(okHttpClient)<br>            .build()<br>    }</pre><pre><a href="http://twitter.com/Provides">@Provides</a><br>    fun provideApiClient(retrofit: Retrofit): ApiService {<br>        return retrofit.create(ApiService::class.java)<br>    }<br>    <br>}</pre><p>for the API calls, I am using <a href="https://imdb-api.com/en/">https://imdb-api.com/en/.</a> To use this API need an account with IMDb-api.com.</p><p>and the Response Model, <strong>Model.kt</strong></p><pre><a href="http://twitter.com/Entity">@Entity</a><br>data class Movie(<br>    <a href="http://twitter.com/PrimaryKey">@PrimaryKey</a><br>    val id: String,<br>    val title: String,<br>    val year: String,<br>    val image: String,<br>    val imDbRating: String<br>)</pre><pre>data class MovieResponse(val items: List&lt;Movie&gt;, val errorMessage: String)</pre><h3>Repository setup with flow</h3><p>On the repository, I am calling the API service and returning the response as flow to ViewModel. Also, I am using NetworkResult sealed class to emit different statuses of the network call.</p><p><strong>NetworkResult.kt</strong></p><pre>sealed class NetworkResult&lt;T&gt; {<br>    data class Loading&lt;T&gt;(val isLoading: Boolean) : NetworkResult&lt;T&gt;()<br>    data class Success&lt;T&gt;(val data: T) : NetworkResult&lt;T&gt;()<br>    data class Failure&lt;T&gt;(val errorMessage: String) : NetworkResult&lt;T&gt;()<br>}</pre><p><strong>MainRepository.kt</strong></p><pre>class MainRepository <a href="http://twitter.com/Inject">@Inject</a> constructor(private val apiService: ApiService) {</pre><pre>suspend fun getPopularMovies()  = flow {<br>        emit(NetworkResult.Loading(true))<br>        val response = apiService.getMostPopularMovies()<br>       emit(NetworkResult.Success(response.items))<br>    }.catch { e -&gt;<br>        emit(NetworkResult.Failure(e.message ?: &quot;Unknown Error&quot;))<br>    }<br>}</pre><h3>ViewModel setup with Livedata</h3><p>In the ViewModel collect the flow and set the response to livedata for UI changes.</p><pre><a href="http://twitter.com/HiltViewModel">@HiltViewModel</a><br>class MainViewModel <a href="http://twitter.com/Inject">@Inject</a> constructor(<br>    private val mainRepository: MainRepository<br>) : ViewModel() {</pre><pre>private var _movieResponse = MutableLiveData&lt;NetworkResult&lt;List&lt;Movie&gt;&gt;&gt;()<br>    val movieResponse: LiveData&lt;NetworkResult&lt;List&lt;Movie&gt;&gt;&gt; = _movieResponse</pre><pre>init {<br>        fetchAllMovies()<br>    }</pre><pre>private fun fetchAllMovies() {<br>        viewModelScope.launch {<br>            mainRepository.getPopularMovies().collect {<br>                _movieResponse.postValue(it)<br>            }<br>        }<br>    }<br>}</pre><h3>Observe the changes in UI</h3><p>finally, I have observed the changes from ViewModel to UI class.</p><pre><a href="http://twitter.com/AndroidEntryPoint">@AndroidEntryPoint</a><br>class MainActivity : AppCompatActivity() {</pre><pre>private lateinit var binding: ActivityMainBinding</pre><pre>private val mainViewModel: MainViewModel by viewModels()<br>    <a href="http://twitter.com/Inject">@Inject</a><br>    lateinit var movieAdapter: MovieAdapter</pre><pre>override fun onCreate(savedInstanceState: Bundle?) {<br>        super.onCreate(savedInstanceState)<br>        binding = ActivityMainBinding.inflate(layoutInflater)<br>        setContentView(binding.root)</pre><pre>binding.rvMovies.adapter = movieAdapter</pre><pre>movieAdapter.setItemClick(object : ClickInterface&lt;Movie&gt; {<br>            override fun onClick(data: Movie) {<br>                Toast.makeText(this@MainActivity, data.title, Toast.LENGTH_SHORT).show()<br>            }<br>        })</pre><pre>mainViewModel.movieResponse.observe(this) {<br>            when(it) {<br>                is NetworkResult.Loading -&gt; {<br>                    binding.progressbar.isVisible = it.isLoading<br>                }</pre><pre>is NetworkResult.Failure -&gt; {<br>                    Toast.makeText(this, it.errorMessage, Toast.LENGTH_SHORT).show()<br>                    binding.progressbar.isVisible = false<br>                }</pre><pre>is  NetworkResult.Success -&gt; {<br>                    movieAdapter.updateMovies(it.data)<br>                    binding.progressbar.isVisible = false<br>                }<br>            }<br>        }</pre><pre>}</pre><pre>}</pre><p>that’s it. we have done with the coding let’s run the code and check it. Now you can able to see the list of movies in recyclerview.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q_0v0dFypqQqSiuCh7SDdg.png" /></figure><p>you can download this example from <strong>GitHub</strong>.</p><p><a href="https://github.com/velmurugan-murugesan/Android-Example/tree/master/MVVMWithRetrofitAndFlow">https://github.com/velmurugan-murugesan/Android-Example/tree/master/MVVMWithRetrofitAndFlow</a></p><p><em>Originally published at </em><a href="https://howtodoandroid.com/android-app-using-mvvm-coroutines-flow-hilt/"><em>https://howtodoandroid.com</em></a><em> on July 25, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a8acf7f57630" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/creating-android-app-using-mvvm-coroutines-flow-hilt-a8acf7f57630">Creating android app using MVVM + Coroutines + Flow + Hilt</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Android Runtime Permissions[Updated with Android 11] — Howtodoandroid]]></title>
            <link>https://medium.com/android-beginners/android-runtime-permissions-updated-with-android-11-howtodoandroid-10dab04ea3ad?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/10dab04ea3ad</guid>
            <category><![CDATA[runtime-permissions]]></category>
            <category><![CDATA[android-permissions]]></category>
            <category><![CDATA[android-example]]></category>
            <category><![CDATA[androiddev]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Fri, 27 May 2022 07:52:08 GMT</pubDate>
            <atom:updated>2022-05-27T07:52:08.567Z</atom:updated>
            <content:encoded><![CDATA[<h3>Android Runtime Permissions[Updated with Android 11] — Howtodoandroid</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GKFsxgwmNghTv2EzKSiRaQ.png" /></figure><p>From the beginning with Android 6.0 Marshmallow, Google has introduced a new runtime permission model, users are not asked for permissions at the time of installation rather developers need to request the permissions at the run time. Only the permissions that are defined in the manifest file can be requested at run time.</p><p>This helps in protecting the privacy of an Android Device user. So for example you(your apps) have to request permissions to:</p><ol><li>Access sensitive user data (such as contacts and SMS).</li><li>Access certain system features (such as camera and internet).</li></ol><p>Depending on the feature, the system might grant the permission automatically or might prompt the user to approve the request.</p><h3>Type of permissions</h3><p>Android defines basically three types of permissions:</p><ol><li>Normal Permissions</li><li>Signature Permissions</li><li>Dangerous Permissions</li></ol><blockquote><em>Both Normal and Dangerous permissions must be defined in the Manifest file. But only Dangerous permissions are checked at runtime, Normal permissions are not.</em></blockquote><h3>Normal Permissions</h3><p>These are required when your app needs to access data or resources outside the app’s sandbox, but where there’s very little risk to the user’s privacy or the operation of other apps.</p><p>If an app declares in its manifest that it needs normal permission, the system automatically grants the app that permission at install time. and users cannot revoke these permissions.</p><p>Permissions like <strong>INTERNET, BLUETOOTH, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE, etc</strong> are normal permissions.</p><p>For more details about the permission check the <a href="https://developer.android.com/reference/android/Manifest.permission"><strong>permission API reference page</strong></a>.</p><h3>Signature Permissions</h3><p>A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants permission without notifying the user.</p><p>Permissions like BIND_AUTOFILL_SERVICE, BIND_INPUT_METHOD, BIND_NFC_SERVICE, etc are signature permissions.</p><h3>Dangerous permissions</h3><p>Some permissions may affect the user’s private information, or could potentially affect his data or the operation of other applications are called Dangerous Permissions. For example, the ability to read the user’s contacts is a dangerous permission.</p><p>Permissions like <strong>CAMERA, READ_CALL_LOG, ACCESS_FINE_LOCATION, READ_SMS, READ_EXTERNAL_STORAGE, etc </strong>aredangerous permissions.</p><p>For more details about the permission check the <a href="https://developer.android.com/reference/android/Manifest.permission"><strong>permission API reference page</strong></a>.</p><h3>How to Check for permissions</h3><p>If your app needs dangerous permission, you must check whether you have that permission every time you perform an operation that requires that permission.</p><p>you do it using the<strong> ContextCompat.checkSelfPermission()</strong> method with the permission name.</p><pre>if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) <br>    == PackageManager.PERMISSION_GRANTED) {<br>    // permission granted<br>} else {<br>    // permission not granted<br>}</pre><p>This will return two types of responses.</p><ul><li><strong>PackageManager.PERMISSION_GRANTED</strong> — This means permission granted. So you can proceed with your operations.</li><li><strong>PackageManager.PERMISSION_DENIED</strong> — This means pemission not granted. So you need to ask the permission again or you can skip that process.</li></ul><h3>Request permissions</h3><p>If the permission is not granted, we need to ask for permission to access certain features like camera, storage, etc.</p><p>To ask permission, we need to use <strong>ActivityCompat.requestPermission() </strong>method with the permission name and the request code.</p><p>First, we need to add the requested permission into the <strong>manifest.xml</strong> file.</p><pre>&lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; /&gt;<br>&lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;</pre><p><strong>Note:</strong> don’t forget to add all the needed permission into the manifest file. otherwise, run time permission won’t work.</p><pre>ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.CAMERA), request_code )</pre><p>This will pop up the permission dialog for the defined permission. Users can able to Allow or deny permission.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/284/0*vEJm4YaMGPjBqrx8" /><figcaption>Asking Runtime permission</figcaption></figure><h3>Handle the permission request response</h3><p>Once the user responded to the permission request, the result will be received in the onRequestPermissionResult. based on the request code, we can check our permission granted or denied.</p><pre>override fun onRequestPermissionsResult(<br>    requestCode: Int,<br>    permissions: Array&lt;out String&gt;,<br>    grantResults: IntArray<br>) {<br>    super.onRequestPermissionsResult(requestCode, permissions, grantResults)<br>    if (requestCode == 201) {<br>        if (grantResults.<em>isNotEmpty</em>() &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {<br>            Toast.makeText(this, &quot;Permission granted&quot;, Toast.LENGTH_SHORT).show()<br>            openCamera()<br>        } else {<br>            Toast.makeText(this, &quot;Permission denied&quot;, Toast.LENGTH_SHORT).show()<br>        }<br>    }<br>}</pre><h3>Requesting multiple permissions</h3><p>Previously, we checked about requesting single permission at a time. In android, it’salso possible to ask for multiple permission at a time. We can use the same <strong>ActivityCompat.requestPermissions()</strong> method as above by passing anarray of permissions.</p><pre>ActivityCompat.requestPermissions(<br>    this,<br>    <em>arrayOf</em>(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE),<br>    request_code<br>)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/363/0*Fwoi3QmdZrTYXBlG" /><figcaption>Runtime permission for camera</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/366/0*xum46RiOXwHOjvf7" /><figcaption>Runtime permission to access photos</figcaption></figure><p>But, we cannot check the multiple permission at a time. We need to check the permission status individually.</p><h3>Handle the permission denial</h3><p>When the user is denied permission for the first time. It means that the user doesn’t understand the purpose of the particular permission. So, we need to show some additional messages to explain the purpose of the permission.</p><p>To do that we need to check for the <strong>shouldShowRequestPermissionRationale()</strong> method with the permission to check, whether the permission is already denied or not. If denied already need to show some additional message using the dialog.</p><pre>if (checkPermission(Manifest.permission.CAMERA)) {<br>    openCamera()<br>} else {<br>    if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {<br>        AlertDialog.Builder(this)<br>            .setMessage(&quot;Need camera permission to capture image. Please provide permission to access your camera.&quot;)<br>            .setPositiveButton(&quot;OK&quot;) <strong>{ </strong>dialogInterface, i <strong>-&gt;<br>                </strong>dialogInterface.dismiss()<br>                ActivityCompat.requestPermissions(<br>                    this,<br>                    <em>arrayOf</em>(Manifest.permission.CAMERA),<br>                    201<br>                )<br>            <strong>}<br>            </strong>.setNegativeButton(&quot;Cancel&quot;) <strong>{ </strong>dialogInterface, i <strong>-&gt;<br>                </strong>dialogInterface.dismiss()<br>            <strong>}<br>            </strong>.create()<br>            .show();<br>    } else {<br>        ActivityCompat.requestPermissions(<br>            this,<br>            <em>arrayOf</em>(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE),<br>            201<br>        )<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/278/0*CxlEiPauXR_2yUPy" /><figcaption>Additional Permission Message</figcaption></figure><h3>One-time permissions</h3><p>Starting in Android 11, whenever your app requests permission related to location, microphone, or camera, the user-facing permissions dialog contains an option called<strong> Only this time. </strong>If the user selects this option in the dialog, your app is granted temporary one-time permission.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/373/0*mfxLPmEOFZcMsbwb" /><figcaption>Android one-time permission</figcaption></figure><p>checks more about <a href="https://developer.android.com/training/permissions/requesting#one-time"><strong>one-time permission</strong></a>.</p><h3>Android Runtime Permission Example</h3><p>check out my final code for Runtime permission <strong>MainActivity.kt</strong>,</p><pre>class MainActivity : AppCompatActivity() {<br><br>    lateinit var btnCamera: Button<br>    lateinit var btnLocation: Button<br><br>    override fun onCreate(savedInstanceState: Bundle?) {<br>        super.onCreate(savedInstanceState)<br>        setContentView(R.layout.<em>activity_main</em>)<br><br>        btnCamera = findViewById(R.id.btnCamera)<br>        btnLocation = findViewById(R.id.btnLocation)<br><br>        btnCamera.setOnClickListener <strong>{<br><br>            </strong>if (checkPermission(Manifest.permission.CAMERA)) {<br>                //openCamera()<br>            } else {<br>                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {<br>                    AlertDialog.Builder(this)<br>                        .setMessage(&quot;Need camera permission to capture image. Please provide permission to access your camera.&quot;)<br>                        .setPositiveButton(&quot;OK&quot;) <strong>{ </strong>dialogInterface, i <strong>-&gt;<br>                            </strong>dialogInterface.dismiss()<br>                            ActivityCompat.requestPermissions(<br>                                this,<br>                                <em>arrayOf</em>(Manifest.permission.CAMERA),<br>                                201<br>                            )<br>                        <strong>}<br>                        </strong>.setNegativeButton(&quot;Cancel&quot;) <strong>{ </strong>dialogInterface, i <strong>-&gt;<br>                            </strong>dialogInterface.dismiss()<br>                        <strong>}<br>                        </strong>.create()<br>                        .show();<br>                } else {<br>                    ActivityCompat.requestPermissions(<br>                        this,<br>                        <em>arrayOf</em>(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE),<br>                        201<br>                    )<br>                }<br>            }<br><br><br>            /**/<br><br>        <strong>}<br><br>    </strong>}<br><br>    private fun checkPermission(permission: String): Boolean {<br>        return ContextCompat.checkSelfPermission(<br>            this,<br>            permission<br>        ) == PackageManager.PERMISSION_GRANTED<br>    }<br><br>    override fun onRequestPermissionsResult(<br>        requestCode: Int,<br>        permissions: Array&lt;out String&gt;,<br>        grantResults: IntArray<br>    ) {<br>        super.onRequestPermissionsResult(requestCode, permissions, grantResults)<br>        if (requestCode == 201) {<br>            if (grantResults.<em>isNotEmpty</em>() &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {<br>                Toast.makeText(this, &quot;Permission granted&quot;, Toast.LENGTH_SHORT).show()<br>                //openCamera()<br>            } else {<br>                Toast.makeText(this, &quot;Permission denied&quot;, Toast.LENGTH_SHORT).show()<br>            }<br>        }<br>    }<br><br>}</pre><p>also, updated <strong>Manifest.xml</strong></p><pre>&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br>    package=&quot;com.velmurugan.runtimepermissionandroid&quot;&gt;<br><br>    &lt;uses-permission android:name=&quot;android.permission.CAMERA&quot; /&gt;<br>    &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;<br><br>    &lt;application<br>        android:allowBackup=&quot;true&quot;<br>        android:icon=&quot;@mipmap/ic_launcher&quot;<br>        android:label=&quot;@string/app_name&quot;<br>        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;<br>        android:supportsRtl=&quot;true&quot;<br>        android:theme=&quot;@style/Theme.RuntimePermissionAndroid&quot;&gt;<br>        &lt;activity<br>            android:name=&quot;.MainActivity&quot;<br>            android:exported=&quot;true&quot;&gt;<br>            &lt;intent-filter&gt;<br>                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;<br>                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;<br>            &lt;/intent-filter&gt;<br>        &lt;/activity&gt;<br>    &lt;/application&gt;<br>&lt;/manifest&gt;</pre><p>Thanks for reading. let me know your feedback on comments. Also, you can download this example on <a href="https://github.com/velmurugan-murugesan/Android-Example/tree/master/RuntimePermissionAndroid"><strong>GITHUB</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/android-runtime-permissions/"><em>https://howtodoandroid.com</em></a><em> on March 18, 2022.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10dab04ea3ad" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/android-runtime-permissions-updated-with-android-11-howtodoandroid-10dab04ea3ad">Android Runtime Permissions[Updated with Android 11] — Howtodoandroid</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin Coroutines — Exception Handling and Cancellation]]></title>
            <link>https://medium.com/android-beginners/kotlin-coroutines-exception-handling-and-cancellation-9047457ee6d8?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/9047457ee6d8</guid>
            <category><![CDATA[android-development]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[exception-handling]]></category>
            <category><![CDATA[kotlin-coroutines]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Thu, 25 Nov 2021 05:04:03 GMT</pubDate>
            <atom:updated>2021-11-25T05:04:03.347Z</atom:updated>
            <content:encoded><![CDATA[<h3>Kotlin Coroutines — Exception Handling and Cancellation</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Mk31hn5oMfvQplD0.png" /></figure><p>It’s very important to handle the exception occurs during the networking operation or any IO operations in kotlin coroutines. So, in this tutorial, we are going to see how to handle the exceptions and how to cancel the particular job running on the kotlin coroutines.</p><p>Before getting into this tutorial, If you are not familiar with kotlin coroutines, I strongly recommend you to read another tutorial on kotlin coroutines.</p><p><a href="https://howtodoandroid.com/kotlin-coroutines-android/"><strong>Kotlin Coroutines for Android Development</strong></a></p><p>In Kotlin Coroutines, we can handle the exceptions in two ways, one is using the try/catch block, another way is using the CoroutineExceptionHandler. let’s see how to implement both on kotlin coroutines.</p><h3>Handling Exception With Try / Catch</h3><p>In this method, we can use try/ catch in the way we are using the kotlin programming. But when we are working with kotlin coroutines, we need to put the try/catch block inside the Coroutine Scope Functions.</p><pre>fun handleExceptionWithTryCatch() {<br>    viewModelScope.launch() <strong>{<br>        </strong>try {<br>            val movies = ApiService.getInstance().getAllMovies401()<br>            movieList.postValue(movies)<br>        } catch (e: Exception) {<br>            Log.d(&quot;Exception&quot;, &quot;${e.message.toString()} handled !&quot;)<br>        }<br>    <strong>}<br></strong>}</pre><p>In the above code, I have created a <strong>ViewModelScope</strong>, that is Coroutines Scope Function to perform a networking operation. The API call returns 401 Exception, In normal cases, it will crash the application. But we are using try/catch around the API call. So the exception will be handled.</p><p><strong>Output</strong>:</p><pre><strong>com.example.kotlincoroutines D/Exception:</strong> HTTP 401 401 Unauthorized handled !</pre><h3>Handle Exception And Return Result</h3><p>In some cases, we need to return the default response when the exception occurs. To do this we need to add the default response in the catch block to return the default response. If we are using multiple operations then we need to use separate try/catch blocks to handle to separately.</p><pre>fun returnDefaultResultOnException() {<br>    viewModelScope.launch <strong>{<br>        </strong>try {<br>            val movie1 = try {<br>                ApiService.getInstance().getAllMovies()<br>            } catch (e: Exception) {<br>                listOf()<br>            }<br><br>            val movie2 = try {<br>                ApiService.getInstance().getAllMovies401()<br>            } catch (e: Exception) {<br>                listOf()<br>            }<br><br>            Log.d(&quot;Movie 1&quot;, movie1.toString())<br>            Log.d(&quot;Movie 2&quot;, movie2.toString())<br><br>        } catch (e: Exception) {<br>            Log.d(&quot;Exception&quot;, &quot;${e.message.<em>toString</em>()} handled !&quot;)<br>        }<br>    <strong>}<br></strong>}</pre><p>In the above code, I am called two API calls. The first API call returns a successful response with a list of movies. But the second API call returns 401 exceptions. So, I have handled that API using the try/catch block and returned the empty movie list as a response.</p><p><strong>Output:</strong></p><pre><strong>com.example.kotlincoroutines D/Movie 1:</strong> [Movie(category=Latest, imageUrl=https://howtodoandroid.com/images/coco.jpg, name=Coco, desc=Coco is a 2017 American 3D computer-animated musical..<br><strong>com.example.kotlincoroutines D/Movie 2:</strong> []</pre><h3>Handling Exception With CoroutineExceptionHandler</h3><p>In this way, we need to attach the separate CoroutineExceptionHandler variable and attach this variable to Coroutine Builder. So, when the exception occurs in the coroutine scope it will be forwarded to the exception handler.</p><pre>private val <em>handler </em>= CoroutineExceptionHandler <strong>{ </strong>_, exception <strong>-&gt;<br>    </strong>Log.d(&quot;Exception&quot;, &quot;${exception.message.toString()} handled !&quot;)<br><strong>}<br><br></strong>fun handleExceptionWithCoroutineExceptionHandler() {<br>    viewModelScope.launch(<em>handler</em>) <strong>{<br>        </strong>val moviesList = ApiService.getInstance().getAllMovies401()<br>        movieList.postValue(moviesList)<br>    <strong>}<br></strong>}</pre><p>In the above code, I have created the <strong>CoroutineExceptionHandler </strong>variable and attached that variable to ViewModelScope. Now, The API call returns the 401 Exception. So the exception will be directed to the exception handler to handle it.</p><p>In this way, we have a generic exception handler and attached the multiple Coroutine Builder.</p><p><strong>Output:</strong></p><pre>com.example.kotlincoroutines D/Exception: HTTP 401 401 Unauthorized handled !</pre><h3>Canceling the Kotlin Coroutine</h3><p>when the user leaves the screen or user wants to cancel some operation, then we need to cancel the operation running on the coroutine scope. to do this first, we need to create a Coroutine Scope variable called <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html"><strong>Job</strong></a>. Job used to do operation on coroutines including canceling.</p><pre>var <em>printingJob</em>: Job? = null<br><br>fun startPrint() {<br><br>    <em>printingJob </em>= viewModelScope.launch <strong>{<br><br>        </strong>try {<br>            for (i in 1..1000) {<br>                delay(20)<br>                <em>println</em>(i)<br>            }<br>        } catch (e: Exception) {<br>            Log.d(&quot;Exception&quot;, &quot;${e.message.<em>toString</em>()} handled !&quot;)<br>        } finally {<br>            Log.d(&quot;finally&quot;, &quot;clear all resources&quot;)<br>        }<br>    <strong>}<br></strong>}<br><br>fun stopPrint() {<br>    <em>printingJob</em>?.cancel()<br>}</pre><p>In the above code, I have created a job variable and by calling the <strong>startPrint()</strong> function I will set the coroutine scope instance into it. Once started, it will print 1 to 1000 in the delay of 20 milliseconds.</p><p>whenever we need to cancel the job need to call the <strong>stopPrint()</strong> function to call the <strong>cancel()</strong> on the job.</p><p><strong>Output:</strong></p><pre>com.example.kotlincoroutines I/System.out: 86 com.example.kotlincoroutines I/System.out: 87 com.example.kotlincoroutines I/System.out: 88 com.example.kotlincoroutines I/System.out: 89 com.example.kotlincoroutines I/System.out: 90 com.example.kotlincoroutines D/Exception: Timed out waiting for 2000 ms handled ! com.example.kotlincoroutines D/finally: clear all resources</pre><h3>Timeout on Kotlin Coroutine</h3><p>Are you want to cancel the particular operation, if it takes a long time to complete in kotlin coroutines. Then you need to run the operation with <strong>withTimeout(timeInMilliseconds)</strong> function inside the coroutine scope. This will cancel the operation automatically after the defined time is reached.</p><pre>fun startPrintWithTimeout() {<br><br>    viewModelScope.launch <strong>{<br>        </strong>try {<br>            withTimeout(2000) <strong>{<br>                </strong>for (i in 1..1000) {<br>                    delay(20)<br>                    <em>println</em>(i)<br>                }<br>            <strong>}<br>        </strong>} catch (e: Exception) {<br>            Log.d(&quot;Exception&quot;, &quot;${e.message.<em>toString</em>()} handled !&quot;)<br>        }<br>        finally {<br>            Log.d(&quot;finally&quot;, &quot;clear all resources&quot;)<br>        }<br>    <strong>}<br></strong>}</pre><p>In the above code, I am printing 1 to 1000 numbers in a 20 milliseconds delay inside the ViewModelScope. Also, I have surrounded the printing operation with the <strong>withTimeOut(2000)</strong> function. So, the printing operation will be canceled after 2000 milliseconds. Also, the printing operation is surrounded by a try/catch block. So the canceled operation with be caught.</p><p><strong>Output:</strong></p><pre>com.example.kotlincoroutines I/System.out: 71 com.example.kotlincoroutines I/System.out: 72 com.example.kotlincoroutines I/System.out: 73 com.example.kotlincoroutines I/System.out: 74 com.example.kotlincoroutines D/Exception: Timed out waiting for 2000 ms handled ! com.example.kotlincoroutines D/finally: clear all resources</pre><p>you can download this example on <a href="https://github.com/velmurugan-murugesan/Android-Example/tree/master/KotlinCoroutines"><strong>Github</strong></a>.</p><p><strong>What’s Next:</strong></p><ul><li><a href="https://medium.com/android-beginners/kotlin-scope-functions-explained-example-7826a103af0">Kotlin Scope Functions Explained [Example]</a></li><li><a href="https://medium.com/android-beginners/koin-dependency-injection-framework-for-android-aa34c0737956">Koin — Dependency Injection Framework For Android</a></li></ul><p><strong>Conclusion</strong></p><p>I hope you learned about the kotlin coroutine and how to handle the exception and cancel the kotlin coroutines. let me know your feedback in the comments.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/kotlin-coroutines-exception-handling/"><em>https://howtodoandroid.com</em></a><em> on November 25, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9047457ee6d8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/kotlin-coroutines-exception-handling-and-cancellation-9047457ee6d8">Kotlin Coroutines — Exception Handling and Cancellation</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin Scope Functions Explained [Example]]]></title>
            <link>https://medium.com/android-beginners/kotlin-scope-functions-explained-example-7826a103af0?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/7826a103af0</guid>
            <category><![CDATA[kotlinandroid]]></category>
            <category><![CDATA[kotlin-scope-functions]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[function-scope]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Mon, 27 Sep 2021 11:35:28 GMT</pubDate>
            <atom:updated>2021-11-23T16:06:11.854Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bWs7L4xsPJgohp7l.png" /></figure><p>By definition, Scoped functions are functions that execute a block of code within the context of an object.</p><p>Kotlin “scope functions” are functions that allow for changing the scope, or the range, of a variable. There are five such functions included in the Kotlin standard library: <strong>apply</strong>, <strong>run</strong>, <strong>with</strong>, <strong>let</strong>, and <strong>also</strong>.</p><p>before getting started into scope functions, i have explained about the basic of kotlin in details.</p><ul><li><a href="https://medium.com/swlh/beginning-android-development-with-kotlin-284adaf938a5">Beginning Android Development with Kotlin</a></li><li><a href="https://medium.com/android-beginners/koin-dependency-injection-framework-for-android-aa34c0737956">Koin — Dependency Injection Framework For Android</a></li><li><a href="https://medium.com/android-beginners/ktor-networking-client-for-android-howtodoandroid-com-70de50be8a88">Ktor — Networking Client For Android — Howtodoandroid.com</a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LKcSbd2JwsQi9sACVoHmVw.png" /></figure><h3>Object References</h3><p>To use these functions, we must understand a couple of things.</p><p>Inside a lambda of a scope function, <strong>this</strong>(lambda receiver) is used to access the context object. The same object can be accessed by using <strong>it</strong>(lambda argument). In general, both can perform similar things.</p><h3>This</h3><p>Inside a scope function, you will be able to reference the context object by a short word (<strong><em>this</em></strong>), instead of the name itself.</p><p><strong>Note</strong>: We can exclude this keyword to refer to members of the class.</p><pre>fun main() {<br>    var user = User(&quot;Joe&quot;,&quot;London&quot;)<br>    val username = with(user) {<br>        name = &quot;Palani&quot;<br>        address = &quot;India&quot;<br>        println(&quot;Name = $name , Address = $address&quot;)<br>        name<br>    }<br>}<br><br>data class User(var name: String, var address: String)</pre><h3>It</h3><p>‘ <strong>let</strong>’ and ‘ <strong>also</strong> ‘ functions refer to the object’s context as a lambda argument.</p><pre>fun main() {<br>    var user = User(&quot;Joe&quot;,&quot;London&quot;)<br>    user.let {<br>        println(&quot;Name : ${it.name}&quot;)<br>        println(&quot;Address : ${it.address}&quot;)<br>    }<br>}<br><br>data class User(var name: String, var address: String)</pre><h3>Return values</h3><p>There are two types of return values that a scope function can return:</p><h4>Lambda result</h4><p>If we write any expression at the end of the code block, it becomes the return value for the scope function. Return value for ‘ <strong>let</strong>’, ‘ <strong>run</strong>’, and ‘ <strong>with</strong> ‘ functions is the lambda result.</p><pre>fun main() {<br>    var user = User(&quot;Joe&quot;,&quot;London&quot;)<br>    val updatedUsername = user.let {<br>        it.name = &quot;John&quot;<br>        it.name<br>    }<br>    println(&quot;Updated Username : $updatedUsername&quot;)<br>}<br><br>data class User(var name: String, var address: String)</pre><h3>Context object</h3><p>‘ <strong>apply</strong>’ and ‘ <strong>also’ </strong>functions return the context object itself. In this case, we don’t need to specify the return value. The context object is automatically returned.</p><pre>fun main() {<br>    var user = User(&quot;Joe&quot;,&quot;London&quot;)<br>    val updatedUser = user.apply {<br>        name = &quot;John&quot;    <br>    }<br>    println(&quot;Updated Username : ${updatedUser.name}&quot;)<br>}<br><br>data class User(var name: String, var address: String)</pre><p>Check the below table for the comparison.</p><p>let’s see the kotlin scope functions in detail.</p><h3>Let</h3><p>Mostly used for null checks, when applying <strong><em>?.let </em></strong>on an object, we can rest safe that every time we access that object inside the scope function, the object will be <strong>not null</strong>. To reference the object inside the scope function, we use the keyword <strong>it</strong>.</p><ul><li><strong>Context Object — it</strong></li><li><strong>Returns — last statement</strong></li><li><strong>Use case</strong> — let function is often used to provide null safety calls. Use safe call operator(?.) with ‘let’ for null safety. It executes the block only with the non-null value.</li></ul><pre>fun main() {<br>    <br>    var user:User? = null<br>    user?.let {<br>        println(&quot;First Time : User $user&quot;)<br>    }<br>    user = User(&quot;John&quot;,&quot;India&quot;)<br>    user?.let {<br>        println(&quot;Second Time : User $user&quot;)<br>    }<br>}<br><br>data class User(var name: String, var address: String)</pre><h3>Run</h3><p>‘run’ function can be said as the combination of ‘ <strong>let</strong>’ and ‘ <strong>with</strong> ‘ functions.</p><ul><li><strong>Context Object</strong> — it</li><li><strong>Returns </strong>— last statement</li><li><strong>Use Case</strong> — Used when the object lambda contains both initialization and the computation of the return value. Using run we can perform null safety calls as well as other computations.</li></ul><p>It is the only scope function that has two variants.</p><h3>run as extension</h3><p>used to create a scope to run an operation over an object, and get a result.</p><pre>fun main() {<br>    val user = User(&quot;mani&quot;,&quot;India&quot;)<br>    val username = user?.run {<br>        name = generateFullName(name)<br>        name<br>    }<br>    println(username)<br>}<br><br>fun generateFullName(name: String) : String {<br>    return name + &quot; kandam&quot;<br>}<br><br>data class User(var name: String, var address: String)</pre><p><strong>Note: </strong>run returns the last statement of the function.</p><h3>run as function</h3><p>reduce the scope of certain variables, to avoid unnecessary access.</p><pre>fun main() {<br>    val user = User(&quot;mani&quot;,&quot;India&quot;)<br>    <br>    val username = run {<br>        generateFullName(user.name)<br>    }<br>    println(username)<br>}<br><br>fun generateFullName(name: String) : String {<br>    return name + &quot; kandam&quot;<br>}<br><br>data class User(var name: String, var address: String)</pre><h3>With</h3><p>Similar to <strong>apply </strong>function, with is also used to change properties of an instance i.e. object configuration. The only difference is <strong>with </strong>is not an extension function. The last expression of with function returns a result.</p><ul><li><strong>Context Object </strong>— this</li><li><strong>Returns </strong>— last statement</li><li><strong>Use Case</strong> — Run multiple operations on an object</li></ul><pre>fun main() {<br>    val user = User(&quot;mani&quot;,&quot;India&quot;)<br>    <br>    val username = with(user) {<br>    	name = &quot;Sathish&quot;<br>        address = &quot;USA&quot;<br>        name<br>    }<br>    <br>    println(username)<br>    <br>}<br><br>data class User(var name: String, var address: String)</pre><h3>Apply</h3><p>Basically, if you are initializing an object, and setting a bunch of properties like in this case, you have a pretty solid candidate to <strong><em>apply </em></strong>this scope function.</p><ul><li><strong>Context Object — </strong>this</li><li><strong>Returns </strong>— same object</li><li><strong>Use Case — </strong>Initialize and configure an object</li></ul><pre>fun main() {<br>    val user = User(&quot;mani&quot;,&quot;India&quot;)<br>    <br>    val updatedUser = user.apply {<br>        name = &quot;Siva&quot;<br>        address = &quot;London&quot;<br>    }<br>    <br>    println(updatedUser)<br>    <br>}<br><br>data class User(var name: String, var address: String)</pre><h3>Also</h3><p>A common use also is for side effects without modifying the object. We can use it for doing some operations on the intermediate results. also does not transform the object. It returns the same object.</p><ul><li><strong>Context Object </strong>— it</li><li><strong>Returns </strong>— same object</li><li><strong>Use Case </strong>— It is used where we have to perform additional operations when we have initialized the object members.</li></ul><pre>fun main() {<br>    val user = User(&quot;mani&quot;,&quot;India&quot;)<br>    <br>    val updatedUser = user.apply {<br>        name = &quot;Siva&quot;<br>        address = &quot;London&quot;<br>    }.also {<br>        println(it)  <br>    }<br>   <br>}<br><br>data class User(var name: String, var address: String)</pre><p>That’s it. Thanks for reading.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/kotlin-scope-functions/"><em>https://howtodoandroid.com</em></a><em> on September 17, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7826a103af0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/kotlin-scope-functions-explained-example-7826a103af0">Kotlin Scope Functions Explained [Example]</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Navigation rail — Material Component For Android]]></title>
            <link>https://medium.com/android-beginners/navigation-rail-material-component-for-android-58a94b443439?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/58a94b443439</guid>
            <category><![CDATA[android-development]]></category>
            <category><![CDATA[material-design]]></category>
            <category><![CDATA[android-navigation]]></category>
            <category><![CDATA[navigationrail]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Thu, 16 Sep 2021 13:32:38 GMT</pubDate>
            <atom:updated>2021-11-23T16:08:41.805Z</atom:updated>
            <content:encoded><![CDATA[<h3>Navigation rail — Material Component For Android</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZYidm_Gpccehw3Ne.png" /></figure><p>The rail is a side navigation component that displays three to seven app destinations and, optionally, a Floating Action Button. Each destination is represented by an icon and a text label.</p><p>The rail can function on its own at larger screen sizes, such as desktop and tablet. When users transition between screen sizes and devices, the rail can also complement other navigation components, such as bottom navigation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/593/1*JoRztg5t5MpgtlOomw0WaQ.png" /></figure><p>Before getting into details, Checkout my other post on material design,</p><ul><li><a href="https://medium.com/analytics-vidhya/sliders-material-component-for-android-5be61bbe6726">Sliders — Material Component For Android</a></li><li><a href="https://medium.com/android-beginners/shapeableimageview-material-components-for-android-cac6edac2c0d">ShapeableImageView — Material components for android</a></li><li><a href="https://velmurugan-murugesan.medium.com/progress-indicators-material-components-for-android-77f637d35036">Progress Indicators — Material Components For Android</a></li><li><a href="https://medium.com/android-beginners/material-chips-material-components-for-android-dd0ef942e5ce">Android Chips — Material Component For Android</a></li></ul><h4>Navigation rails shouldn’t be used for:</h4><ul><li>Small screen sizes</li><li>Single tasks, such as viewing a single email</li><li>Secondary navigation destinations</li></ul><p>Before we can get started, you need to add the dependency for the Android Material Components library. The Navigation Rail is only currently available in the latest release of1.4.0.</p><pre>implementation &#39;com.google.android.material:material:1.4.0&#39;</pre><h3>Adding Navigation Rail in layout</h3><p>Create a new layout file or just add the NavigationRailView to one of your existing layouts like in the following XML snippet.</p><pre>&lt;com.google.android.material.navigationrail.NavigationRailView<br>    android:id=&quot;@+id/navigation_rail&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    app:menu=&quot;@menu/navigation_rail_menu&quot;<br>    app:layout_constraintStart_toStartOf=&quot;parent&quot;<br>    app:layout_constraintTop_toTopOf=&quot;parent&quot;<br>    style=&quot;@style/Widget.MaterialComponents.NavigationRailView.Colored&quot; /&gt;</pre><p>When adding this view to your layout, there are some typical guidelines that should be followed. These most likely depend on what your view hierarchy consists of, but as a general guide:</p><ul><li>The Navigation Rail should sit below the TopBar of the current screen. This Rail should not overlap the top bar or be shown underneath this. Its height should fill the space between the bottom of the top app bar and the bottom of the screen</li><li>The Navigation Rail should be shown at the side of the main content area of the current screen. It should not be shown on top of this content, instead the content area should be shown next to the Navigation Rail.</li></ul><h3>Adding Menu</h3><p>The parameter <strong>app:menu</strong> takes a menu reference and holds all the navigation views to be displayed in the NavigationRailas menu items.</p><pre>&lt;com.google.android.material.navigationrail.NavigationRailView<br>    android:id=&quot;@+id/navigation_rail&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    app:menu=&quot;@menu/navigation_rail_menu&quot; /&gt;</pre><p>An example menu <strong>navigation_rail_menu.xml</strong> look like this:</p><pre>&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;<br>    &lt;item<br>        android:id=&quot;@+id/inbox&quot;<br>        android:enabled=&quot;true&quot;<br>        android:icon=&quot;@drawable/ic_baseline_inbox_24&quot;<br>        android:title=&quot;Inbox&quot;/&gt;<br>    &lt;item<br>        android:id=&quot;@+id/sent&quot;<br>        android:enabled=&quot;true&quot;<br>        android:icon=&quot;@drawable/ic_baseline_send_24&quot;<br>        android:title=&quot;Sent&quot;/&gt;<br>    &lt;item<br>        android:id=&quot;@+id/draft&quot;<br>        android:enabled=&quot;true&quot;<br>        android:icon=&quot;@drawable/ic_baseline_drafts_24&quot;<br>        android:title=&quot;Draft&quot;/&gt;<br>    &lt;item<br>        android:id=&quot;@+id/trash&quot;<br>        android:enabled=&quot;true&quot;<br>        android:icon=&quot;@drawable/ic_baseline_restore_from_trash_24&quot;<br>        android:title=&quot;Trash&quot;/&gt;<br>&lt;/menu&gt;</pre><h3>Menu Gravity</h3><p>Navigation rail destinations can be aligned as a group to the top, bottom, or center of a layout. On tablets, bottom alignment can make destinations easier for a user to reach with their thumbs.</p><p>app:menuGravity=”top | center | bottom”</p><pre>&lt;com.google.android.material.navigationrail.NavigationRailView<br>    android:id=&quot;@+id/navigation_rail&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    app:menu=&quot;@menu/navigation_rail_menu&quot;<br>    app:menuGravity=&quot;top&quot; /&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*zJ7CoXlrdiKH7i7_6tCQOw.png" /></figure><h3>Menu Label Visibility</h3><p>The label is only being shown for the currently selected item within the Rail. This is the default behavior for the label visibility and we can control this using the <strong>labelVisibilityMode </strong>attribute.</p><p>app:labelVisibilityMode=”auto | labeled | selected | unlabeled”</p><pre>&lt;com.google.android.material.navigationrail.NavigationRailView<br>    android:id=&quot;@+id/navigation_rail&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    app:menu=&quot;@menu/navigation_rail_menu&quot;<br>    app:labelVisibilityMode=&quot;auto&quot;<br>    app:menuGravity=&quot;top&quot;/&gt;</pre><p><strong>auto </strong>— when there are more than 3 items the Rail will use the selected option, otherwise, the labeled option will be applied.</p><p><strong>labeled </strong>— Persistent text labels are visible at all times, regardless of a destination’s state.</p><p><strong>selected </strong>— Selected text labels appear only when a destination is activated.</p><p><strong>unlabeled </strong>— If all icons in the navigation rail can be expected to have clear meaning to users, labels can be omitted as a group.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*XD_098xKcO1Rioa_3J9xSA.png" /></figure><h3>Adding Layout Header</h3><p>The rail provides a convenient container for anchoring the Floating Action Button (FAB) to the top of a screen, placing the app’s key action above navigation destinations.</p><p>Other than showing a menu inside of our Navigation Rail, we can provide a layout reference for the <strong>headerLayout</strong> attribute of the view.</p><p>app:headerLayout=”@layout/layout_fab”</p><pre>&lt;com.google.android.material.navigationrail.NavigationRailView<br>    android:id=&quot;@+id/navigation_rail&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;match_parent&quot;<br>    app:menu=&quot;@menu/navigation_rail_menu&quot;<br>    app:headerLayout=&quot;@layout/layout_fab&quot;<br>    app:labelVisibilityMode=&quot;labeled&quot;<br>    app:menuGravity=&quot;top&quot; /&gt;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/579/1*UyO9mPpp6gB5_05rPQHV-Q.png" /></figure><p><strong>layout_fab .xml</strong></p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br>&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br>    android:layout_width=&quot;wrap_content&quot;<br>    android:layout_height=&quot;wrap_content&quot;<br>    android:orientation=&quot;vertical&quot;&gt;<br><br>    &lt;com.google.android.material.floatingactionbutton.FloatingActionButton<br>        android:id=&quot;@+id/fabMain&quot;<br>        android:layout_width=&quot;wrap_content&quot;<br>        android:layout_height=&quot;wrap_content&quot;<br>        android:src=&quot;@android:drawable/ic_input_add&quot;/&gt;<br><br>&lt;/LinearLayout&gt;</pre><h3>Styling the Navigation Rail</h3><p>There are several bundled styles that can be used to control how the Navigation Rail is displayed on the screen.</p><p><strong>Default</strong></p><p>With this default style applied, the different parts of the Navigation Rail have the following attributes applied to them:</p><ul><li>Rail Width: <strong>72dp</strong></li><li>Rail background: <strong>colorSurface</strong></li><li>Selected Icon color: <strong>colorPrimary</strong></li><li>Unselected Icon color: <strong>colorOnSurface</strong> (at 60%)</li></ul><pre>style=&quot;@style/Widget.MaterialComponents.NavigationRailView&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/553/1*b26x3hPUaM6kBmY37JqcRA.png" /></figure><p><strong>Colored</strong></p><p>Similar to the <strong>PrimarySurface</strong> style.</p><ul><li>Rail Width: <strong>72dp</strong></li><li>Rail background: <strong>colorPrimary</strong></li><li>Selected Icon color: <strong>colorOnPrimary</strong></li><li>Unselected Icon color: <strong>colorOnPrimary</strong> (at 60%)</li></ul><pre>style=&quot;@style/Widget.MaterialComponents.NavigationRailView.Colored&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*IHYWZ_1zYB29hBdlIHGMXg.png" /></figure><p><strong>Compact</strong></p><p>In some cases, we may want our Navigation Rail to take up less width in the screen. If the default width appears to take up more space than is needed, the following style can be used to use a reduced width:</p><ul><li>Rail Width: <strong>52dp</strong></li><li>Rail background: <strong>colorSurface</strong></li><li>Selected Icon color: <strong>colorPrimary</strong></li><li>Unselected Icon color: <strong>colorOnSurface</strong> (at 60%)</li></ul><pre>style=&quot;@style/Widget.MaterialComponents.NavigationRailView.Compact&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*oYJ_C6Wc0vCg0YcA4HK__Q.png" /></figure><p><strong>Colored.Compact</strong></p><p>Similar to the <strong>PrimarySurface</strong> style that we previously covered, the <strong>Colored.Compact</strong> style uses the same attributes here with the small change of width:</p><ul><li>Rail Width: <strong>52dp</strong></li><li>Rail background: <strong>colorPrimary</strong></li><li>Selected Icon color: <strong>colorOnPrimary</strong></li><li>Unselected Icon color: <strong>colorOnPrimary</strong> (at 60%)</li></ul><pre>style=&quot;@style/Widget.MaterialComponents.NavigationRailView.Colored.Compact&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/626/1*bPMk0-hp49vC9RrDSHWzpw.png" /></figure><p><strong>PrimarySurface</strong></p><p>The W <strong>idget.MaterialComponents.NavigationRailView.PrimarySurface </strong>style will automatically switch between the component’s primary-colored style in light theme and surface-colored style in dark theme.</p><ul><li>Rail Width: <strong>72dp</strong></li><li>Rail background: <strong>colorPrimary</strong></li><li>Selected Icon color: <strong>colorOnPrimary</strong></li><li>Unselected Icon color: <strong>colorOnPrimary</strong> (at 60%)</li></ul><pre>style=&quot;@style/Widget.MaterialComponents.NavigationRailView.PrimarySurface&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/599/1*h1MCF_jUCOSDtNKJmTek4A.png" /></figure><h3>Displaying Badges</h3><p>Rail icons can include badges in the upper right corner of the icon. Badges convey dynamic information about the associated destination, such as counts or status.</p><p>To apply a badge we need to utilize the <strong>getOrCreateBadge</strong> function on our navigation rail.</p><pre>val inboxBadge = mainBinding.navigationRail.getOrCreateBadge(R.id.<em>inbox</em>)</pre><p>Change visibility of the badge using the visibility parameter.</p><pre>inboxBadge.isVisible = true</pre><p>Set the badge text using the number parameter.</p><pre>inboxBadge.number = 10</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/342/1*9lqZDZXILBEAspidUsRDPw.png" /></figure><h3>Badge Gravity</h3><p>We can control the positioning of the badge using the <strong>badgeGravity</strong> attribute of the BadgeDrawable.</p><pre>inboxBadge.<em>badgeGravity </em>= BadgeDrawable.<em>TOP_START</em></pre><p>We can set the different badge gravity attributes.</p><ul><li>TOP_END</li><li>TOP_START</li><li>BOTTOM_END</li><li>BOTTOM_START</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*tJ4CYQtSQOPuObQ6HbYLNg.png" /></figure><h3>Badge Color</h3><p>We can set the colors for the badges individually, by using the <strong>backgroundColor</strong> and <strong>badgeTextColor</strong> on any of the BadgeDrawable references.</p><pre>val inboxBadge = mainBinding.navigationRail.getOrCreateBadge(R.id.<em>inbox</em>)<br>inboxBadge.<em>isVisible </em>= true<br>inboxBadge.<em>number </em>= 10<br>inboxBadge.<em>badgeGravity </em>= BadgeDrawable.<em>TOP_END<br></em>inboxBadge.<em>backgroundColor </em>= Color.<em>GRAY<br></em>inboxBadge.<em>badgeTextColor </em>= Color.<em>WHITE</em></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/361/1*257Pd9bkqcj7VwnfOtQZCA.png" /></figure><h3>Badge Overflow</h3><p>If we want to manually adjust the maximum number of characters that are to be displayed within a badge, we can do so using the <strong>maxCharacterCount </strong>attribute.</p><pre>val inboxBadge = mainBinding.navigationRail.getOrCreateBadge(R.id.<em>inbox</em>)<br>inboxBadge.<em>isVisible </em>= true<br>inboxBadge.<em>number </em>= 56<em><br></em>inboxBadge.<em>maxCharacterCount </em>= 2</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/367/1*VQvWIxMJi00rLvSNObtj3w.png" /></figure><h3>Badge Offset</h3><p>The navigation badges are displayed outside of the icon area with enough space to not cause any overlapping. The <strong>verticalOffset</strong> and <strong>horizontalOffset</strong> attributes can be used to provide a pixel value offset for our navigation badge.</p><pre>val inboxBadge = mainBinding.navigationRail.getOrCreateBadge(R.id.<em>inbox</em>)<br>inboxBadge.<em>isVisible </em>= true<br>inboxBadge.<em>number </em>= 56<br>inboxBadge.<em>badgeGravity </em>= BadgeDrawable.<em>TOP_END<br></em>inboxBadge.<em>backgroundColor </em>= Color.<em>GRAY<br></em>inboxBadge.<em>badgeTextColor </em>= Color.<em>WHITE<br></em>inboxBadge.<em>maxCharacterCount </em>= 2<br>inboxBadge.<em>verticalOffset </em>= 10<br>inboxBadge.<em>horizontalOffset </em>= 10</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/360/1*GKfSmYtHIevj9jMqRFA1KA.png" /></figure><h3>Handling Item Selected</h3><p>we can set an item selection listener on our Navigation Rail and use this to react to any interactions with menu items — using the ID of the menu item to handle the corresponding menu item.</p><pre>mainBinding.navigationRail.setOnItemSelectedListener <strong>{ </strong>item <strong>-&gt;<br>    </strong>when(item.<em>itemId</em>) {<br>        R.id.<em>inbox </em>-&gt; {<br>            // Respond to navigation item 1 click<br>            true<br>        }<br>        R.id.<em>sent </em>-&gt; {<br>            true<br>        }<br>        R.id.<em>draft </em>-&gt; {<br>            true<br>        }<br>        R.id.<em>trash </em>-&gt; {<br>            true<br>        }<br>        else -&gt; false<br>    }<br><strong>}</strong></pre><p>There’s also a method for detecting when navigation items have been reselected:</p><pre>mainBinding.navigationRail.setOnNavigationItemReselectedListener { item -&gt;<br>    when(item.itemId) {<br>        R.id.item1 -&gt; {<br>            // Respond to navigation item 1 reselection<br>        }<br>        R.id.item2 -&gt; {<br>            // Respond to navigation item 2 reselection<br>        }<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/966/1*KmJeouUM9_TjmxF2Kw57Hg.gif" /></figure><p>That’s it. Thanks for reading.</p><p>You can download this example on <a href="https://github.com/velmurugan-murugesan/Android-Example/tree/master/NavigationRailExample"><strong>Github</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/navigation-rail-material-component-android/"><em>https://howtodoandroid.com</em></a><em> on September 15, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=58a94b443439" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/navigation-rail-material-component-for-android-58a94b443439">Navigation rail — Material Component For Android</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Jetpack compose — Retrofit with Recyclerview]]></title>
            <link>https://medium.com/android-beginners/jetpack-compose-retrofit-with-recyclerview-43a84a9bc269?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/43a84a9bc269</guid>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[recyclerview]]></category>
            <category><![CDATA[retrofit]]></category>
            <category><![CDATA[mvvm]]></category>
            <category><![CDATA[androiddev]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Tue, 14 Sep 2021 05:37:35 GMT</pubDate>
            <atom:updated>2021-11-23T16:10:24.545Z</atom:updated>
            <content:encoded><![CDATA[<h3>Jetpack compose — Retrofit with Recyclerview</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M_K1L5D475Z6RORQ.png" /></figure><p>In this post, I am going to explain about using the retrofit and recyclerview in jetpack compose with MVVM pattern. Everybody knows that the Jetpack Compose is a modern toolkit designed to simplify UI development.</p><p>Before jump in this example on retrofit and recyclerview. I have created posts on jetpack compose components, layouts, modifiers, and themes. go through this for a better understanding of jetpack compose.</p><ul><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-basic-components-a12f7902395b">Getting started with jetpack compose — Basic components</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-layouts-f974d23f656c">Getting started with jetpack compose — Layouts</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-modifiers-d3a61551af">Getting started with jetpack compose — Modifiers</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-constraintlayout-fdd18c666dd3">Getting started with jetpack compose — ConstraintLayout</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-theming-14be92c4cea7">Getting started with jetpack compose — Theming</a></li></ul><h3>Setup jetpack compose on android studio</h3><h4>Method 1 — Creating new Jetpack compose Project</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T0SVG2V0DgCOt6k9DPT9Og.png" /></figure><p>Create New Project by selecting “ <strong>Empty Compose Activity</strong> “, It will add all the Gradle dependencies in the Gradle file and MainAcitivity to accept composable. So, straightaway we can start working on the project.</p><h4>Method 2 — Migrate Existing Android Studio Project</h4><p>Add jetpack compose version in the project build.gradle file.</p><pre>buildscript {<br>    ext {<br>        compose_version = &#39;1.0.0&#39;<br>    }<br>    ...<br>}</pre><p>Then, add the build features and compose options in your module-level build.gradle file.</p><pre>compileOptions {<br>        sourceCompatibility &quot;1.8&quot;<br>        targetCompatibility &quot;1.8&quot;<br>    }<br>    kotlinOptions {<br>        jvmTarget = &#39;1.8&#39;<br>        useIR = true<br>    }<br>    buildFeatures {<br>        compose true<br>    }<br>    composeOptions {<br>        kotlinCompilerExtensionVersion compose_version<br>        kotlinCompilerVersion &#39;1.5.10&#39;<br>    }<br>    packagingOptions {<br>        resources {<br>            excludes += &#39;/META-INF/{AL2.0,LGPL2.1}&#39;<br>        }<br>    }</pre><p>The next step is to add the jetpack compose dependencies in the gradle file.</p><pre>implementation &quot;androidx.compose.ui:ui:$compose_version&quot;<br>    implementation &quot;androidx.compose.material:material:$compose_version&quot;<br>    implementation &quot;androidx.compose.ui:ui-tooling-preview:$compose_version&quot;<br>    implementation &#39;androidx.activity:activity-compose:1.3.1&#39;<br>    debugImplementation &quot;androidx.compose.ui:ui-tooling:$compose_version&quot;</pre><p>Finally, change your MainAcitivity.kt to extends <strong>ComponentActivity</strong>. Also, add the setContent to accept the composable content on <strong>oncreate()</strong>.</p><pre>class MainActivity : ComponentActivity() {<br>    override fun onCreate(savedInstanceState: Bundle?) {<br>        super.onCreate(savedInstanceState)<br>        setContent {<br>        }<br>    }<br>}</pre><h3>Setup Retrofit for jetpack compose</h3><p>To getting started with a retrofit first, we need to add the retrofit dependencies.</p><pre>implementation &#39;com.squareup.retrofit2:retrofit:2.9.0&#39; implementation &quot;com.squareup.okhttp3:okhttp:5.0.0-alpha.2&quot; implementation &#39;com.squareup.retrofit2:converter-gson:2.9.0&#39;</pre><p>Next, we need to create to ApiService to fetch data from the API.</p><p>In this example, I am using <strong>“https://howtodoandroid.com/apis/movielist.json&quot; </strong>API to get a list of movies. the response object will be,</p><pre>[{<br>        &quot;category&quot;: &quot;Latest&quot;,<br>        &quot;imageUrl&quot;: &quot;https://howtodoandroid.com/images/coco.jpg&quot;,<br>        &quot;name&quot;: &quot;Coco&quot;,<br>        &quot;desc&quot;: &quot;Coco is a 2017 American 3D computer-animated musical fantasy adventure film produced by Pixar&quot;<br>    },<br>    {<br>        &quot;category&quot;: &quot;Latest&quot;,<br>        &quot;imageUrl&quot;: &quot;https://howtodoandroid.com/images/terminator_2.jpg&quot;,<br>        &quot;name&quot;: &quot;Terminator 2: Judgment Day 3D&quot;,<br>        &quot;desc&quot;: &quot;Similar to Cameron&#39;s Titanic 3D, Lightstorm Entertainment oversaw the work on the 3D version of Terminator 2, which took nearly a year to finish.&quot;<br>    },<br>    ....<br>]</pre><p>So, let’s create a Model class to hold the response data.</p><p><strong>Model.kt</strong></p><pre>data class Movie(val name: String, val imageUrl: String, val desc: String, val category: String)</pre><p>Then, create an ApiService interface and a method to get list of movies.</p><pre>interface ApiService {<br><br>    @GET(&quot;movielist.json&quot;)<br>    suspend fun getMovies() : List&lt;Movie&gt;<br>}</pre><p>In this same ApiService, we can get the instance of the ApiService using the companion object.</p><pre>interface ApiService {<br><br>    @GET(&quot;movielist.json&quot;)<br>    suspend fun getMovies() : List&lt;Movie&gt;<br><br>    companion object {<br>        var apiService: ApiService? = null<br>        fun getInstance() : ApiService {<br>            if (apiService == null) {<br>                apiService = Retrofit.Builder()<br>                    .baseUrl(&quot;https://howtodoandroid.com/apis/&quot;)<br>                    .addConverterFactory(GsonConverterFactory.create())<br>                .build().create(ApiService::class.<em>java</em>)<br>            }<br>            return apiService!!<br>        }<br>    }<br><br>}</pre><p>Now, we have created ApiService for the API call. let’s create ViewModel to consume data.</p><h3>Setup ViewModel</h3><p>We can create a ViewModel by extending the <a href="https://developer.android.com/topic/libraries/architecture/viewmodel">ViewModel()</a> class. So, Create a class MainViewModel and extends the ViewModel.</p><pre>class MainViewModel : ViewModel() {<br><br>}</pre><p>Next, we need to create mutablestateof() observable to notify the changes to composable at runtime.</p><p>check this to know more about <a href="https://developer.android.com/jetpack/compose/state"><strong>State and Jetpack Compose | Android Developers</strong></a>.</p><p>Call the <strong>apiService.getMovies()</strong> inside the viewModelScope and set the response in the mutablestate variable.</p><pre>class MainViewModel : ViewModel() {<br>    var movieListResponse:List&lt;Movie&gt; by <em>mutableStateOf</em>(<em>listOf</em>())<br>    var errorMessage: String by <em>mutableStateOf</em>(&quot;&quot;)<br>    fun getMovieList() {<br>        <em>viewModelScope</em>.<em>launch </em><strong>{<br>            </strong>val apiService = ApiService.getInstance()<br>            try {<br>                val movieList = apiService.getMovies()<br>                movieListResponse = movieList<br>            }<br>            catch (e: Exception) {<br>                errorMessage = e.message.<em>toString</em>()<br>            }<br>        <strong>}<br>    </strong>}<br>}</pre><p>Now the data is ready. Next, we need to display the data using the LazyColumn composable component.</p><h3>Creating LazyColumn: Easy way to Recyclerview</h3><p>If you need to display a large number of items (or a list of an unknown length), using a layout such as a Column can cause performance issues, since all the items will be composed and laid out whether or not they are visible.</p><p>Compose provides a set of components that only compose and lay out items that are visible in the component’s viewport. These components include <strong>LazyColumn </strong>and <strong>LazyRow</strong>.</p><p>A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It’s similar to a Recyclerview in the classic Android View system.</p><p>check more about <a href="https://developer.android.com/reference/kotlin/androidx/compose/foundation/lazy/package-summary#lazycolumn"><strong>lazyColumn</strong></a>.</p><p>Let’s create a composable function for the movie item.</p><h4>MovieItem() composable</h4><p>in this example, I am using the coil library to load images from API. please add the coil dependency in Gradle file.</p><pre>implementation &quot;io.coil-kt:coil-compose:1.3.2&quot;</pre><p>I have created a movie item in Card and set corner radius 8dp and elevation. Also, created a row with 20% for the image and the remaining 80% for the text data.</p><p>I am not explaining the movie item components here. I have explained the composable components in another post. please check that for a better understanding of creating composable components.</p><p>the movie composable function code,</p><pre>@Composable<br>fun MovieItem(movie: Movie) {<br>    <em>Card</em>(<br>        modifier = Modifier<br>            .<em>padding</em>(8.<em>dp</em>, 4.<em>dp</em>)<br>            .<em>fillMaxWidth</em>()<br>            .<em>height</em>(110.<em>dp</em>), shape = <em>RoundedCornerShape</em>(8.<em>dp</em>), elevation = 4.<em>dp<br>    </em>) <strong>{<br>        </strong><em>Surface</em>() <strong>{<br><br>            </strong><em>Row</em>(<br>                Modifier<br>                    .<em>padding</em>(4.<em>dp</em>)<br>                    .<em>fillMaxSize</em>()<br>            ) <strong>{<br><br>                </strong><em>Image</em>(<br>                    painter = <em>rememberImagePainter</em>(<br>                        data = movie.imageUrl,<br><br>                        builder = <strong>{<br>                            </strong>scale(Scale.<em>FILL</em>)<br>                            placeholder(R.drawable.<em>placeholder</em>)<br>                            transformations(CircleCropTransformation())<br><br>                        <strong>}<br>                    </strong>),<br>                    contentDescription = movie.desc,<br>                    modifier = Modifier<br>                        .<em>fillMaxHeight</em>()<br>                        .<em>weight</em>(0.2f)<br>                )<br><br><br>                <em>Column</em>(<br>                    verticalArrangement = Arrangement.Center,<br>                    modifier = Modifier<br>                        .<em>padding</em>(4.<em>dp</em>)<br>                        .<em>fillMaxHeight</em>()<br>                        .<em>weight</em>(0.8f)<br>                ) <strong>{<br>                    </strong><em>Text</em>(<br>                        text = movie.name,<br>                        style = MaterialTheme.typography.subtitle1,<br>                        fontWeight = FontWeight.Bold<br>                    )<br>                    <em>Text</em>(<br>                        text = movie.category,<br>                        style = MaterialTheme.typography.caption,<br>                        modifier = Modifier<br>                            .<em>background</em>(<br>                                Color.LightGray<br>                            )<br>                            .<em>padding</em>(4.<em>dp</em>)<br>                    )<br>                    <em>Text</em>(<br>                        text = movie.desc,<br>                        style = MaterialTheme.typography.body1,<br>                        maxLines = 2,<br>                        overflow = TextOverflow.Ellipsis<br>                    )<br><br>                <strong>}<br>            }<br>        }<br>    }<br><br></strong>}</pre><p>the preview of the movie item,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/705/1*LyDeoRbwN0ps1TgTtZNerw.png" /></figure><p>The view for the movie item is ready. let’s use the lazyColumn to make it look like the recyclerview.</p><p>using lazyColumn, loop through all the items, and add the movie items.</p><pre>@Composable<br>fun MovieList(movieList: List&lt;Movie&gt;) {<br>    <em>LazyColumn </em><strong>{<br>        </strong><em>itemsIndexed</em>(items = movieList) <strong>{ </strong>index, item <strong>-&gt;<br>            </strong><em>MovieItem</em>(movie = item)<br>        <strong>}<br>    }<br></strong>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Brwrj7BUG98NBXDAY343lA.png" /></figure><h3>Making item Selectable</h3><p>To make the item in lazyColumn is selected. First, we need to create the mutableState() variable to save the selected item position.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*cZ-k0pksuiDNH5k9MSGb2A.png" /></figure><p>Also, pass the current index and selected item index to every item in the lazyColumn. along with the position we need to pass the lambda function for the click listener. on click of the movie item, we need to change the selected item position.</p><pre>@Composable<br>fun MovieList(movieList: List&lt;Movie&gt;) {<br>    var selectedIndex by <em>remember </em><strong>{ </strong><em>mutableStateOf</em>(-1) <strong>}<br>    </strong><em>LazyColumn </em><strong>{<br><br>        </strong><em>itemsIndexed</em>(items = movieList) <strong>{ </strong>index, item <strong>-&gt;<br>            </strong><em>MovieItem</em>(movie = item, index, selectedIndex) <strong>{ </strong>i <strong>-&gt;<br>                </strong>selectedIndex = i<br>            <strong>}<br>        }<br>    }<br><br></strong>}</pre><p>In this movie item compensable, we need to check that the current position and the selected position are the same or not. if same then we need to set the selected background for the item.</p><p>Also, add the clickable modifier for the movie item. by clicking the card, we need to change the selectedIndex . that will reload the composable and make the clicked item selected.</p><pre>@Composable<br>fun MovieItem(movie: Movie, index: Int, selectedIndex: Int, onClick: (Int) -&gt; Unit) {<br><br>    val backgroundColor =<br>        if (index == selectedIndex) MaterialTheme.colors.primary else MaterialTheme.colors.background<br>    <em>Card</em>(<br>        modifier = Modifier<br>            .<em>padding</em>(8.<em>dp</em>, 4.<em>dp</em>)<br>            .<em>fillMaxWidth</em>()<br>            .<em>clickable </em><strong>{ </strong>onClick(index) <strong>}<br>            </strong>.<em>height</em>(110.<em>dp</em>), shape = <em>RoundedCornerShape</em>(8.<em>dp</em>), elevation = 4.<em>dp<br>    </em>) <strong>{<br>        </strong><em>Surface</em>(color = backgroundColor) <strong>{</strong><br>    ....<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CiQ1DPCuq3oylCvXiygv9A.png" /></figure><p>That’s it. Thanks for reading. You can download this example on <a href="https://github.com/velmurugan-murugesan/JetpackCompose/tree/master/JetpackComposeMVVMRetrofitAndRecyclerview"><strong>Github</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/jetpack-compose-retrofit-recyclerview/"><em>https://howtodoandroid.com</em></a><em> on September 13, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=43a84a9bc269" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/jetpack-compose-retrofit-with-recyclerview-43a84a9bc269">Jetpack compose — Retrofit with Recyclerview</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting started with jetpack compose — Theming]]></title>
            <link>https://medium.com/android-beginners/getting-started-with-jetpack-compose-theming-14be92c4cea7?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/14be92c4cea7</guid>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[material-design]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[material-theming]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Tue, 14 Sep 2021 05:22:53 GMT</pubDate>
            <atom:updated>2021-11-23T16:26:42.894Z</atom:updated>
            <content:encoded><![CDATA[<h3>Getting started with jetpack compose — Theming</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*u4qt4JJSYvIbwYic.png" /></figure><p>Jetpack Compose implements Material Theming and supports a dark theme by default. You can customize color, typography, and shape theming values to fit your product’s brand, and get access to convenient functions for working with a system of dark themes (like isSystemInDarkTheme, lightColors, and darkColors).</p><p>The default MaterialTheme from the documentation looks like this:</p><pre><em>MaterialTheme</em>(<br>    colors = colors,<br>    typography = <em>Typography</em>,<br>    shapes = <em>Shapes</em>,<br>    content = content<br>)</pre><p>We can set custom attributes:</p><ul><li><strong>colors</strong>: A complete definition of the Material Color theme for this hierarchy.</li><li><strong>typography</strong>: A set of text styles to be used as this hierarchy’s typography system.</li><li><strong>shapes</strong>: A set of shapes to be used by the components in this hierarchy.</li></ul><p>Check out the example I have created for jetpack compose material theming:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/293/1*sPin2MMsCxoYxIoRzuDi3Q.gif" /></figure><p>you can download this example from <a href="https://github.com/velmurugan-murugesan/JetpackCompose/tree/master/JetpackComposeTheming"><strong>github</strong></a>.</p><p>If you’re new to Compose, I highly recommend going through the following articles:</p><ul><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-basic-components-a12f7902395b">Getting started with jetpack compose — Basic components</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-layouts-f974d23f656c">Getting started with jetpack compose — Layouts</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-modifiers-d3a61551af">Getting started with jetpack compose — Modifiers</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-constraintlayout-fdd18c666dd3">Getting started with jetpack compose — ConstraintLayout</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-scaffold-layout-ef8d901561e9">Getting started with jetpack compose — Scaffold layout</a></li></ul><p>Let’s see the material theme attributes in detail.</p><h3>Color</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BBUJaeFNRmI9wyo9sRIojQ.png" /></figure><p>Jetpack Compose uses the Color class from Compose’s graphics package. We have many ways to define a color, but there are two common ways we use it more frequently.</p><p>One Way is defining the hex code of the color</p><pre>val<em>Purple200 </em>= <em>Color</em>(0xFFBB86FC)</pre><p>The other way is specifying the RGB values to the Color class:</p><pre>val blue = Color(red = 0f, green = 0f, blue = 1f)</pre><p>Since ARGB Hex is just a bunch of jargon to describe what the heck “ 0XFF00bc00 &quot; means, let me translate:</p><ul><li>First two characters 0x tell the compiler that this is a hexadecimal number</li><li>Second two characters , “FF&quot; or &quot;DC&quot;, represent Transparency/Opaqueness/<strong>A</strong>lpha in Hex</li><li>The remaining six character pairs represent <strong>R</strong>ed, <strong>G</strong>reen, and <strong>B</strong>lue</li></ul><p>Create a file called something like Color.kt (the name does not matter) and fill it with immutable values:</p><p><strong>Color.kt</strong></p><pre>import androidx.compose.ui.graphics.Color<br><br>val <em>Purple200 </em>= <em>Color</em>(0xFFBB86FC)<br>val <em>Purple500 </em>= <em>Color</em>(0xFF6200EE)<br>val <em>Purple700 </em>= <em>Color</em>(0xFF3700B3)<br>val <em>Teal200 </em>= <em>Color</em>(0xFF03DAC5)</pre><p>Accessing the Color from the <strong>color.kt</strong> when required.</p><pre><em>Text</em>(text = &quot;Jetpack compose&quot; , color = <em>Purple500</em>)</pre><h3>Colors class</h3><p>The colors class allows us to define different <a href="https://material.io/design/color/the-color-system.html"><strong>Material Design Color System</strong></a>.</p><pre>class Colors(<br>    primary: Color,<br>    primaryVariant: Color,<br>    secondary: Color,<br>    secondaryVariant: Color,<br>    background: Color,<br>    surface: Color,<br>    error: Color,<br>    onPrimary: Color,<br>    onSecondary: Color,<br>    onBackground: Color,<br>    onSurface: Color,<br>    onError: Color,<br>    isLight: Boolean<br>)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DPAmUFOFfLBjnk38s4yzcw.png" /></figure><p>There are around 13 attributes in the constructor of Colors. Let&#39;s see what each attribute means.</p><ul><li><strong>Primary</strong> — color displayed most frequently across your app’s screens and components;</li><li><strong>Primary Variant</strong> — color is used to distinguish elements using primary colors, such as top app bar and the system bar.</li><li><strong>Secondary</strong> — color provides more ways to accent and distinguish your product. Having a secondary color is optional, and should be applied sparingly to accent select parts of your UI;</li><li><strong>SecondaryVariant</strong> — color is used to distinguish elements using secondary colours;</li><li><strong>Background</strong> — color appears behind scrollable content;</li><li><strong>Surface</strong> — color uses on surfaces of components, like cards and menus;</li><li><strong>Error</strong> — color used for indicating an error.</li><li><strong>OnPrimary</strong> — color of text and icons displayed on top of the primary color.</li><li><strong>OnSecondary</strong> — color of text and icons displayed on top of the secondary color;</li><li><strong>OnBackground</strong> — color of text and icons displayed on top of the background color;</li><li><strong>OnSurface</strong> — color of text and icons displayed on top of the surface color;</li><li><strong>OnError</strong> — color of text and icons displayed on top of the error color.</li><li><strong>IsLight </strong>— Whether these colors are considered as a “light” or “dark” set of colors.</li></ul><p>To make our support for DarkMode and LightMode easier, Jetpack Compose also provides two functions that generates default colors for these modes.</p><ul><li>darkColors</li><li>lightColors</li></ul><pre>private val <em>DarkColorPalette </em>= <em>darkColors</em>(<br>    primary = <em>Purple200</em>,<br>    primaryVariant = <em>Purple700</em>,<br>    secondary = <em>Teal200</em>,<br>    onPrimary = Color.White,<br>    onSecondary = Color.Black<br>)<br><br>private val <em>LightColorPalette </em>= <em>lightColors</em>(<br>    primary = <em>Purple500</em>,<br>    primaryVariant = <em>Purple700</em>,<br>    secondary = <em>Teal200</em>,<br>    onPrimary = Color.White,<br>    onSecondary = Color.Black<br>)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/850/1*2ycvNPy67fqKJ4Nu-4lDDA.png" /></figure><p>We have successfully created colors for the Material Theme. Let’s create the Typography.</p><h3>Typography</h3><p>The Typograph is a class that helps us to style the texts. With the help of the Typograph class, we can customize FontFamily, FontStyle, FontWeight, LetterSpacing, TextDecoration, Color, and many more attributes related to texts.</p><pre>class Typography(<br>    defaultFontFamily: FontFamily = FontFamily.Default,<br>    h1: TextStyle,<br>    h2: TextStyle,<br>    h3: TextStyle,<br>    h4: TextStyle,<br>    h5: TextStyle,<br>    h6: TextStyle,<br>    subtitle1: TextStyle,<br>    subtitle2: TextStyle,<br>    body1: TextStyle,<br>    body2: TextStyle,<br>    button: TextStyle,<br>    caption: TextStyle,<br>    overline: TextStyle<br>)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CAchOhm0yRtVp7BC4yBPCA.png" /><figcaption><a href="https://material.io/design/typography/the-type-system.html#type-scale">https://material.io/design/typography/the-type-system.html#type-scale</a></figcaption></figure><p>In addition to this, we should configure a Typography object with the following parameters:</p><ul><li><strong>h1</strong> is the largest headline, reserved for short and important text.</li><li><strong>h2</strong> is the second-largest headline, reserved for short and important text.</li><li><strong>h3</strong> is the third-largest headline, reserved for short and important text.</li><li><strong>h4</strong> is the fourth-largest headline, reserved for short and important text.</li><li><strong>h5</strong> is the fifth-largest headline, reserved for short and important text.</li><li><strong>h6</strong> is the sixth-largest headline, reserved for short and important text.</li><li><strong>subtitle1</strong> is the largest subtitle and is typically reserved for medium-emphasis text that is shorter in length.</li><li><strong>subtitle2</strong> is the smallest subtitle and is typically reserved for medium-emphasis text that is shorter in length.</li><li><strong>body1</strong> is the largest body and is typically reserved for a long-form text that is shorter in length.</li><li><strong>body2</strong> is the smallest body and is typically reserved for a long-form text that is shorter in length.</li><li><strong>button</strong> is reserved for a button text.</li><li><strong>caption</strong> is one of the smallest font sizes it reserved for annotating imagery or introduce a headline.</li><li><strong>overline</strong> is one of the smallest font sizes.</li></ul><p>We can override the needed font Style like h1, body1, button, etc as below,</p><p><strong>Type.kt</strong></p><pre>val <em>Typography </em>= Typography(<br>    body1 = TextStyle(<br>        fontFamily = FontFamily.Default,<br>        fontWeight = FontWeight.Normal,<br>        fontSize = 16.<em>sp<br>    </em>),<br>    button = TextStyle(<br>        fontFamily = FontFamily.Default,<br>        fontWeight = FontWeight.W500,<br>        fontSize = 14.<em>sp<br>    </em>),<br>    caption = TextStyle(<br>        fontFamily = FontFamily.Default,<br>        fontWeight = FontWeight.Normal,<br>        fontSize = 12.<em>sp<br>    </em>)<br>    <br>)</pre><p>The example I have created,</p><pre>@Composable<br>fun TypographyPreview() {<br><br>    <em>Column</em>(Modifier.<em>width</em>(400.<em>dp</em>).<em>padding</em>(10.<em>dp</em>)) <strong>{<br>        </strong><em>Text</em>(text = &quot;H2 &quot; ,style = MaterialTheme.typography.h2)<br>        <em>Spacer</em>(modifier = Modifier.<em>padding</em>(4.<em>dp</em>))<br>        <em>Text</em>(text = &quot;Subtitle 1 &quot; ,style = MaterialTheme.typography.subtitle1)<br>        <em>Spacer</em>(modifier = Modifier.<em>padding</em>(4.<em>dp</em>))<br>        <em>Text</em>(text = &quot;Body 1 &quot; ,style = MaterialTheme.typography.body1)<br>        <em>Spacer</em>(modifier = Modifier.<em>padding</em>(4.<em>dp</em>))<br>        <em>Text</em>(text = &quot;Button &quot; ,style = MaterialTheme.typography.button)<br>        <em>Spacer</em>(modifier = Modifier.<em>padding</em>(4.<em>dp</em>))<br>        <em>Text</em>(text = &quot;Caption &quot; ,style = MaterialTheme.typography.caption)<br><br>    <strong>}<br></strong>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/889/1*Xj84u_Wzm24yPB9WibX6CQ.png" /></figure><p>Done with the Typography. finally, create the shape.</p><h3>Shape</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WxyHW53MjbDDh0sQlDU22w.png" /></figure><p>Creating shapes with Jetpack Compose is super easy. Similar to how we created the Typography instance, we also create the instance of Shapes.</p><p><strong>Shape.kt</strong></p><pre>import androidx.compose.foundation.shape.RoundedCornerShape<br>import androidx.compose.material.Shapes<br>import androidx.compose.ui.unit.dp<br><br>val <em>Shapes </em>= Shapes(<br>    small = <em>RoundedCornerShape</em>(4.<em>dp</em>),<br>    medium = <em>RoundedCornerShape</em>(4.<em>dp</em>),<br>    large = <em>RoundedCornerShape</em>(0.<em>dp</em>)<br>)</pre><h3>Let’s Create a Material Theme</h3><p>By using the instances of colors, typography, and shapes above, we can make a material theme that can be used across the application.</p><pre>@Composable<br>fun JetpackComposeThemingTheme(<br>    colors: Colors,<br>    content: @Composable() () -&gt; Unit<br>) {<br>    <em>MaterialTheme</em>(<br>        colors = colors,<br>        typography = <em>Typography</em>,<br>        shapes = <em>Shapes</em>,<br>        content = content<br>    )<br>}</pre><p>CustomComposeTheme is a composable function with two attributes:</p><p><strong>isDarkTheme </strong>— To set the dark or light color scheme based on checking isSystemInDarkTheme.<br><strong>content </strong>— A composable function where the MaterialTheme is to be used.</p><pre>class MainActivity : ComponentActivity() {<br>    override fun onCreate(savedInstanceState: Bundle?) {<br>        super.onCreate(savedInstanceState)<br><br>        <em>setContent </em><strong>{<br>            </strong><em>MaterialTheme </em><strong>{<br>                </strong><em>Column </em><strong>{<br>                    </strong><em>Text</em>(text = &quot;Jetpack Compose&quot;)<br>                <strong>}<br>            }<br>        }<br><br>    </strong>}<br>}</pre><h3>Dark theme</h3><p>Material composable that make use of a Surface (like Card, TopAppBar, etc.) automatically include dark theme properties like desaturated colors for accessibility, elevation overlays, and limited color accents. You can also incorporate these in custom scenarios.</p><p>isSystemInDarkTheme() is a call that asks any compatible Android device for the user&#39;s preference of a light or dark theme.</p><p>It <strong>returns a boolean value</strong> which we can use in a Ternary (Conditional) Assignment expression such as</p><pre>colors = if (darkTheme) DarkColorPalette else LightColorPalette.</pre><p>code to add the dark mode in theme,</p><pre>@Composable<br>fun PurpleTheme(<br>    darkTheme: Boolean = <em>isSystemInDarkTheme</em>(),<br>    content: @Composable() () -&gt; Unit<br>) {<br>    val colors = if (darkTheme) <em>DarkColorPalette </em>else <em>LightColorPalette<br>    MaterialTheme</em>(<br>        colors = colors,<br>        typography = <em>Typography</em>,<br>        shapes = <em>Shapes</em>,<br>        content = content<br>    )<br>}</pre><h3>Material Icons</h3><p>Jetpack Compose also provides a convenient means of using icons listed in the <a href="https://material.io/resources/icons"><strong>Material Icons tool</strong></a>, including all icon styles-filled, outlined, rounded, two-tone, and sharp. With this artifact, you can use icons directly, without the need to download SVGs and convert them to VectorDrawables in Android Studio.</p><p>Add dependency in module <strong>build.gradle</strong></p><pre>implementation &quot;androidx.compose.material:material-icons-extended:$compose_version&quot;</pre><p>You can get the icon by,</p><pre>Icon(Icons.Default.Add) // Default == Filled<br>Icon(Icons.Outlined.Notifications)<br>Icon(Icons.Rounded.ArrowForward)<br>Icon(Icons.TwoTone.Menu)<br>Icon(<br>   Icons.Sharp.Edit,<br>   tint = MaterialTheme.colors.primary<br>)</pre><p>That’s all about jetpack compose theming.</p><p>You can download this example from <a href="https://github.com/velmurugan-murugesan/JetpackCompose/tree/master/JetpackComposeTheming"><strong>Github</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/jetpack-compose-theming-2/"><em>https://howtodoandroid.com</em></a><em> on September 3, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14be92c4cea7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-theming-14be92c4cea7">Getting started with jetpack compose — Theming</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting started with jetpack compose — Scaffold layout]]></title>
            <link>https://medium.com/android-beginners/getting-started-with-jetpack-compose-scaffold-layout-ef8d901561e9?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/ef8d901561e9</guid>
            <category><![CDATA[jetpack]]></category>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[scaffold]]></category>
            <category><![CDATA[androiddev]]></category>
            <category><![CDATA[scaffold-layout]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Fri, 27 Aug 2021 09:33:06 GMT</pubDate>
            <atom:updated>2021-11-23T16:27:48.269Z</atom:updated>
            <content:encoded><![CDATA[<h3>Getting started with jetpack compose — Scaffold layout</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_Pf7vSpXeT4Cr44o.png" /></figure><p>A Scaffold is a layout that implements the basic material design layout structure. You can add things like a TopBar, BottomBar, FAB, or a Drawer. Jetpack Compose provides Scaffold Composable which can save a lot of time. It’s like a prebuilt template.</p><p>If you’re new to Compose, I highly recommend going through the following articles:</p><ul><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-basic-components-a12f7902395b">Getting started with jetpack compose — Basic components</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-layouts-f974d23f656c">Getting started with jetpack compose — Layouts</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-modifiers-d3a61551af">Getting started with jetpack compose — Modifiers</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-constraintlayout-fdd18c666dd3">Getting started with jetpack compose — ConstraintLayout</a></li></ul><p>looks at my sample scaffold layout,</p><pre>setContent {<br>            JetpackComposeScaffoldLayoutTheme {<br>                // A surface container using the &#39;background&#39; color from the theme<br>                Surface(color = MaterialTheme.colors.background) {<br>                    var toolbarTitle by remember {<br>                        mutableStateOf(&quot;Home&quot;)<br>                    }<br>                    val scaffoldState =<br>                        rememberScaffoldState(rememberDrawerState(initialValue = DrawerValue.Closed))<br>                    val scope = rememberCoroutineScope()<br><br>                    Scaffold(<br>                        modifier = Modifier.background(Color.White),<br>                        scaffoldState = scaffoldState,<br>                        topBar = {<br>                            AppToolbar(<br>                                scaffoldState = scaffoldState,<br>                                scope = scope,<br>                                toolbarTitle = toolbarTitle<br>                            )<br>                        }, drawerContent = {<br>                            DrawerView(scaffoldState = scaffoldState, scope = scope)<br>                        },<br>                        content = {},<br>                        bottomBar = { AppBottomBar() },<br>                        snackbarHost = { state -&gt; MySnackHost(state) },<br>                        isFloatingActionButtonDocked = true,<br>                        floatingActionButtonPosition = FabPosition.Center,<br>                        floatingActionButton = { MyFloatingButton(scaffoldState) }<br>                        )<br>                }<br>            }<br>        }</pre><p>and the output of this code,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/298/1*icXFKykaezU-qPDkEJp_mQ.gif" /></figure><p>Looks very simple. let’s see all the composable in detail,</p><h3>Modifier</h3><p>A modifier is a way to modify certain aspects of the component that result in how it’s displayed on the screen.</p><p>I am explained modifiers in another post. Please check it.</p><p><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-modifiers-d3a61551af">Getting started with jetpack compose — Modifiers</a></p><h3>scaffoldState</h3><p>It maintains the state of the scaffold composable. It contains drawerState and snackbarHostState to perform operations like close, opening the drawer. Also, show and hide the snackbar.</p><pre>class ScaffoldState(<br>    val drawerState: DrawerState,<br>    val snackbarHostState: SnackbarHostState<br>)</pre><p>set the scaffoldState in scaffold composable.</p><pre>val scaffoldState = rememberScaffoldState(rememberDrawerState(initialValue = DrawerValue.Closed))<br> Scaffold(modifier = Modifier.background(Color.White),<br>          scaffoldState = scaffoldState,<br>          ...<br> }</pre><h3>rememberCoroutineScope</h3><p>As LaunchedEffect is a composable function, it can only be used inside other composable functions. In order to launch a coroutine outside of a composable, but scoped so that it will be automatically canceled once it leaves the composition, use rememberCoroutineScope.</p><p>rememberCoroutineScope is a composable function that returns a CoroutineScope bound to the point of the Composition where it’s called. The scope will be canceled when the call leaves the Composition.</p><p>For example, display s snackbar we need to use remeberCoroutineScope,</p><pre>val scope = rememberCoroutineScope()<br>    FloatingActionButton(onClick = {<br>        scope.launch {<br>            when (scaffoldState.snackbarHostState.showSnackbar(<br>                message = &quot;Jetpack Compose Snackbar&quot;,<br>                actionLabel = &quot;Ok&quot;<br>            )) {<br>                SnackbarResult.Dismissed -&gt;<br>                    Log.d(&quot;TAB&quot;, &quot;Dismissed&quot;)<br>                SnackbarResult.ActionPerformed -&gt;<br>                    Log.d(&quot;TAB&quot;, &quot;Action!&quot;)<br>            }<br>        }<br>    }) {<br>        Text(&quot;X&quot;)<br>    }</pre><h3>TopAppBar</h3><p>It’s a simple composable function to design the top bar of the app.</p><p>Let’s see the function of the TopAppBar:</p><pre>@Composable<br>fun TopAppBar(<br>    title: @Composable () -&gt; Unit,<br>    modifier: Modifier = Modifier,<br>    navigationIcon: @Composable (() -&gt; Unit)? = null,<br>    actions: @Composable RowScope.() -&gt; Unit = <strong>{}</strong>,<br>    backgroundColor: Color = MaterialTheme.colors.<em>primarySurface</em>,<br>    contentColor: Color = <em>contentColorFor</em>(backgroundColor),<br>    elevation: Dp = AppBarDefaults.TopAppBarElevation<br>)</pre><p><strong><em>Parameters</em></strong></p><p><strong>title</strong> — provide the title text for the TopAppBar.</p><pre>title = <strong>{ </strong><em>Text</em>(text = &quot;Home&quot;) <strong>}</strong></pre><p><strong>Modifier</strong> — Used to modify the background of the TopAppBar.</p><p><strong>navigationIcon</strong> — Used to set the Navigation Icon like Drawer menu and handle the functions alike open the drawer by clicking the menu icon.</p><pre>navigationIcon = <strong>{<br>    </strong><em>Icon</em>(<br>        painter = <em>painterResource</em>(id = R.drawable.<em>ic_baseline_menu_24</em>),<br>        contentDescription = &quot;Menu&quot;, modifier = Modifier.<em>clickable </em><strong>{<br>            </strong>scope.<em>launch </em><strong>{<br>                </strong>scaffoldState.drawerState.open()<br>            <strong>}<br>        }<br>    </strong>)<br><strong>}</strong></pre><p><strong>actions</strong> — The actions displayed at the end of the TopAppBar. This should typically be IconButtons. The default layout here is a Row, so icons inside will be placed horizontally.</p><pre>actions = <strong>{<br>    </strong>val context = <em>LocalContext</em>.current<br>    <em>Icon</em>(<br>        painter = <em>painterResource</em>(id = R.drawable.<em>ic_baseline_settings_24</em>),<br>        contentDescription = &quot;Setting&quot;, modifier = Modifier.<em>clickable </em><strong>{<br>            </strong>Toast.makeText(context, &quot;Open Setting&quot;, Toast.<em>LENGTH_SHORT</em>).show()<br>        <strong>}<br>    </strong>)<br><strong>}</strong></pre><p><strong>backgroundColor</strong> — Set the background color for the TopApBar.</p><p><strong>elevation</strong> — the elevation of this TopAppBar.</p><p>This is the code for the sample I have created for the TopAppBar.</p><pre>@Composable<br>fun AppToolbar(scaffoldState: ScaffoldState, scope: CoroutineScope, toolbarTitle: String) {<br>    TopAppBar(<br>        title = { Text(text = toolbarTitle) },<br>        modifier = Modifier.background(Color(0xFF008800)),<br>        navigationIcon = {<br>            Icon(<br>                painter = painterResource(id = R.drawable.ic_baseline_menu_24),<br>                contentDescription = &quot;Menu&quot;, modifier = Modifier.clickable {<br>                    scope.launch {<br>                        scaffoldState.drawerState.open()<br>                    }<br>                }<br>            )<br>        },<br>        actions = {<br>            val context = LocalContext.current<br>            Icon(<br>                painter = painterResource(id = R.drawable.ic_baseline_settings_24),<br>                contentDescription = &quot;Setting&quot;, modifier = Modifier.clickable {<br>                    Toast.makeText(context, &quot;Open Setting&quot;, Toast.LENGTH_SHORT).show()<br>                }<br>            )<br>        }<br>    )<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/719/1*GnzLDTeqRIxhC9DD1aSQWg.png" /></figure><h3>The Drawer Content</h3><p>In the <strong>drawerContent</strong>, we need to provide the content for the Drawer. content of the Drawer sheet that can be pulled from the left side.</p><p>Let check out my sample drawer composable.</p><pre>@Composable<br>fun DrawerContent(scaffoldState: ScaffoldState, scope: CoroutineScope) {<br><br>    Column(modifier = Modifier.fillMaxWidth()) {<br>        Image(<br>            painter = painterResource(id = R.drawable.ic_baseline_face_24),<br>            modifier = Modifier<br>                .size(100.dp)<br>                .align(Alignment.CenterHorizontally), contentDescription = &quot;Face&quot;<br>        )<br><br>        Spacer(modifier = Modifier.padding(4.dp))<br>        Text(<br>            text = &quot;Velmurugan&quot;,<br>            style = MaterialTheme.typography.subtitle1,<br>            modifier = Modifier.align(<br>                Alignment.CenterHorizontally<br>            )<br>        )<br>        Spacer(modifier = Modifier.padding(4.dp))<br>        Text(text = &quot;User1&quot;,<br>            Modifier<br>                .fillMaxWidth()<br>                .background(Color.Gray)<br>                .padding(8.dp, 4.dp)<br>                .clickable {<br>                    scope.launch {<br>                        scaffoldState.drawerState.close()<br>                    }<br>                })<br>        Spacer(modifier = Modifier.padding(4.dp))<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/589/1*GEoyOELnFDB-hbsnSh3yEA.png" /></figure><p>By using the <strong>scaffoldState</strong> we can show and close the drawer content.</p><p><strong>scaffoldState.drawerState.open()</strong> — display the drawer</p><p><strong>scaffoldState.drawerState.close()</strong> — close the drawer</p><h3>BottomAppBar</h3><p>The bottomAppBar is used to display the menu at bottom of the screen same as the bottom.</p><p>To create bottomAppBar, First, we need to create Menu items for the Bottom Navigation.</p><pre>data class MenuItem(val title: String, val icon: ImageVector)<br><br>    fun getMenuList() : List&lt;MenuItem&gt; {<br>        val menuItems = mutableListOf&lt;MenuItem&gt;()<br>        menuItems.add(MenuItem(Navigations.HOME.name, Icons.Filled.Home))<br>        menuItems.add(MenuItem(Navigations.SEARCH.name, Icons.Filled.Search))<br>        menuItems.add(MenuItem(Navigations.FAVORITE.name, Icons.Filled.Favorite))<br>        menuItems.add(MenuItem(Navigations.SETTINGS.name, Icons.Filled.Settings))<br>        return menuItems<br>    }<br><br>    val bottomMenuList = getMenuList()</pre><p>Next, we need to create <strong>BottomNavigation </strong>composable to create Menu item using the <strong>BottomNavigationItem</strong>.</p><pre>@Composable<br>fun RowScope.BottomNavigationItem(<br>    selected: Boolean,<br>    onClick: () -&gt; Unit,<br>    icon: @Composable () -&gt; Unit,<br>    modifier: Modifier = Modifier,<br>    enabled: Boolean = true,<br>    label: @Composable (() -&gt; Unit)? = null,<br>    alwaysShowLabel: Boolean = true,<br>    interactionSource: MutableInteractionSource = <em>remember </em><strong>{ </strong><em>MutableInteractionSource</em>() <strong>}</strong>,<br>    selectedContentColor: Color = <em>LocalContentColor</em>.current,<br>    unselectedContentColor: Color = selectedContentColor.copy(alpha = ContentAlpha.medium)<br>)</pre><p><strong><em>Parameters</em></strong></p><p><strong>selected </strong>— set the select state for the bottom navigation menu item.</p><p><strong>onClick()</strong> — set the click listener for the menu item click.</p><p>i <strong>con:@Composable()</strong> — set the icon for the bottom navigation menu item.</p><pre>icon = <strong>{<br>    </strong><em>Icon</em>(<br>        imageVector = bottomMenu.icon,<br>        contentDescription = bottomMenu.title<br>    )<br><strong>}</strong></pre><p><strong>label </strong>— add the label for the menu item.</p><p><strong>alwaysShowLabel: Boolean</strong> — show and hide the menu item label.</p><p><strong>selectedContentColor: Color</strong> — content color for the selected menu item</p><p><strong>unselectedContentColor: Color</strong> — content color for the unselected menu item.</p><p>Let’s see the example BottomAppBar,</p><pre>@Composable<br>fun BottomAppBar() {<br>    data class MenuItem(val title: String, val icon: ImageVector)<br><br>    fun getMenuList() : List&lt;MenuItem&gt; {<br>        val menuItems = mutableListOf&lt;MenuItem&gt;()<br>        menuItems.add(MenuItem(Navigations.HOME.name, Icons.Filled.Home))<br>        menuItems.add(MenuItem(Navigations.SEARCH.name, Icons.Filled.Search))<br>        menuItems.add(MenuItem(Navigations.FAVORITE.name, Icons.Filled.Favorite))<br>        menuItems.add(MenuItem(Navigations.SETTINGS.name, Icons.Filled.Settings))<br>        return menuItems<br>    }<br><br>    val bottomMenuList = getMenuList()<br><br>    BottomNavigation {<br>        bottomMenuList.forEach { bottomMenu -&gt;<br>            BottomNavigationItem(<br>                selected = bottomMenu.title == &quot;Home&quot;,<br>                onClick = {<br>                },<br>                icon = {<br>                    Icon(<br>                        imageVector = bottomMenu.icon,<br>                        contentDescription = bottomMenu.title<br>                    )<br>                })<br>        }<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/742/1*3J443RyW71wHI0su9N5beQ.png" /></figure><h3>FloatingActionButton</h3><p>we can create FAB using the FloatingActionButton composable function.</p><pre>@OptIn(ExperimentalMaterialApi::class)<br>@Composable<br>fun FloatingActionButton(<br>    onClick: () -&gt; Unit,<br>    modifier: Modifier = Modifier,<br>    interactionSource: MutableInteractionSource = <em>remember </em><strong>{ </strong><em>MutableInteractionSource</em>() <strong>}</strong>,<br>    shape: Shape = MaterialTheme.shapes.small.copy(<em>CornerSize</em>(percent = 50)),<br>    backgroundColor: Color = MaterialTheme.colors.secondary,<br>    contentColor: Color = <em>contentColorFor</em>(backgroundColor),<br>    elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),<br>    content: @Composable () -&gt; Unit<br>)</pre><p><strong><em>Parameters</em></strong></p><p><strong>onClick()</strong> — set click listener for the FAB.</p><p><strong>modifier </strong>— add view modification for the FAB.</p><p><strong>shape </strong>= MaterialTheme.shapes.small.copy( <em>CornerSize</em>(percent = 50)) — Provide the shape for the FAB.</p><p><strong>backgroundColor </strong>— set the background color for the FAB.</p><p><strong>contentColor </strong>— set the content color on the FAB.</p><p><strong>content </strong>— provide the content composable for the FAB.</p><p>Let’s see the sample FAB,</p><pre>@OptIn(ExperimentalMaterialApi::class)<br>@Composable<br>fun FloatingActionButtonSample() {<br>    FloatingActionButton(onClick = {<br>        <br>    }) {<br>        Text(&quot;+&quot;)<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/354/1*KNBYvF4feI5ZKKbD2ImEcw.png" /></figure><h4>FloatingActionButtonPosition</h4><p>When you have added a FAB, you can use FloatingActionButtonPosition to specify its position. The default position is at the end of your layout.</p><p>Now, I changed the position to the center using,</p><pre>floatingActionButtonPosition = FabPosition.Center</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/788/1*plhT-xHhBp9_F0dcEDpIDw.png" /></figure><h3>Snackbar</h3><p>By default, a Snackbar is provided, and we can just call it to show without setting it up. However, if we want to customize it, we can still set it up and customize it as below.</p><pre>@OptIn(ExperimentalMaterialApi::class)<br>@Composable<br>fun MySnackHost(state: SnackbarHostState) {<br>    SnackbarHost(<br>        state,<br>        snackbar = { data -&gt;<br>            Snackbar(<br>                modifier = Modifier<br>                    .padding(8.dp)<br>                    .background(Color.Black, RoundedCornerShape(8.dp)),<br>                action = {<br>                    Text(<br>                        text = &quot;HIDE&quot;,<br>                        modifier = Modifier<br>                            .padding(8.dp)<br>                            .clickable {<br>                                state.currentSnackbarData?.dismiss()<br>                            },<br>                        style = androidx.compose.ui.text.TextStyle(<br>                            fontWeight = FontWeight.Bold,<br>                            color = MaterialTheme.colors.primary,<br>                            fontSize = 18.sp<br>                        )<br>                    )<br>                }<br>            ) {<br>                Text(text = data.message)<br>            }<br>        })<br>}</pre><p>Now we can set the customized snackbar into the scaffold.</p><pre>Scaffold(modifier = Modifier.background(Color.White),<br>                        scaffoldState = scaffoldState,<br>                        topBar = {<br>                        }, drawerContent = {<br>                            <br>                        },<br>                        content = {},<br>                        bottomBar = { BottomAppBar() },<br>                        snackbarHost = { state -&gt; MySnackHost(state) },<br>                        isFloatingActionButtonDocked = true,<br>                        floatingActionButtonPosition = FabPosition.Center,<br>                        floatingActionButton = { FloatingActionButtonSample() }<br>                    )</pre><p>Now, we set the custom snackbar into the scaffold layout.</p><p>The next step is to display the snackbar using the <strong>scaffoldState</strong>.</p><p>whenever we need to show the snackbar, we need to pass the message and the click action.</p><p>I have created a FAB composable, a click of the FAB, I am displaying the snackbar. please check the code below,</p><pre>@OptIn(ExperimentalMaterialApi::class)<br>@Composable<br>fun FloatingActionButtonSample(scaffoldState: ScaffoldState) {<br>    val scope = rememberCoroutineScope()<br>    FloatingActionButton(onClick = {<br>        scope.launch {<br>            when (scaffoldState.snackbarHostState.showSnackbar(<br>                message = &quot;Snackbar&quot;,<br>                actionLabel = &quot;Ok&quot;<br>            )) {<br>                SnackbarResult.Dismissed -&gt;<br>                    Log.d(&quot;TAB&quot;, &quot;Dismissed&quot;)<br>                SnackbarResult.ActionPerformed -&gt;<br>                    Log.d(&quot;TAB&quot;, &quot;Action!&quot;)<br>            }<br>        }<br>    }) {<br>        Text(&quot;X&quot;)<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/432/1*ZjswHgksL-YiH68eNbxjoA.png" /></figure><p>That’s it. Thanks for reading.</p><p>You can download this example on <a href="https://github.com/velmurugan-murugesan/JetpackCompose/tree/master/JetpackComposeScaffoldLayout"><strong>GitHub</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/jetpack-compose-scaffold-layout/"><em>https://howtodoandroid.com</em></a><em> on August 27, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ef8d901561e9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-scaffold-layout-ef8d901561e9">Getting started with jetpack compose — Scaffold layout</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting started with jetpack compose — ConstraintLayout]]></title>
            <link>https://medium.com/android-beginners/getting-started-with-jetpack-compose-constraintlayout-fdd18c666dd3?source=rss----4e0b28298434---4</link>
            <guid isPermaLink="false">https://medium.com/p/fdd18c666dd3</guid>
            <category><![CDATA[constraintlayout]]></category>
            <category><![CDATA[jetpack]]></category>
            <category><![CDATA[jetpack-compose]]></category>
            <category><![CDATA[compose-layout]]></category>
            <category><![CDATA[androiddev]]></category>
            <dc:creator><![CDATA[Velmurugan Murugesan]]></dc:creator>
            <pubDate>Fri, 27 Aug 2021 08:54:51 GMT</pubDate>
            <atom:updated>2021-11-23T16:29:32.728Z</atom:updated>
            <content:encoded><![CDATA[<h3>Getting started with jetpack compose — ConstraintLayout</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9Wz9ZT0L_ByHNniP5PUe3g.png" /></figure><p>ConstraintLayout can help place composable relative to others on the screen and is an alternative to using multiple nested Row, Column, Box, and custom layout elements. ConstraintLayout is useful when implementing larger layouts with more complicated alignment requirements. — <a href="https://developer.android.com/jetpack/compose/layouts/constraintlayout">Android Developers</a></p><p>If you’re new to Compose, I highly recommend going through the following articles:</p><ul><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-basic-components-a12f7902395b">Getting started with jetpack compose — Basic components</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-layouts-f974d23f656c">Getting started with jetpack compose — Layouts</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-modifiers-d3a61551af">Getting started with jetpack compose — Modifiers</a></li><li><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-scaffold-layout-ef8d901561e9">Getting started with jetpack compose — Scaffold layout</a></li></ul><p>To use ConstraintLayout in Compose, you need to add this dependency in your <strong>build.gradle</strong>:</p><pre>implementation &quot;androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02&quot;</pre><h3>Steps to setup constraintLayout in jetpack compose</h3><ul><li>Create reference for each composable in constraintLayout using <strong>createRefs()</strong> or <strong>createRef()</strong>.</li><li>Constraints are provided using the <strong>constrainAs </strong>modifier which takes the reference as a parameter and lets you specify its constraints in the body lambda.</li><li>Constraints are specified using <strong>linkTo </strong>or other helpful methods.</li><li><strong>parent </strong>is an existing reference that can be used to specify constraints towards the ConstraintLayout composable itself.</li></ul><h3>Create constraintLayout</h3><p>As mentioned earlier, First need to crate reference of each composable using <strong>createRefs()</strong> inside a constraintLayout.</p><pre>ConstraintLayout() {<br>        val (textTopStart, textTopCenter, textTopEnd, textCenterStart,textCenter, textCenterEnd, textBottomStart, textBottomCenter, textBottomEnd) = createRefs()<br>     ....<br>}</pre><p>Next, create a composable and add a constraint using <strong>constraintAs </strong>modifier. Also, specify constraints to the composable using <strong>linkTo()</strong>.</p><pre>Text(text = &quot;Top start&quot;, Modifier.constrainAs(textTopStart) {<br>            top.linkTo(parent.top, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>        })</pre><p>Here’s an example of a composable using a ConstraintLayout:</p><pre>@Composable<br>fun ConstraintLayoutLinkToParentExample() {<br><br>    ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .height(200.dp)) {<br><br>        val (textTopStart, textTopCenter, textTopEnd, textCenterStart,textCenter, textCenterEnd, textBottomStart, textBottomCenter, textBottomEnd) = createRefs()<br><br>        Text(text = &quot;Top start&quot;, Modifier.constrainAs(textTopStart) {<br>            top.linkTo(parent.top, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>        })<br><br>        Text(text = &quot;Top Center&quot;, Modifier.constrainAs(textTopCenter) {<br>            top.linkTo(parent.top, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br><br>        Text(text = &quot;Top End&quot;, Modifier.constrainAs(textTopEnd) {<br>            top.linkTo(parent.top, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br><br>        Text(text = &quot;Center start&quot;, Modifier.constrainAs(textCenterStart) {<br>            top.linkTo(parent.top, 8.dp)<br>            bottom.linkTo(parent.bottom, 8.dp)<br>        })<br><br>        Text(text = &quot;Center&quot;, Modifier.constrainAs(textCenter) {<br>            top.linkTo(parent.top, 8.dp)<br>            bottom.linkTo(parent.bottom, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br><br>        Text(text = &quot;Center end&quot;, Modifier.constrainAs(textCenterEnd) {<br>            top.linkTo(parent.top, 8.dp)<br>            bottom.linkTo(parent.bottom, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br><br><br>        Text(text = &quot;Bottom start&quot;, Modifier.constrainAs(textBottomStart) {<br>            start.linkTo(parent.start, 8.dp)<br>            bottom.linkTo(parent.bottom, 8.dp)<br>        })<br><br>        Text(text = &quot;Bottom Center&quot;, Modifier.constrainAs(textBottomCenter) {<br>            bottom.linkTo(parent.bottom, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br><br>        Text(text = &quot;Bottom end&quot;, Modifier.constrainAs(textBottomEnd) {<br>            bottom.linkTo(parent.bottom, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        })<br>    }<br>}</pre><p>In the above code, I have created 9 different composable and aligned them in different parts of the constraint layout. the output of the above code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/635/1*8pby_7CjcGRGnVJEvpRowg.png" /></figure><h3>ConstraintLayout using constraintSet</h3><p>In the ConstraintLayout example, constraints are specified <strong>inline</strong>, with a modifier in the composable they’re applied to. If you want to decouple the constraint from the constraintLatyout, then we need to use constraintSet.</p><ul><li>create constraintSet using composable references and constraints.</li><li>create constraintLayout by passing constraintSet as a parameter.</li><li>Assign references created in the ConstraintSet to composables using the <strong>layoutId </strong>modifier.</li></ul><p>We Will see the point in detail here,</p><p>First, need to create constraintSet.</p><pre>val constraintSet = ConstraintSet {<br>        val buttonLogin = createRefFor(&quot;buttonLogin&quot;)<br>        val inputUsername = createRefFor(&quot;inputUsername&quot;)<br>        val inputPassword = createRefFor(&quot;inputPassword&quot;)<br><br>        constrain(inputUsername) {<br>            top.linkTo(parent.top, 32.dp)<br>            start.linkTo(parent.start, 16.dp)<br>            end.linkTo(parent.end, 16.dp)<br>        }<br><br>        constrain(inputPassword) {<br>            top.linkTo(inputUsername.bottom, 8.dp)<br>            start.linkTo(parent.start, 16.dp)<br>            end.linkTo(parent.end, 16.dp)<br>        }<br><br>        constrain(buttonLogin) {<br>            top.linkTo(inputPassword.bottom, 16.dp)<br>            start.linkTo(parent.start, 16.dp)<br>            end.linkTo(parent.end, 16.dp)<br>        }<br><br>    }</pre><p>In the above code, First I have created references for the composable like buttonLogin, inputUsername.</p><p>Then, created constraints for the references. for the inputUsername , set <strong>top to parent</strong> and <strong>start to parent</strong> and <strong>end to parent</strong>. like that we need to create constraints for all the references.</p><p>Next, we need to pass the constraintSet as a parameter for the constraintLayout.</p><pre>ConstraintLayout(constraintSet) {<br>        .....<br>    }</pre><p>Finally, Assign references created in the ConstraintSet to composable using the layoutId modifier.</p><pre>ConstraintLayout(constraintSet, modifier = Modifier<br>        .fillMaxWidth()<br>        .height(250.dp)) {<br>        val context = LocalContext.current<br>        var username by remember {<br>            mutableStateOf(&quot;&quot;)<br>        }<br>        var password by remember {<br>            mutableStateOf(&quot;&quot;)<br>        }<br>        TextField(value = username,  onValueChange = { username = it } , label = { Text(text = (&quot;Username&quot;))},  modifier =  Modifier.layoutId(&quot;inputUsername&quot;))<br><br>        TextField(value = password, onValueChange = { password = it }, label = { Text(&quot;Password&quot;)},        visualTransformation = PasswordVisualTransformation(),<br>            modifier = Modifier.layoutId(&quot;inputPassword&quot;))<br><br>        Button(onClick = { Toast.makeText(context, &quot;Username $username , Password: $password &quot;, Toast.LENGTH_SHORT).show()}, Modifier.layoutId(&quot;buttonLogin&quot;)) {<br>            Text(text = &quot;Login&quot;)<br>        }<br>    }</pre><p>We need to apply the created constraints by adding layoutId modifier to the composable. For the first TextField(), I have applied the <strong>inputUsername</strong> constraints.</p><p>Output for the above code,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/778/1*gjcIUKPvNGC0gZhaXIuPGA.png" /></figure><h3>Guildline</h3><p>A guideline is an invisible view through which we can constraint the composables. The guideline can be aligned using percentage, offset, and padding. As guidelines are invisible, we can create responsive UI using them.</p><h4>Types of guidelines</h4><ul><li><strong>createGuidelineFromTop</strong> — Creates a guideline at a specific offset/percentage from the top of the ConstraintLayout.</li><li><strong>createGuidelineFromRight </strong>— Creates a guideline at a width offset/percentage from the right of the ConstraintLayout.</li><li><strong>createGuidelineFromLeft </strong>— Creates a guideline at a width offset/percentage from the left of the ConstraintLayout.</li><li><strong>createGuidelineFromBottom </strong>— Creates a guideline at a specific offset/percentage from the bottom of the ConstraintLayout.</li></ul><pre>        // guideline 20 percentage from top<br>        val guildLineFromTop = createGuidelineFromTop(0.2f)<br>        // guideline 20 Dp from top<br>        val guildLineFromTop = createGuidelineFromTop(20.dp)</pre><p>Let’s create a guideline of 20 percentage from the top of the contraintlayout. and link the guideline to composable.</p><pre>@Composable<br>fun ConstraintLayoutGuideLine() {<br><br>    ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .height(100.dp)<br>        .padding(12.dp)) {<br><br>        val (input) = createRefs()<br>        val guildLineFromTop = createGuidelineFromTop(0.2f)<br><br>        Text(text = &quot;GuildLine From top and start&quot;, modifier = Modifier.constrainAs(input) {<br>            top.linkTo(guildLineFromTop, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>            end.linkTo(parent.end, 8.dp)<br>        } )<br>    }<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/0*dii89ihnh3skiBSv" /></figure><p>Also, we can set multiple guidelines for the composable. Below, I have created two guidelines, one from the top of the parent layout and the other one is from the start of the parent layout.</p><pre>@Composable<br>fun ConstraintLayoutGuideLine() {<br><br>    ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .height(100.dp)<br>        .padding(12.dp)) {<br><br>        val (input) = createRefs()<br>        val guildLineFromTop = createGuidelineFromTop(0.2f)<br>        val guildLineFromStart = createGuidelineFromStart(50.dp)<br><br>        Text(text = &quot;GuildLine From top and start&quot;, modifier = Modifier.constrainAs(input) {<br>            top.linkTo(guildLineFromTop, 8.dp)<br>            start.linkTo(guildLineFromStart, 8.dp)<br>        } )<br>    }<br>}</pre><h3>Barrier</h3><p>A Barrier is similar to a Guideline. But the barrier has reference to the views that you wish to use to form a “barrier” against. If anyone of the views grows, the barrier will adjust its size to the largest height or width of the referenced items.</p><h4>Types of barriers</h4><p>We can create four different barriers.</p><ul><li>createStartBarrier(vararg elements: ConstrainedLayoutReference)</li><li>createEndBarrier(vararg elements: ConstrainedLayoutReference)</li><li>createTopBarrier(vararg elements: ConstrainedLayoutReference)</li><li>createBottomBarrier(vararg elements: ConstrainedLayoutReference)</li></ul><p>Let’s see in the example,</p><p>First, create a reference for the components.</p><pre>val (input1, input2, input3) = createRefs()</pre><p>Next, create a barrier using the reference of the components.</p><pre>val barrier = createEndBarrier(input1, input2)</pre><p>here, I have created a <strong>createEndBarrier </strong>referencing input1, and input2.</p><p>finally, add the barrier to another component, that always wants to be the end of the barrier.</p><pre>@Composable<br>fun BarrierExample() {<br>    ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .padding(12.dp)) {<br>        val (input1, input2, input3) = createRefs()<br><br>        val barrier = createEndBarrier(input1, input2)<br><br>        Text(text = &quot;Iuput 1 Large&quot;, modifier = Modifier.constrainAs(input1) {<br>            top.linkTo(parent.top, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>        } )<br><br>        Text(text = &quot;Iuput 2&quot;, modifier = Modifier.constrainAs(input2) {<br>            top.linkTo(input1.bottom, 8.dp)<br>            start.linkTo(parent.start, 8.dp)<br>        } )<br><br>        Text(text = &quot;Iuput 3&quot;, modifier = Modifier.constrainAs(input3) {<br>            top.linkTo(input1.bottom, 8.dp)<br>            start.linkTo(barrier, 8.dp)<br>        } )<br>    }<br>}</pre><p>the output of the above code,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/862/1*AI_5ICHlkRuUCoTm6R3LVg.png" /></figure><h3>Chains</h3><p>Chains allow us to align the views vertically or horizontally and also control the space between them, along with how the views use the space.</p><h4>Type of chains</h4><p><strong>createHorizontalChain()</strong> -create horizontal chain.</p><p><strong>createVerticalChain()</strong> — create vertical chain.</p><h3>ChainStyle</h3><p>we have three different types of chain styles.</p><ul><li><strong>Spread</strong> : The views are evenly distributed.</li><li><strong>Spread inside</strong> : The first and last views are aligned to the constraints on each end of the chain, and the rest are evenly distributed.</li><li><strong>Packed </strong>: The views are packed together.</li></ul><p>Let’s see the example,</p><p>First, I am creating three buttons with references inside a constaintLayout.</p><pre>ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .padding(12.dp)) {<br>        val (button1, button2, button3) = createRefs()<br>    ....<br>}</pre><p>Next, I am creating a horizontal chain with all the button references. also, I am using Spread inside chain style.</p><pre>@Composable<br>fun ChainExample() {<br>    ConstraintLayout(modifier = Modifier<br>        .fillMaxWidth()<br>        .padding(12.dp)) {<br>        val (button1, button2, button3) = createRefs()<br><br>        createHorizontalChain(button1, button2, button3, chainStyle = ChainStyle.SpreadInside)<br><br><br>        Button(onClick = { }, modifier = Modifier.constrainAs(button1) {<br>            centerHorizontallyTo(parent)<br>        }) {<br>            Text(text = &quot;Button 1&quot;)<br>        }<br><br>        Button(onClick = { }, modifier = Modifier.constrainAs(button2) {<br>            centerVerticallyTo(parent)<br>        }) {<br>            Text(text = &quot;Button 2&quot;)<br>        }<br><br>        Button(onClick = { }, modifier = Modifier.constrainAs(button3) {<br>            centerHorizontallyTo(parent)<br>        }) {<br>            Text(text = &quot;Button 3&quot;)<br>        }<br>    }<br>}</pre><p>chain output with spread inside style,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/846/1*OtwNhouT7C2KQkrXhIaclw.png" /></figure><p>chain with spread style,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*tAtr1XXMH5Xdzq7nPeZ_nA.png" /></figure><p>chain with packed style,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/869/1*h5YrI0pdwFVcjvK8LTXUmQ.png" /></figure><p>That’s all about the constraintLayout.</p><p>You can download this example on <a href="https://github.com/velmurugan-murugesan/JetpackCompose/tree/master/JetpackComposeConstraintLayout"><strong>GitHub</strong></a>.</p><p><em>Originally published at </em><a href="https://howtodoandroid.com/jetpack-compose-constraintlayout"><em>https://howtodoandroid.com</em></a><em> on August 27, 2021.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fdd18c666dd3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/android-beginners/getting-started-with-jetpack-compose-constraintlayout-fdd18c666dd3">Getting started with jetpack compose — ConstraintLayout</a> was originally published in <a href="https://medium.com/android-beginners">Howtodoandroid</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>