How to use synthetic property in Kotlin Android Extension

Issue #555 Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand. In your case, for Fragment, you need to use view.btn_K in onViewCreated override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) val view = inflater.inflate(R.layout.fragment_card_selector, container, false) view.btn_K.setOnClickListener{} // access with `view` return view } Or better, you should only access synthetic properties in onViewCreated...

December 23, 2019 路 1 min 路 Khoa Pham

How to access view in fragment in Kotlin

Issue #497 Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand. In your case, for Fragment, you need to use view.btn_K in onViewCreated override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) val view = inflater.inflate(R.layout.fragment_card_selector, container, false) view.btn_K.setOnClickListener{} // access with `view` return view } Or better, you should only access synthetic properties in onViewCreated...

November 10, 2019 路 1 min 路 Khoa Pham

How to show error message like Snack Bar in iOS

Issue #472 Build error view Use convenient code from Omnia To make view height dynamic, pin UILabel to edges and center import UIKit final class ErrorMessageView: UIView { let box: UIView = { let view = UIView() view.backgroundColor = R.color.primary view.layer.cornerRadius = 6 return view }() let label: UILabel = { let label = UILabel() label.styleAsText() label.textColor = R.color.darkText label.numberOfLines = 0 return label }() override init(frame: CGRect) { super.init(frame: frame) setup() } required init?...

October 21, 2019 路 3 min 路 Khoa Pham

How to structure classes

Issue #466 iOS View Controller -> View Model | Logic Handler -> Data Handler -> Repo Android Activity -> Fragment -> View Model | Logic Handler -> Data Handler -> Repo ...

October 16, 2019 路 1 min 路 Khoa Pham

How to add AdMob to Android app

Issue #431 Use AdMob with Firebase https://firebase.google.com/docs/admob/android/quick-start build.gradle buildscript { repositories { google() jcenter() } dependencies { classpath 'com.google.gms:google-services:4.3.2' } } app/build.gradle class Version { class Firebase { static def analytics = "17.2.0" static def ads = "18.2.0" } } dependencies { implementation "com.google.firebase:firebase-analytics:$Version.Firebase.analytics" implementation "com.google.firebase:firebase-ads:$Version.Firebase.ads" } apply plugin: 'com.google.gms.google-services' Manifest.xml <manifest> <application> <!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 --> <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="[ADMOB_APP_ID]"/> </application> </manifest> MyApplication.kt class MyApplication: Application() { override fun onCreate() { super....

September 27, 2019 路 1 min 路 Khoa Pham

How to do launch screen in Android

Issue #397 We recommend that, rather than disabling the preview window, you follow the common Material Design patterns. You can use the activity鈥檚 windowBackground theme attribute to provide a simple custom drawable for the starting activity. styles.xml <style name="LaunchTheme" parent="Theme.AppCompat.NoActionBar"> <item name="android:windowBackground">@drawable/launch_background</item> </style> Set android:theme="@style/LaunchTheme" to activity element AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.onmyway133.whatsupintech"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".features.main.MainActivity" android:label="@string/app_name" android:theme="@style/LaunchTheme"> <intent-filter> <action android:name="android....

September 4, 2019 路 1 min 路 Khoa Pham

How to add header to NavigationView in Android

Issue #396 Use app:headerLayout <com.google.android.material.navigation.NavigationView android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/navigationView" android:fitsSystemWindows="true" android:layout_gravity="start" app:menu="@menu/drawer_menu" app:itemIconTint="@color/title" app:itemTextColor="@color/title" app:headerLayout="@layout/navigation_header" /> navigation_header.xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.appcompat.widget.AppCompatImageView android:layout_width="0dp" android:layout_height="wrap_content" android:src="@drawable/icon" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> ...

September 4, 2019 路 1 min 路 Khoa Pham

How to create bounce animation programmatically in Android

Issue #383 Right click res -> New -> Android Resource Directory, select anim and name it anim Right click res/anim -> New -> Android Resource file, name it bounce <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="0" android:toYDelta="-100" android:repeatCount="infinite" /> </set> We have to set repeatCount in xml, setting in code does not work !! val bounce = AnimationUtils.loadAnimation(context, R.anim.bounce) bounce.repeatMode = Animation.REVERSE bounce.duration = (1000..2000).random().toLong() imageView.startAnimation(bounce) ...

August 28, 2019 路 1 min 路 Khoa Pham

How to use point in dp programmatically in Android

Issue #382 import android.content.Context fun Int.toDp(context: Context?): Int { if (context != null) { val scale = context.resources.displayMetrics.density return (this.toFloat() * scale + 0.5f).toInt() } else { return 0 } } val set = ConstraintSet() set.setMargin(imageView.id, ConstraintSet.RIGHT, rightMargin.toDp(150)) Read more https://stackoverflow.com/questions/5255184/android-and-setting-width-and-height-programmatically-in-dp-units ...

August 28, 2019 路 1 min 路 Khoa Pham

How to create constraints programmatically with ConstraintLayout in Android

Issue #381 From API < 17, there is ViewCompat.generateViewId() For API 17, there is View.generateViewId() Note that to use ConstraintSet, all views under ConstraintLayout inside xml must have unique id val imageView = ImageView(context) imageView.id = View.generateViewId() imageView.setImageResource(resId) constraintLayout.addView(imageView) val set = ConstraintSet() set.clone(constraintLayout) set.connect(imageView.id, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT) set.applyTo(constraintLayout) ...

August 28, 2019 路 1 min 路 Khoa Pham

How to use custom font as resource in Android

Issue #380 Downloadable fonts https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts Android 8.0 (API level 26) and Android Support Library 26 introduce support for APIs to request fonts from a provider application instead of bundling files into the APK or letting the APK download fonts. The feature is available on devices running Android API versions 14 and higher through the Support Library 26 Before Select File -> New -> Folder -> Assets Folder to create src/main/assets/fonts al myTypeface = Typeface....

August 28, 2019 路 1 min 路 Khoa Pham

How to get Hacker News top stories using parallel coroutine and Retrofit

Issue #379 interface Api { @GET("topstories.json?print=pretty") suspend fun getTopStories(): List<Int> @GET("item/{id}.json?print=pretty") suspend fun getStory(@Path("id") id: Int): Item } class Repo { fun api(): Api { return Retrofit.Builder() .baseUrl("https://hacker-news.firebaseio.com/v0/") .addConverterFactory(MoshiConverterFactory.create()) .build() .create(Api::class.java) } } class ViewModel(val repo: Repo): ViewModel() { val items = MutableLiveData<ArrayList<Item>>() suspend fun load() { try { val ids = repo.api() .getTopStories() .take(20) val items = ids.map { repo.api().getStory(it) } this.items.value = items.toCollection(ArrayList()) } catch (e: Exception) { this....

August 28, 2019 路 2 min 路 Khoa Pham

How to show generic list in Fragment in Android

Issue #378 After having a generic RecyclerView, if we want to show multiple kinds of data in Fragment, we can use generic. We may be tempted to use interface or protocol, but should prefer generic. class FeedFragment() : Fragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) val mainViewModel: MainViewModel = ViewModelProviders.of(activity!!).get(MainViewModel::class.java) mainViewModel.resId.observe(viewLifecycleOwner, Observer { when (it) { R.id.gitHub -> { handleGitHub() } R.id.hackerNews -> { handleHackerNews() } R.id.reddit -> { handleReddit() } R....

August 28, 2019 路 2 min 路 Khoa Pham

How to use Product Hunt GraphQL API with Retrofit

Issue #370 Define response model import com.squareup.moshi.Json data class Response( @field:Json(name="data") val data: ResponseData ) data class ResponseData( @field:Json(name="posts") val posts: Posts ) data class Posts( @field:Json(name="edges") val edges: List<Edge> ) data class Edge( @field:Json(name="node") val node: Item ) data class Item( @field:Json(name="id") val id: String, @field:Json(name="name") val name: String, @field:Json(name="url") val url: String, @field:Json(name="tagline") val tagline: String, @field:Json(name="featuredAt") val featuredAt: String, @field:Json(name="votesCount") val votesCount: Int, @field:Json(name="commentsCount") val commentsCount: Int, @field:Json(name="thumbnail") val thumbnail: Thumbnail ) data class Thumbnail( @field:Json(name="url") val ur: String ) Here is the query...

August 26, 2019 路 2 min 路 Khoa Pham

How to get trending repos on GitHub using Retrofit

Issue #367 https://api.github.com/search/repositories?sort=stars&order=desc&q=language:javascript,java,swift,kotlin&q=created:>2019-08-21 interface Api { @GET("https://api.github.com/search/repositories") suspend fun getTrendingRepos( @Query("sort") sort: String, @Query("order") order: String, @Query("q") qs: List<String> ): Response } class Repo { fun api(): Api { return Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MoshiConverterFactory.create()) .build() .create(Api::class.java) } } class ViewModel(val repo: Repo, val dateProvider: DateProvider): ViewModel() { val items = MutableLiveData<ArrayList<Item>>() suspend fun load() { try { val order = "desc" val sort = "star" val formatter = SimpleDateFormat("YYYY-MM-dd") val qs = listOf( "language:javascript,java,swift,kotlin", "q=created:>${formatter....

August 22, 2019 路 1 min 路 Khoa Pham

How to use Retrofit in Android

Issue #366 Code uses Retrofit 2.6.0 which has Coroutine support app/build.gradle implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01" implementation "com.squareup.moshi:moshi:$Version.moshi" implementation "com.squareup.retrofit2:retrofit:$Version.retrofit" implementation "com.squareup.retrofit2:converter-moshi:$Version.retrofit" Api.kt import retrofit2.http.GET interface Api { @GET("api/articles") suspend fun getArticles(): List<Article> } Repo.kt import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory class Repo { fun get(): Api { return Retrofit.Builder() .baseUrl("https://dev.to") .addConverterFactory(MoshiConverterFactory.create()) .build() .create(Api::class.java) } } ViewModel.kt import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import kotlinx.coroutines.Dispatchers class ViewModel(val repo: Repo): ViewModel() { val articles = liveData(Dispatchers.Main) { emit(repo.get().getArticles().toCollection(ArrayList())) } } Article....

August 22, 2019 路 1 min 路 Khoa Pham

How to use ViewModel and ViewModelsProviders in Android

Issue #363 ViewModels a simple example https://medium.com/androiddevelopers/viewmodels-a-simple-example-ed5ac416317e Rotating a device is one of a few configuration changes that an app can go through during its lifetime, including keyboard availability and changing the device鈥檚 language. All of these configuration changes cause the Activity to be torn down and recreated The ViewModel class is designed to hold and manage UI-related data in a life-cycle conscious way. This allows data to survive configuration changes such as screen rotations....

August 20, 2019 路 3 min 路 Khoa Pham

How to inject view model with Koin in Android

Issue #359 app/build.gradle implementation "org.koin:koin-core:$Version.koin" implementation "org.koin:koin-androidx-scope:$Version.koin" implementation "org.koin:koin-androidx-viewmodel:$Version.koin" MyApplication.kt import android.app.Application import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.core.context.startKoin import org.koin.dsl.module class MyApplication: Application() { var appModule = module { single { MyRepo() } viewModel { MyViewModel(get()) } } override fun onCreate() { super.onCreate() startKoin { androidLogger() androidContext(this@MyApplication) modules(appModule) } } } MyFragment.kt import org.koin.androidx.viewmodel.ext.android.viewModel val viewModel: MyViewModel by viewModel() ...

August 15, 2019 路 1 min 路 Khoa Pham

How to use coroutine LiveData in Android

Issue #358 app/build.gradle implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01" import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import kotlinx.coroutines.Dispatchers class MainViewModel : ViewModel() { val repository: TodoRepository = TodoRepository() val firstTodo = liveData(Dispatchers.IO) { val retrivedTodo = repository.getTodo(1) emit(retrivedTodo) } } Use coroutines with LiveData https://developer.android.com/topic/libraries/architecture/coroutines The liveData building block serves as a structured concurrency primitive between coroutines and LiveData. The code block starts executing when LiveData becomes active and is automatically canceled after a configurable timeout when the LiveData becomes inactive....

August 15, 2019 路 1 min 路 Khoa Pham

How to declare generic RecyclerView adapter in Android

Issue #357 generic/Adapter.kt package com.onmyway133.generic import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView abstract class Adapter<T>(var items: ArrayList<T>): RecyclerView.Adapter<RecyclerView.ViewHolder>() { abstract fun configure(item: T, holder: ViewHolder) fun update(items: ArrayList<T>) { this.items = items notifyDataSetChanged() } override fun getItemCount(): Int = items.count() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val view = LayoutInflater .from(parent.context) .inflate(viewType, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { configure(items[position], holder as ViewHolder) } } class ViewHolder(view: View): RecyclerView....

August 14, 2019 路 1 min 路 Khoa Pham