Skip to content

Instantly share code, notes, and snippets.

@devrath
Created March 15, 2022 12:18
Show Gist options
  • Select an option

  • Save devrath/11842ade3b69c8726ef92c4e009d20ab to your computer and use it in GitHub Desktop.

Select an option

Save devrath/11842ade3b69c8726ef92c4e009d20ab to your computer and use it in GitHub Desktop.
Here we shall have a fragment that has a recycler view
class BreakingNewsFragment : Fragment(R.layout.fragment_breaking_news) {
private val viewModel: BreakingNewsViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = FragmentBreakingNewsBinding.bind(view)
val newsArticleAdapter = NewsArticleListAdapter(
onItemClick = { article ->
},
onBookmarkClick = { article ->
}
)
binding.apply {
recyclerView.apply {
adapter = newsArticleAdapter
layoutManager = LinearLayoutManager(requireContext())
setHasFixedSize(true)
}
lifecycleScope.launchWhenResumed {
viewModel.breakingNews.collect { articles ->
newsArticleAdapter.submitList(articles)
}
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/text_view_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/button_retry"
android:layout_margin="8dp"
android:gravity="center_horizontal"
android:visibility="gone"
tools:text="An error occurred"
tools:visibility="visible" />
<Button
android:id="@+id/button_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/retry"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/backgrounds/scenic" />
<ImageView
android:layout_width="match_parent"
android:layout_height="80dp"
android:src="@drawable/gradient"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_view_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#fff"
app:layout_constraintEnd_toStartOf="@id/image_view_bookmark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Headline" />
<ImageView
android:id="@+id/image_view_bookmark"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_margin="8dp"
android:src="@drawable/ic_bookmark_unselected"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
class NewsArticleComparator : DiffUtil.ItemCallback<NewsArticle>() {
/**
* To know if two articles are the same, we can use the url field because url is the primary key
*/
override fun areItemsTheSame(oldItem: NewsArticle, newItem: NewsArticle) =
oldItem.url == newItem.url
/**
* Now in comparing two items, We need to match each value of NewsArticle constructor param
* So, If either one of the param is different, We return false
*/
override fun areContentsTheSame(oldItem: NewsArticle, newItem: NewsArticle) =
oldItem == newItem
}
class NewsArticleListAdapter(
private val onItemClick : (NewsArticle) -> Unit,
private val onBookmarkClick : (NewsArticle) -> Unit
) : ListAdapter<NewsArticle,NewsArticleViewHolder>(NewsArticleComparator()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsArticleViewHolder {
val binding =
ItemNewsArticleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return NewsArticleViewHolder(
binding,
onItemClick = { position ->
val article = getItem(position)
if (article != null) {
onItemClick(article)
}
},
onBookmarkClick = { position ->
val article = getItem(position)
if (article != null) {
onBookmarkClick(article)
}
}
)
}
override fun onBindViewHolder(holder: NewsArticleViewHolder, position: Int) {
// Get the position of the item
val currentItem = getItem(position)
// Theoretically current item can return null so we shall check for null and then bind the item
if (currentItem != null) {
holder.bind(currentItem)
}
}
}
class NewsArticleViewHolder(
// Binding view
private val binding: ItemNewsArticleBinding,
// Entire row click
private val onItemClick : (Int) -> Unit,
// Bookmark view click
private val onBookmarkClick : (Int) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
init {
// Position of the adapter
val position = bindingAdapterPosition
binding.apply {
// Set click listener for entire row
root.setOnClickListener {
if (position != RecyclerView.NO_POSITION) {
onItemClick(position)
}
}
// Set click listener for a particular item in the row
imageViewBookmark.setOnClickListener {
if (position != RecyclerView.NO_POSITION) {
onBookmarkClick(position)
}
}
}
}
fun bind(article: NewsArticle) {
binding.apply {
Glide.with(itemView)
.load(article.thumbnailUrl)
.error(R.drawable.image_placeholder)
.into(imageView)
textViewTitle.text = article.title ?: ""
imageViewBookmark.setImageResource(
when {
article.isBookmarked -> R.drawable.ic_bookmark_selected
else -> R.drawable.ic_bookmark_unselected
}
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment