I want to add horizontal image scroller like an image attached below. I know there are solutions but all solutions are 4 to 5 years old and after Kotlin and constraint layout I am assuming that now there are some good methods to achieve this. Please help me out and share the best and easy way to do this. Thanks in advance.

- 112
- 6

- 624
- 15
- 35
-
Have you tried using HorizontalScrollView? – SaadAAkash Oct 02 '19 at 10:14
-
https://stackoverflow.com/questions/29429556/android-horizontal-scrolling-image-gallery I am trying to do with this method (Answer No.1) but I don't know how to add different image in loop – SFAH Oct 02 '19 at 10:26
-
You should use horizontal RecyclerView and pass lambda as a click listener – Vitalii Malyi Oct 02 '19 at 10:29
-
1@SFAH okay I'm implementing one for you with multiple images & posting as an answer in a short while. – SaadAAkash Oct 02 '19 at 10:34
2 Answers
Create an Item:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:background="@color/colorAccent"
card_view:cardCornerRadius="8dp"
card_view:cardUseCompatPadding="true">
<LinearLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:scaleType="centerCrop"
android:src="@mipmap/ic_launcher_round" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="8dp"
android:text="@string/app_name"
android:textColor="#000000"
android:textSize="16sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
Then add this item to your RecyclerView
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorPrimary" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" />
</LinearLayout>
Then call it from your Activity and set a HORIZONTAL
LayoutManager to it and then its adapter:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
displayList()
}
private fun displayList() {
val imageList = ArrayList<ImageDataModel>()
imageList.clear()
imageList.add(ImageDataModel("https://conversionxl.com/wp-content/uploads/2018/09/coding-language.jpg", "Test"))
imageList.add(ImageDataModel("https://makeawebsitehub.com/wp-content/uploads/2016/02/learn-code-e1455713167295.jpg", "Test"))
imageList.add(ImageDataModel("https://www.tecmint.com/wp-content/uploads/2016/11/Convert-PNG-to-JPG-Using-for-loop-Command.png", "Test"))
imageList.add(ImageDataModel("https://conversionxl.com/wp-content/uploads/2018/09/coding-language.jpg", "Test"))
imageList.add(ImageDataModel("https://www.tecmint.com/wp-content/uploads/2016/11/Convert-PNG-to-JPG-Using-for-loop-Command.png", "Test"))
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.HORIZONTAL, false)
recyclerView.adapter = ViewAdapter(imageList)
}
}
As you can see the RecyclerView needs an Adapter too, it's a simple Adapter which uses Glide to shown images like this:
class ViewAdapter(private val imageDataModelList: ArrayList<ImageDataModel>) : RecyclerView.Adapter<ViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_list, parent, false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(imageDataModelList[position])
}
override fun getItemCount(): Int {
return imageDataModelList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindItems(imageDataModel: ImageDataModel) {
val textView = itemView.findViewById<TextView>(R.id.tvName)
val imageView = itemView.findViewById<ImageView>(R.id.imageView)
textView.text = imageDataModel.name
Glide.with(itemView.context).load(imageDataModel.url).into(imageView)
}
}
}
Don't forget to add dependencies of Glide in your app-level build.gradle
:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
}
The app should look like this: https://i.stack.imgur.com/fpGuq.jpg

- 3,065
- 3
- 19
- 25
-
-
1@SFAH inside `MainActivity` inside the method `displayList()`, since it's in Kotlin I don't need to initialize like in Java, this class can access id `recyclerView` of the layout `activity_main` directly. – SaadAAkash Oct 03 '19 at 14:35
-
Learn more about how I used Kotlin Extensions by importing Kotlin Synthetics in the following official documentation & example: https://kotlinlang.org/docs/tutorials/android-plugin.html – SaadAAkash Oct 03 '19 at 14:45
-
One more question please , What is imageDataModelList? I can't used it .. – SFAH Oct 03 '19 at 15:12
-
Sure, go on, no problem, I'm here to help. In the `MainActivity`, inside `displayList()`, I have a `val imageList = ArrayList
()`. Then I've passed this `ArrayList – SaadAAkash Oct 03 '19 at 15:17()` to Adapter in this line: `recyclerView.adapter = ViewAdapter(imageList)` -
And then in the ViewAdapter, I have `class ViewAdapter(private val imageDataModelList: ArrayList
)`, which means I've received that imageList as imageDataModelList here in the Adapter, I've just renamed while revceiving that's all. – SaadAAkash Oct 03 '19 at 15:18 -
Thankyou so much...BUt I cant understand this Datatype `ImageDataModel` What type of datatype this is? – SFAH Oct 03 '19 at 15:20
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200354/discussion-between-saadaakash-and-sfah). – SaadAAkash Oct 03 '19 at 15:23
Not specifically for RecyclerViews but there are some nice Kotlin language features you can use.
I personally would not do this with a constraint layout but a RecyclerView. Kotlin offers a couple of nice options for working with collections so its worth using those if you need to do any manipulation. I would advice you to not make the list available as mutable outside the adapter. This can be achieved with the use of backing properties.
As for making them clickable you could use an OnItemTouchListener. However personally I prefer to use OnClickListener and a callback. The callback belongs to the adapter and the OnClickListener is added to the root view of the viewholder.
Besides this their are various nice tricks you can use like typealias.
Here is the code I could come up with quickly (I haven't done any non test app work with recyclerviews so don't have a properly worked out sample to draw on):
class ImageListAdapter : RecyclerView.Adapter<ImageListAdapter.ImageListItemVH>() {
private val _items = mutableListOf<ImageItem>()
val items: List<ImageItem>
get() = _items
var clickCallback: ImageClickCallback? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageListItemVH {
val itemView = LayoutInflater.from(parent.context)
.inflate(
R.layout.viewholder_image_list_item,
parent,
false
)
return ImageListItemVH(itemView)
}
override fun getItemCount(): Int = _items.size
override fun onBindViewHolder(holder: ImageListItemVH, position: Int) {
holder.bind(_items[position]) { clickCallback?.invoke(it) }
}
fun addItem(newItem: ImageItem) {
_items += newItem
notifyItemInserted(_items.size - 1)
}
fun addItems(newItems: List<ImageItem>) {
val sizeBefore = _items.size
_items += newItems
notifyItemRangeInserted(sizeBefore - 1, newItems.size)
}
fun clearItems() {
val sizeBefore = _items.size
_items.clear()
notifyItemRangeRemoved(0, sizeBefore - 1)
}
fun setItems(items: List<ImageItem>) {
_items.clear()
_items += items
notifyDataSetChanged()
}
class ImageListItemVH(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(imageItem: ImageItem, callback: (id: String) -> Unit) =
itemView.setOnClickListener { callback(imageItem.id) }
}
}
data class ImageItem(
val id: String,
val location: String
)
typealias ImageClickCallback = (id: String) -> Unit
If the image collection is either of a large size or not limited to a small amount of static items you should use the paging library, specifically in this case the PagedList

- 71
- 4