RecyclerView item with layout_weight=1 - android

Resume:
I have a ChatActivity that's basic a RecyclerView. In my chat_row_layout, i have a horizontal LinearLayout (width = wrap_content) with 2 TextViews, one of then with layout_weight = 1.
My problem :
When scrolling the recycler, some of my views width get messed up because of the recycling.
Is there some way to fix that? Ex. Force the adapter to get the original view measures
Ps: sorry for the bad formating + lack of info (i'm on phone)

Related

Horizontal RecyclerView with variable item heights not wrapping properly

What I intend to achieve
The item view should occupy the entire height of the item
It could be that the item height is lesser than the height of the tallest item in the recyclerview, in which case it should just stick to the top like in the screenshot above.
The bug I'm running into
As in the screenshot above, views are getting truncated.
What I've tried so far
Initially I went with wrap_content on the recyclerview, now that it is supported. It didn't work when none of the views visible on the screen at the time were the tallest. This makes sense in how the view hierarchy is laid out. How can the height of something which hasn't even been bound to any data yet be calculated if the height is dependent on that data?
Workaround time :S
Instead of trying a custom layoutmanager, I first went with what I felt needed to be done - laying out all item views at the beginning to figure out their height.
There's a progressbar and an animation playing in the upper part of the screen to catch the user's attention while all this happens with recyclerview visibility set to invisible. I use two things, one didn't suffice - I've attached an observer in the adapter's onViewAttached() call and I've used a scroll change listener as well. There's a LinearSnapHelper attached to the recycler view to snap to adjacent (next or previous, depending on the scroll direction) position on scroll.
In this setup,
I'm going to each position in the recyclerview using layoutManager.smoothScrollToPosition()
Getting the child view height using
View currentChildView = binding.nextRv.getChildAt(layoutManager.findFirstCompletelyVisibleItemPosition());
if (currentChildView != null) {
currentChildHeight = currentChildView.getHeight();
}
in scroll change listener on RecyclerView.SCROLL_STATE_IDLE or by passing the height to the view attached observer mentioned above in the adapter's onViewAttachedToWindow()
#Override
public void onViewAttachedToWindow(BindingViewHolder holder) {
if (mObserver != null) {
mObserver.onViewAttached(holder.binding.getRoot().getHeight());
}
}
Storing a maxHeight that changes to the max of maxHeight and new child's height.
As is evident, this is ugly. Plus it doesn't give me the current view's height - onAttached means it's only just attached, not measured and laid out. It is the recycled view, not the view bound to current data item. Which presents problems like the truncation of view illustrated above.
I've also tried wrap_content height on the recycler view and invalidating from recycler's parent till the recycler and the child on scroll coming to SCROLL_STATE_IDLE. Doesn't work.
I'm not sure how a custom layoutmanager can help here.
Can someone guide me in the right direction?
I could not accept #Pradeep Kumar Kushwaha's answer because against one solution, I do not want different font sizes in the list. Consistency is a key element in design. Second alternative he gave couldn't work because with ellipsize I would need to give a "more" button of some sort for user to read the entire content and my text view is already taking a click action. Putting more some place else would again not be good design.
Changing the design with the simple compromise of resizing the recyclerview when the tallest, truncated item comes into focus, it turns into the simple use case of notifyItemChanged(). Even for the attempt I made using the view attached observer and scroll state listener, notifyItemChanged could be used but that approach is just too hacky. This I can live with in both code and design. Here goes the code required.
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
int position = ((LinearLayoutManager) binding.nextRv.getLayoutManager())
.findFirstVisibleItemPosition();
if (position != nextSnippetAdapter.getItemCount() - 1) {
binding.nextRv.getAdapter().notifyItemRangeChanged(position, 2);
} else {
binding.nextRv.getAdapter().notifyItemChanged(position);
}
}
}
For my particular setup, calling for just these two elements works. It can further be optimized so as to call for single element at position + 1 in most cases, and checking and calling for the appropriate one in corner (literal) cases.
Inside your adapter where I can find two cards one on top and another on bottom
How I would have defined my layout is like this:
Cardview1
LinearLayout1 --> orientation vertical
cardview2 (Top card where text is written)
Linearlayout2 (where I can see icons such as like etc)-->orientation horizontal
Now fix the height of Linearlayout2 by setting it to wrap content.
And the height of cardview2 should be 0dp and add weight = 1
Now inside cardview2 add a TextView1 to matchparent in height and width.
Better inside textview1 add ellipsize to end and add max lines
If you want to show all lines try to find autoresizetextview library it can be founded here --> AutoResizeTextView
Hope it helps.
I think the recyclerview can be set to height wrap_content. And the items can be make like height to match_parent.
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layput_height="wrap_content"/>
Item as:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
// your coode
</androidx.constraintlayout.widget.ConstraintLayout>
I had little more requirement than the question. Even my problem solved in the way.
Remember I am using:
androidx.recyclerview:recyclerview:1.0.0-beta01
dependency for the project

How to center RecyclerView in the center (and without scrolling) when possible?

This is a short question:
Suppose I have a RecyclerView that has undefined number of items, what should I do to it, so that if there is a small number of items that (all) can fit the screen, they will be centered and the user won't be able to scroll ?
Of course, if there are too many items, that cannot fit the screen, I would like to have the RecyclerView to show them all as normal (from the beginning to how much it can show, and allow to scroll).
To understand what I mean, I think such a thing is possible when using ScrollView (or HorizontalScrollView if in horizontal), together with a LinearLayout that sets the gravity to be centered .
OK, I think I've found a way:
first, we wait for the RecyclerView to finish its layout process, as I've found about here .
Then, you need to check which child views are shown (available in the LayoutManager that you use), and look at the first and last ones.
If both of them are exactly the same as those that of the total items, it means all needed views are shown, so I can add margins on both sides of the RecyclerView (or padding on its container), according to the space that's left.
I found one complicate way to achieve that.
Main concept: set the height of RV dynamicly in code
RecyclerView rv= (RecyclerView) findViewById(R.id.rv);
rv.setAdapter(new MySlideUpAdapter());
rv.setLayoutManager(new LinearLayoutManager(this));
ViewGroup.LayoutParams layoutParams = rv.getLayoutParams();
layoutParams.height=100;
rv.setLayoutParams(layoutParams);
You may need to calculate the RV's height by childcount*childheight to get pricise value. And don't forget to compare the height to the Parent Layout height, make sure RV's height is less than its Parent Layout height.
Here is my Layout
<RelativeLayout...>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv"
android:layout_centerInParent="true"
android:layout_width="match_parent"
<-height will be changed in code, ignore the 50dp->
android:layout_height="50dp">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>

ScrollView.getChildAt(0).getHeight() can't get the right value

I have a ScrollView which child's height is 500px,this contain 2
button and the sum of height of them is 500px.but the value of
child.getHeight() is 788 not 500 I know ScrollView extends Framelayout,i replace the ScrollView with Framelayout in the same scene and the value of child.getHeight() is 500.
Why is this happen?
As per my knowledge and what i found on serch is, when you use scroll view the scroll view adds some padding inside its child elements for its comfort. but in case framelayout this not happens so you are getting these different values for scrollview and framelayout. as you can see android:margin not works for scrollview but works for framelayout. you can see these two examples for understanding-
margin issue
difference between padding and margin

Android: RemoveAllItems from view doesn't refresh size

I have a ScrollView that contains a LinearLayout.
In code I add items to the LinearLayout and it nicely expands.
When I remove, in code, all the items from the LinearLayout, the LinearLayout stays the same size, it's empty though.
How do I get the ScrollView to reclaim the height that the LinearLayout used when it had items and shrink back the LinearLayout to use the least height as it is now empty?
I have tried (in C#):
linearLayout.RemoveAllViewsInLayout();
linearLayout.PostInvalidate();
scrollView.PostInvalidate();
Java or C# answers are fine.
I only have Java experience with Android, so I would try using:
linearLayout.requestLayout();
This should cause another layout pass, and assuming your LinearLayout is set to WRAP_CONTENT it will measure all the children and size itself to fit the smallest space that the children occupy (or minHeight if you have that set and it is larger).
This trick seems to work. The result is that the linearlayout ids resized and the scrollview as well:
linearLayout.RemoveAllViewsInLayout();
linearLayout.Visibility = ViewStates.Gone;
scrollView.SmoothScrollTo(0, 0);
linearLayout.Visibility = ViewStates.Visible;
There must be a better way, but this works.

Force GridView to only a single row?

Is there a way to force GridView to only be a single row? Right now by default it will extend its height to accommodate all views supplied by its adapter
You Should combine a horizontal SCROLLVIEW and a LINEARLAYOUT and a GRIDVIEW to achieve what you want!
put grid view in linearlayout and put the linear layout in the horizontal scroll view;
then when setting adapter! count the number of data!
after that you should calculate the desired width to show all your items!
for example you want to show 8 item! each width is 100dp . so the desired width would be 800dp!
then you should add these lines of code
yourGridView.setNumColumns(8);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(800, ViewGroup.LayoutParams.MATCH_PARENT);
yourGridView.setLayoutParams(lp);
dnt forget to set the width of the linear layout as WRAP_CONTENT in the xml!
*** IMPORTANT NOTE
as i know, by doing this, gridview can't garbage collection because Scroll View doesn't support such a thing and your grid view nested in it!
so dnt use this method for lots of images or you will get HEAP SIZE error!

Categories

Resources