diff --git a/app/build.gradle b/app/build.gradle index c536ab0..b9df9ef 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,6 +34,11 @@ android { testOptions { unitTests.returnDefaultValues = true } + + dataBinding { + // https://developer.android.com/topic/libraries/data-binding/start + enabled = true + } } dependencies { diff --git a/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundListAdapter.kt b/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundListAdapter.kt new file mode 100644 index 0000000..1e5e3d9 --- /dev/null +++ b/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundListAdapter.kt @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 Hossain Khan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hossainkhan.android.demo.ui.common + +import android.view.ViewGroup +import androidx.databinding.ViewDataBinding +import androidx.recyclerview.widget.AsyncDifferConfig +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter + +/** + * A generic RecyclerView adapter that uses Data Binding & DiffUtil. + * + * Here is an example of adapter with diff utils and click listener implemented. + * ```kotlin + * class ExampleListAdapter( + * private val itemClickCallback: ((ModelObject) -> Unit)? + * ) : DataBoundListAdapter( + * diffCallback = object : DiffUtil.ItemCallback() { + * override fun areItemsTheSame(oldItem: ModelObject, newItem: ModelObject): Boolean { + * return oldItem.id == newItem.id + * } + * + * override fun areContentsTheSame(oldItem: ModelObject, newItem: ModelObject): Boolean { + * return oldItem == newItem + * } + * } + * ) { + * + * override fun createBinding(parent: ViewGroup): ListItemBinding { + * val binding = DataBindingUtil.inflate( + * LayoutInflater.from(parent.context), R.layout.list_item, + * parent, false) + * + * binding.root.setOnClickListener { + * binding.data?.let { + * itemClickCallback?.invoke(it) + * } + * } + * return binding + * } + * + * override fun bind(binding: ListItemBinding, item: ModelObject) { + * binding.idea = item + * } + * } + * ``` + * + * And here is how the adapter is instantiated in Fragment/Activity + * ``` + * val ideaListAdapter = ExampleListAdapter { modelObject -> + * doActionOnModelObjectSelected(modelObject) + * } + * ``` + * + * @param Type of the items in the list + * @param The type of the ViewDataBinding + */ +abstract class DataBoundListAdapter( + diffCallback: DiffUtil.ItemCallback +) : ListAdapter>( + AsyncDifferConfig.Builder(diffCallback).build() +) { + /** + * Provides [ViewDataBinding] for the list item after it's inflated with DataBinding. + */ + protected abstract fun createBinding(parent: ViewGroup): V + + /** + * API where view should bound with the data model item. + */ + protected abstract fun bind(binding: V, item: T) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataBoundViewHolder { + val binding = createBinding(parent) + return DataBoundViewHolder(binding) + } + + + override fun onBindViewHolder(holder: DataBoundViewHolder, position: Int) { + bind(holder.binding, getItem(position)) + holder.binding.executePendingBindings() + } + + +} diff --git a/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundViewHolder.kt b/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundViewHolder.kt new file mode 100644 index 0000000..95658da --- /dev/null +++ b/app/src/main/java/com/hossainkhan/android/demo/ui/common/DataBoundViewHolder.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Hossain Khan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hossainkhan.android.demo.ui.common + +import androidx.databinding.ViewDataBinding +import androidx.recyclerview.widget.RecyclerView + +/** + * A generic ViewHolder that works with a [ViewDataBinding]. + * @param The type of the ViewDataBinding. + */ +class DataBoundViewHolder constructor( + val binding: T +) : RecyclerView.ViewHolder(binding.root) diff --git a/resources/google-play/Constraint Layout - Google Play Banner.svg b/resources/google-play/Constraint Layout - Google Play Banner.svg new file mode 100644 index 0000000..533e38e --- /dev/null +++ b/resources/google-play/Constraint Layout - Google Play Banner.svg @@ -0,0 +1,15 @@ + + +Android Constraint LayoutDEMO \ No newline at end of file diff --git a/resources/google-play/ConstraintLayout-banner.png b/resources/google-play/ConstraintLayout-banner.png new file mode 100644 index 0000000..1f5ef50 Binary files /dev/null and b/resources/google-play/ConstraintLayout-banner.png differ