guys
When I use horizontal RecyclerView ItemDecoration I encounter some problems, I want to achieve different decoration height but horizontal recyclerview decoration height is always the same, pictures and code are below, I used the same code in vertical GridLayoutManger is effective, I saw the source code should be measured when the horizontal recyclerview has special processing, this is normal?
pic
class MainItemDecoration : RecyclerView.ItemDecoration() {
private val space20 = (Resources.getSystem().displayMetrics.density * 20).toInt()
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
) {
val lp = view.layoutParams as GridLayoutManager.LayoutParams
outRect.left = space20
outRect.right = space20
when (lp.spanIndex) {
0 -> {
outRect.bottom = 0
}
1 -> {
outRect.bottom = space20
}
2 -> {
outRect.bottom = space20 * 2
}
}
}
}
----- MainActivity----
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
recyclerView.apply {
layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false)
adapter = MainAdapter()
addItemDecoration(MainItemDecoration())
}
}
}
--- xml-------
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/holo_red_light"
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:listitem="#layout/item_main"
tools:orientation="horizontal"
tools:spanCount="3" />
</FrameLayout>
--- item ----
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/text"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:background="#android:color/holo_blue_light"
android:gravity="center"
android:textColor="#android:color/white"
android:textSize="16sp"
tools:text="123" />
</FrameLayout>
Related
I need to display items similar to a hamburger.
Each element has a different height, but the distance between them should be always the same. I tried to use LinearLayoutManager, but spaces between items were too big. I created custom LinearLayoutManager but it doesn't work as I expected. How I should make spacing like 16dp or 50 px between ImageView.
I also need to make no spacing for the same type of items, but this problem is less important.
class CustomLinearLayoutManager(context: Context) : LinearLayoutManager(context) {
private val horizontalSpace: Int
get() = width - paddingEnd - paddingStart
private val verticalSpace: Int
get() = height - paddingBottom - paddingTop
override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateDefaultLayoutParams())
}
override fun generateLayoutParams(c: Context, attrs: AttributeSet): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateLayoutParams(c, attrs))
}
override fun generateLayoutParams(lp: ViewGroup.LayoutParams): RecyclerView.LayoutParams {
return spanLayoutSize(super.generateLayoutParams(lp))
}
private fun spanLayoutSize(layoutParams: RecyclerView.LayoutParams): RecyclerView.LayoutParams {
if (orientation == HORIZONTAL) {
layoutParams.width = (horizontalSpace / itemCount)
} else if (orientation == VERTICAL) {
layoutParams.height = (verticalSpace / itemCount)
}
return layoutParams
}
override fun canScrollVertically(): Boolean {
return false
}
override fun canScrollHorizontally(): Boolean {
return false
}
}
RecyclerView_item.xml
<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:id="#+id/RecyclerFood_item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/ingredientPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:contentDescription="#string/display_image_of_ingredient"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment_layout.xml
<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:id="#+id/DishFragmentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="my.custom.food-app.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/DishList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am trying to implement a simple nested recyclerview with a vertical parent and horizontal children.
The layout for the parent is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<include layout="#layout/loading_indicator" />
<include layout="#layout/error_layout" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcasts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/podcastsTitle"
android:layout_marginTop="5dp" />
</RelativeLayout>
The layout for the child recyclerview is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
style="#style/TitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:textAppearance="#style/TextAppearance.AppCompat.Large" />
<TextView
android:id="#+id/description"
style="#style/AuxTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:maxLines="2"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcastsItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
The adapter for the parent is as follows:
class CuratedPodcastsAdapter(val context: Context, private val podcastLists: ArrayList<PodcastList>) : RecyclerView.Adapter<CuratedPodcastsAdapter.ViewHolder>() {
private val viewPool = RecyclerView.RecycledViewPool()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.podcast_section_layout, parent, false))
override fun getItemCount(): Int = podcastLists.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(podcastLists[holder.adapterPosition])
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
#BindView(R.id.title)
lateinit var title: TextView
#BindView(R.id.description)
lateinit var description: TextView
#BindView(R.id.podcastsItems)
lateinit var podcastItems: RecyclerView
init {
ButterKnife.bind(this, itemView)
}
fun bindItems(curatedPodcastList: PodcastList) {
title.text = curatedPodcastList.title
description.text = curatedPodcastList.description
title.typeface = FontUtils.boldTypeface
description.typeface = FontUtils.mediumTypeface
val childLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
childLayoutManager.initialPrefetchItemCount = 4
podcastItems.apply {
layoutManager = childLayoutManager
adapter = PodcastAdapter(this#CuratedPodcastsAdapter.context, curatedPodcastList.podcasts!!)
setItemViewCacheSize(20)
setRecycledViewPool(viewPool)
}
}
}
}
while the children's adapter is:
class PodcastAdapter(val context: Context, private val episodes: ArrayList<Podcast>): RecyclerView.Adapter<PodcastAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.podcast_item_layout, parent, false))
override fun getItemCount(): Int = episodes.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindItems(episodes[holder.adapterPosition])
}
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view) {
#BindView(R.id.art)
lateinit var art: ImageView
#BindView(R.id.title)
lateinit var title: TextView
#BindView(R.id.publisher)
lateinit var publisher: TextView
#BindView(R.id.card)
lateinit var card: CardView
init {
ButterKnife.bind(this, view)
}
fun bindItems(podcast: Podcast){
title.text = podcast.title
publisher.text = podcast.publisher
GlideApp.with(context).load(podcast.image).error(R.drawable.no_cover).into(art)
card.setOnClickListener {
context.startActivity(context.intentFor<PodcastActivity>(PodcastActivity.PODCAST_ID to podcast.id, PodcastActivity.PODCAST_TITLE to podcast.title))
}
}
}
}
When content is loaded for the first time, everything appears correctly like below:
After scrolling downwards then back up again, spaces begin to appear between the content like so:
None of the recyclerviews have any item decoration added to them. My perception was that using a common viewpool would at least improve performance and help with such layout inconsistencies but it hasn't helped.
What is the cause of this problem and how can it be fixed?
You need to change the height of your child layout of recyclerview
to android:layout_height="wrap_content"
Sample code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
style="#style/TitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:textAppearance="#style/TextAppearance.AppCompat.Large" />
<TextView
android:id="#+id/description"
style="#style/AuxTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:maxLines="2"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/podcastsItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
I'm preparing a little game in my app and would like to create a recylerview based on gridlayoutmanager and my problem is that I can't center horizontally all elements inside this view.
I have already tried to fix it by some changes in layout file but it didn't help.
Adapter :
class AdapterCheckYrslf(private val word: String) :
RecyclerView.Adapter<AdapterCheckYrslf.CardViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_checkrslf_letter, parent, false)
return CardViewHolder(view)
}
override fun getItemCount(): Int {
return word.length
}
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
holder.currentLetter.text = word[position].toUpperCase().toString()
}
class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val currentLetter = itemView.findViewById<TextView>(R.id.item_checkyrslf_letter)
}
}
GridSpacingItemDecoration, it makes a space beetwen every item :
class GridSpacingItemDecoration(private val space: Int) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View,
parent: RecyclerView, state: RecyclerView.State) {
outRect.left = space
outRect.right = space
outRect.bottom = space
outRect.top = space
}
}
ColumnQty :
class ColumnQty(context: Context, viewId: Int) {
private val width: Int
private val height: Int
private var remaining: Int = 0
private val displayMetrics: DisplayMetrics
init {
val view = View.inflate(context, viewId, null)
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
width = view.measuredWidth
height = view.measuredHeight
displayMetrics = context.resources.displayMetrics
}
fun calculateNoOfColumns(): Int {
var numberOfColumns = displayMetrics.widthPixels / width
remaining = displayMetrics.widthPixels - numberOfColumns * width
if (remaining / (2 * numberOfColumns) < 15) {
numberOfColumns--
remaining = displayMetrics.widthPixels - numberOfColumns * width
}
return numberOfColumns
}
fun calculateSpacing(): Int {
val numberOfColumns = calculateNoOfColumns()
return remaining / (2 * numberOfColumns)
}
}
Activity :
val gridManagerFix = ColumnQty(this, R.layout.item_checkrslf_letter)
check_yrslf_word.layoutManager = GridLayoutManager(this, gridManagerFix.calculateNoOfColumns())
check_yrslf_word.addItemDecoration(GridSpacingItemDecoration(gridManagerFix.calculateSpacing()))
check_yrslf_word.setHasFixedSize(true)
Fragment of layout :
<LinearLayout
android:id="#+id/helper_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center_vertical"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="#+id/check_yrslf_end"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/check_yrslf_hand">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/check_yrslf_word"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:clipChildren="true"
android:clipToPadding="true"
android:numColumns="auto_fit"
android:overScrollMode="never"
android:scrollbars="none"
android:scrollingCache="true"
android:stretchMode="columnWidth"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
Item layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:id="#+id/item_checkyrslf_cardLetter"
style="#style/Widget.MaterialComponents.CardView"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_marginBottom="5dp"
android:checkable="false"
app:cardBackgroundColor="#color/grey_3"
app:cardElevation="0dp"
app:checkedIconTint="#color/white"
app:strokeColor="#color/colorAccent"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/item_checkyrslf_letter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="#font/poppins_medium"
android:gravity="center"
android:includeFontPadding="false"
android:text="A"
android:textAppearance="#style/TextAppearance.MaterialComponents.Headline1"
android:textColor="#color/textColor"
android:textSize="16sp" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
Pictures :
How does this layout look in Preview
That's what I have
I would like to have
Try making the RecyclerView android:layout_width="match_parent" and android:gravity="center"
Edit 1:
Try removing all those added params to your RecyclerView: (Something like this)
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/check_yrslf_word"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_gravity="center_horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Now try it, just for debugging purposes.
I have solved it by changing GridLayoutManager to LinearLayoutManager.
I am using groupie recycler view to display 4 items. I want the layout to be a 2x2 instead of all of them under one another. This is what I have so far and the way it displays:
Module Class:
data class Module ( val Code: String,
val Desc: String){
constructor(): this("", "")
}
Module Fragment code snippet:
private fun updateRecyclerView(items: List<Item>) {
fun init() {
recycler_view_mod.apply {
layoutManager = LinearLayoutManager(this#ModuleFragment.context)
adapter = GroupAdapter<ViewHolder>().apply {
moduleSection = Section(items)
add(moduleSection)
//setOnItemClickListener(onItemClick)
}
}
shouldInitRecyclerView = false
}
fun updateItems() = moduleSection.update(items)
if (shouldInitRecyclerView)
init()
else
updateItems()
}
ModuleItem:
class ModuleItem (val module: Module,
val modId: String,
private val context: Context)
: Item(){
override fun bind(viewHolder: ViewHolder, position: Int) {
viewHolder.textView_Code.text = module.Code
viewHolder.textView_Description.text = module.Desc
}
override fun getLayout() = R.layout.item_module
}
Module Fragment layout:
<FrameLayout 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"
tools:context=".fragment.ModuleFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view_mod"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
ModuleItem Layout:
<android.support.v7.widget.CardView
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:id="#+id/cardView_item_module"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_margin="4dp"
android:foreground="?android:attr/selectableItemBackground"
app:cardBackgroundColor="#android:color/white"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="4dp"
app:cardElevation="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView_Code"
android:textColor="#color/colorPrimaryDark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="#id/imageView_profile_picture"
android:layout_marginStart="10dp"
android:layout_marginTop="5dp"
android:textSize="25sp"
android:textAppearance="#style/Base.TextAppearance.AppCompat"
tools:text="Code" />
<TextView
android:id="#+id/textView_Description"
android:textColor="#color/colorPrimaryDark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="#+id/textView_Code"
android:layout_below="#+id/textView_Code"
android:layout_marginStart="2dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="#style/Base.TextAppearance.AppCompat.Small"
tools:text="Description" />
</RelativeLayout>
</android.support.v7.widget.CardView>
ScreenShot:
Any help would be appreciated, let me know if you need any more information
So all you have to do is adjust the layoutmanager, like this:
private fun updateRecyclerView(items: List<Item>) {
fun init() {
recycler_view_mod.apply {
layoutManager = GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false)
adapter = GroupAdapter<ViewHolder>().apply {
moduleSection = Section(items)
add(moduleSection)
//setOnItemClickListener(onItemClick)
}
}
shouldInitRecyclerView = false
}
fun updateItems() = moduleSection.update(items)
if (shouldInitRecyclerView)
init()
else
updateItems()
}
You just need to use the right layout manager, it would look something to this effect, just set the span to 2
val mLayoutManager = GridLayoutManager(context, 2, GridLayoutManager.VERTICAL, false)
recyclerView.setLayoutManager(mLayoutManager)
I've been scratching my head about this problem. I have a recyclerview inside a recyclerview that shows a grid layout where you can scroll both vertically and horizontally.
I decided to enlarge the width and height of each item. Previously, width and height were: 80 x 100
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/book_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/inner_dropshadow"
android:layout_width="80dp"
android:layout_height="100dp"
android:scaleType="fitXY"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/bookdropshadow" />
</android.support.constraint.ConstraintLayout>
And then I enlarged it to 150x 180. And then Level 4-6 row completely disappeared no matter how much I scroll up. I only expected the recyclerview to display larger images. Why does this happen?
[EDIT] I ran a debug and it seems only 3 positions are bound in the outer adapter when the app is run on a phone but there are 4 positions when run on a tablet.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/book_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/inner_dropshadow"
android:layout_width="150dp"
android:layout_height="180dp"
android:scaleType="fitXY"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/bookdropshadow" />
</android.support.constraint.ConstraintLayout>
Please note that this also happens when I run the app on a device. In a tablet, it shows all the Levels, while on a phone, it only shows Levels 1-3.
Outer recyclerview layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/mainlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/color_white">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="#+id/swiperefresh"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/toolbar">
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="always">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/browsebooksheader_layout"
android:id="#+id/bb_header"
app:layout_constraintBottom_toTopOf="#+id/guidelinetop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"/>
<android.support.constraint.Guideline
android:id="#+id/guidelinetop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.30"/>
<Button
android:id="#+id/btn_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:background="#drawable/search_btn_border"
android:padding="8dp"
android:text="Search"
android:textSize="#dimen/browse_search_textsize"
android:textColor="#android:color/darker_gray"
app:layout_constraintBottom_toTopOf="#+id/recyclerview_main"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/bb_header" />
<ProgressBar
android:id="#+id/main_progressbar"
style="?android:attr/progressBarStyleSmall"
android:layout_marginTop="16dp"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:indeterminateTint="#color/color_grey"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btn_search"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"
android:background="#color/color_white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/btn_search"
app:layout_constraintBottom_toBottomOf="parent"/>
</android.support.constraint.ConstraintLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/toolbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/swiperefresh"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<include layout="#layout/toolbar_layout_wo_learn"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
Inner recyclerview layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/book_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Category Title"
android:textColor="#color/defaultdark_color"
android:textSize="#dimen/browse_category_textsize"
android:fontFamily="#font/vagroundedstd_bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="#dimen/browse_seeall_imagesize"
android:layout_height="#dimen/browse_seeall_imagesize"
android:layout_marginBottom="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:id="#+id/see_all_btn"
android:src="#drawable/seeall"
app:layout_constraintBottom_toTopOf="#+id/inner_recyclerview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/inner_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
android:background="#color/color_white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/book_category"/>
<TextView
android:id="#+id/h_line"
android:layout_width="match_parent"
android:layout_height="0.8dp"
android:background="#color/color_grey"
android:gravity="center"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:alpha="0.5"
app:layout_constraintTop_toBottomOf="#id/inner_recyclerview"/>
</android.support.constraint.ConstraintLayout>
Outer Adapter
class BrowseBooksAdapter : RecyclerView.Adapter<BrowseBooksAdapter.SimpleViewHolder>() {
private var sortedList : SortedMap<String, List<ResourcesList>> = emptyMap<String, List<ResourcesList>>().toSortedMap()
fun setData(sortedList : SortedMap<String, List<ResourcesList>>) {
if (this.sortedList != sortedList) {
this.sortedList = sortedList
notifyDataSetChanged()
}
}
override fun getItemCount(): Int {
return sortedList.count()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.browsebooks_layout, parent, false)
return SimpleViewHolder(view)
}
override fun onBindViewHolder(holder: SimpleViewHolder, position: Int) {
val dataList = ArrayList(sortedList.values)[position]
holder.category_text.text = ArrayList(sortedList.keys)[position]
holder.booksByCategory = dataList
holder.horizontalAdapter.setData(dataList)
}
class SimpleViewHolder(v: View, var booksByCategory : List<ResourcesList>? = null) : RecyclerView.ViewHolder(v) {
var recyclerView : RecyclerView = v.findViewById(R.id.inner_recyclerview)
var category_text : TextView = v.findViewById(R.id.book_category)
var fragmentCallback: FragmentCallback? = null
val horizontalAdapter: BooksByCategoryAdapter
init {
recyclerView.layoutManager = object : LinearLayoutManager(v.context, LinearLayoutManager.HORIZONTAL, false) {
override fun canScrollHorizontally(): Boolean {
return true
}
override fun canScrollVertically(): Boolean {
return false
}
}
horizontalAdapter = BooksByCategoryAdapter()
recyclerView.adapter = horizontalAdapter
fragmentCallback = v.context as FragmentCallback
var mLastClickTime : Long = 0
v.see_all_btn.setOnClickListener {
val category = v.book_category.text.toString()
// double-clicking prevention, using threshold of 1000 ms
if (!(SystemClock.elapsedRealtime() - mLastClickTime < 1000)){
mLastClickTime = SystemClock.elapsedRealtime()
if(fragmentCallback != null){
fragmentCallback!!.callBackSeeAllFragment(booksByCategory!!, category)
}
}
}
}
}
}
Inner Adapter
class BooksByCategoryAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var booksByCategory: List<ResourcesList> = emptyList()
fun setData(data: List<ResourcesList>) {
if (this.booksByCategory != data) {
this.booksByCategory = data
notifyDataSetChanged()
}
}
override fun getItemCount(): Int {
return booksByCategory.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val cellForRow = layoutInflater.inflate(R.layout.bookcontainer_layout, parent, false)
return CustomVH(cellForRow)
}
override fun onBindViewHolder(rawHolder: RecyclerView.ViewHolder, position: Int) {
val holder = rawHolder as CustomVH
val booksProcessModel = BooksProcessModel()
booksProcessModel.setItem(booksByCategory[position])
holder.booksByCategory = booksByCategory[position]
Picasso.get().load(booksByCategory[position].coverURI).into(holder.inner_bookcover)
}
private inner class CustomVH(v: View, var booksByCategory : ResourcesList? = null): RecyclerView.ViewHolder(v) {
var inner_bookcover : ImageView = v.findViewById(R.id.inner_bookcover)
var fragmentCallback: FragmentCallback? = null
var ctx : Context = v.context
var mLastClickTime : Long = 0
init {
fragmentCallback = ctx as FragmentCallback
v.setOnClickListener {
// double-clicking prevention, using threshold of 1000 ms
if (!(SystemClock.elapsedRealtime() - mLastClickTime < 1000)){
mLastClickTime = SystemClock.elapsedRealtime()
if(fragmentCallback != null){
fragmentCallback!!.callBackDownloadBookFragment(booksByCategory!!)
}
}
}
}
}
class BooksProcessModel {
private var processBooks : ResourcesList? = null
fun setItem(books: ResourcesList) {
this.processBooks = books
}
fun setVisibility(ctx: Context) : Int {
val sp = PreferenceManager.getDefaultSharedPreferences(ctx)
val page = sp.getString(processBooks!!.id.toString(), "")
if (page != "") {
return View.VISIBLE
}
return View.INVISIBLE
}
}
}
You need to change the layout_height of the outer recycler view to wrap_content.
Nevermind, figured it out. I should be using a NestedScrollView instead of a ScrollView. The missing items were still there. It's just that I couldn't scroll the nested recyclerview.
In my case it was because I had the RecyclerView directly and even though it scrolled (horizontally), the same thing happened to me if for example the keyboard appeared.
Solution: Put the RecyclerView inside a NestedScrollView and delegate the scroll to it, like this:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/item"/>
</androidx.core.widget.NestedScrollView>