Horizontal recyclerView (DiscreteScrollView library) with scaling set to 50% between selected view and others doesn't keep spacing the same. Example below shows that spacing between 1/2 and 4/5 are more spacious than views next to currently selected item on center. It happens gradually by scrolling, for an example going from item 3 to item 2 will be moving item 3/4 apart from each other when onScroll is happening.
spacing between items example
I Thought about checking the current width of view when onScroll is happening and programatically reduce the left/right margin by applying new layout params so the space would stay the same.
Trying:
override fun onScroll(
scrollPosition: Float,
currentPosition: Int,
newPosition: Int,
currentHolder: CurrencyAdapter.ViewHolder?,
newCurrent: CurrencyAdapter.ViewHolder?
) {
val layoutParams = currentHolder.layout.layoutParams as ConstraintLayout.LayoutParams
}
}
produces
ClassCastException: androidx.recyclerview.widget.RecyclerView$LayoutParams cannot be cast to androidx.constraintlayout.widget.ConstraintLayout$LayoutParams
1. Is it possible to manipulate layoutParams from within viewHolder?
2. Are there any other options to set fixed spacing?
EDIT:
adding DividerItemDecoration shows better where the problem is coming from:
DividerItemDecoration
3. Is ItemDecoration the right direction for fixing the issue then?
Related
I have a viewpager2 with customTransformer that works fine, the issue is i can't define margin between items so it only shows 1 item at a time (i don't want to see the preview of the swiped item) , i tried with setPadding(12,0,0,0) and what it actually did ,it cut from the width of my item. i couldn't find how to use margin in itemdecoration so it could set a larger margin between th eitems, anybody have an idea ?
I ended up editing my own custom hinge depth page Transformer by setting up the spacing needed for between items to translationX = spacingValue
I have a problem with recyclerview items width:
i already looked through android docs and stack so i think, there is no solution to this problem.
i have an ordinary recyclerview with a horizontal gridlayout
sorry, but i dont have enough reputation to embed pictures
Picture of recyclerview
and i want the items of it being shown next to each other, but I want to make the width of the items depend on the width of the parent (in this case, the recyclerview width used in the other fragment).
I can show you what i want by using a fixed value (in this example 200dp)
Picture of the solution I want, but here a fixed value for width is used
However if my constraint of the item is set to "match parent" like here:
Picture constraint set to match parent
The result is, that the width of the items seen in the phone always depends of the width of the recyclerview. in my case its cut nearly in half:
recyclerview cut in half
also android studio only allows one view as a top level layout, so i cannot use a guideline that is set to any %
possible solution to that?
If you have width of recycler view (in pixel not dp), just divide it by number of items in a row, and in your adapter in "onBindViewHolder" method set item width. this solution is when all of your item has same width.
In addition for height of every item use WRAP_CONTENT.
I've RecyclerView with LinearLayoutManager and horizontal orientation. I want to add it zoom in/out functions(like Trello Android app). I changed the items' scale:
itemView.scaleY = 0.7f
itemView.scaleX = 0.7f
Then space appeared between items. How to remove these spaces and place items one by one without space? This is how it looks like now
I'm using a horizontal RecyclerView with PagerSnapHelper to make it look like a ViewPager. It's displaying CardViews.
My question is, how can I make it show a small peek of the edge of the next and previous card? The user needs to see a little of those cards so they understand intuitively that they need to swipe horizontally so they can view other cards.
I'll also note that the current card always needs to be centered, even for the first one, which would not have a previous card peeking on the left. Also, the design requirements are out of my control; I need to peek, I can't use dot indicators or anything else.
I could use a LinearSnapHelper and make the width of the cards smaller, but then 1) the first item will be left-aligned instead of centered, since there's no card peeking on the left side and 2) how much of each card displays would vary based on the width of the phone.
This seems like it should be a common and simple task, so I hope I'm missing something obvious to make it happen.
After some trial and error, I found a solution. Fortunately, it wasn't as complicated as I thought, although not as clean as I hoped.
So start with a RecyclerView and its Adapter, use a LinearLayoutManager with a Horizontal orientation, add in a PagerSnapHelper and so on... then to fix the specific issue in this question I made some adjustments to the adapter:
private var orientation: Int? = null
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
orientation = (recyclerView.layoutManager as LinearLayoutManager).orientation
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Kludge to adjust margins for horizontal, ViewPager style RecyclerView
if (orientation != LinearLayout.VERTICAL) {
holder.itemView.layoutParams = (holder.itemView.layoutParams as RecyclerView.LayoutParams).apply {
val displayMetrics = DisplayMetrics()
baseActivity.windowManager.defaultDisplay.getMetrics(displayMetrics)
// To show the edge of the next/previous card on the screen, we'll adjust the width of our MATCH_PARENT card to make
// it just slightly smaller than the screen. That way, no matter the size of the screen, the card will fill most of
// it and show a hint of the next cards.
val widthSubtraction = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40f, displayMetrics).toInt()
width = displayMetrics.widthPixels - widthSubtraction
// We always want the spot card centered. But the RecyclerView will left-align the first card and right-align the
// last card, since there's no card peeking on that size. We'll adjust the margins in those two places to pad it out
// so those cards appear centered.
// Theoretically we SHOULD be able to just use half of the amount we shrank the card by, but for some reason that's
// not quite right, so I'm adding a fudge factor developed via trial and error to make it look better.
val fudgeFactor = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6f, displayMetrics).toInt()
val endAdjustment = (widthSubtraction / 2) - fudgeFactor
marginStart = if (position == 0) endAdjustment else 0
marginEnd = if (position == (itemCount - 1)) endAdjustment else 0
}
}
}
Of course, you'll want to change 40f and 6f to the appropriate values for your use case.
In case you're wondering, I have the orientation check because in my case, the same adapter is used for two different RecyclerViews. One is a simple vertical list. The other is horizontal and functions like a ViewPager, which greatly increased the complexity.
Is there any good way of getting the height of the content inside RecyclerView? Considering all items may have different height.
In my scenario I'm using a LinearLayoutManager.
I've searched around and found surprisingly few results for this problem.
RecyclerView.computeVerticalScrollRange will give an estimation - it averages the height of the rows being currently displayed and multiplies that by the result of getItemCount
computeHorizontalScrollRange for width if you're orientation is horizontal.
RecyclerView is a ViewGroup. You can use getChildAt / getChildCount to get views. Then from the view, you can call getWidth / getHeight.
If you have ItemDecorators and need to get size including them, you can use LayoutManager's getDecorated<xxx> methods.
I use to experiment with View.measure method:
recycler.measure(View.MeasureSpec.makeMeasureSpec(recycler.width, View.MeasureSpec.EXACTLY), View.MeasureSpec.UNSPECIFIED)
val height = recycler.measuredHeight
If your items are simple enough (e.g. with fixed heights), it should work.