I am trying to create a Comments section to my app and am using a RecyclerView to display the comments. I would like to add a left margin to each RecyclerView item to show the "depth" that the comment is replying at. I have successfully added padding to each item viewholder using viewHolder.itemView.setPadding(depth *30, 0, 0, 0); but there is no equivalent setMargin function.
This is what I have now:
The red line is where I want to create a margin, for example.
I will need to calculate the margin dynamically as well.
You could change your item views to be a View within a FrameLayout (or similar), so that adding margin actually accomplishes something. But my recommendation would be to use a RecyclerView.ItemDecoration to apply offsets to each view.
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
Context context = view.getContext();
int indentation = context.getResources().getDimensionPixelSize(R.dimen.indentation);
RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
outRect.left = indentation * holder.getIndentationLevel();
}
This is assuming you have a dimen resource for a single level of indentation, and that your ViewHolder has the item's indentation level.
Related
The app I am working on contains lots of listviews. In one case, I have a recyclerView that leverages the GridLayoutManager to create a two column view. I haven't worked with recyclerViews yet as far as adapters go but here is the problem I am having. Each item in the view is being sized to the same height despite having the appropriate wrap_content attributes. I guess my question would be, is there a trick to pull this off where each child element has a different height? Is something going on behind the scenes with a recyclerView that causes all children to have a fixed height of the tallest child element? Does this sound like a recycler problem with the view holders?
My adapter logic is as follows
public ClubViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.onboard_club, parent, false);
return new ClubViewHolder(itemView, mRecyclerClickListener);
}
public void onBindViewHolder(final ClubViewHolder holder, int position) {
Item club = clubList.get(position);
if (null != club) {
holder.clubTitleText.setText(club.getName());
holder.subtitleText.setText(context.getResources().getString(R.string.club_members,club.getNumberMembers()+""));
// Do some imageView logic here
}
}
Do I need to set height in here programmatically?
EDIT: To clarify further, the layout I inflate is the layout in question here. It is a Vertical LinearLayout containing an imageView, and two text views. I need the LinearLayout to wrap the children XML attributes but it currently isn't doing that despite the LL having a height of wrap_content and all children height set to wrap_content as well
SOLUTION: Solution was posted by a user below. I will leave the update here for anyone struggling in the future.
Layout I need: Two columns whose children vary in height
Tie it in with an adapter as you normally would.
Set a StaggeredGridLayoutManager on the recyclerView widget
In the manager constructor pass in a spanCount of 2 and an Orientation of Vertical
Boom, close the sprint ticket and forget about it
Thanks again Stack Community, cheers!
The best way to control placement and size of item for RecyclerView is through its LayoutManager.
If you're looking for GridView with elements that resize themselves according to the content you can use StaggeredGridLayoutManager
Nice example of Staggered Grid Layout can be found here.
On the other hand if you need just few "groups" of different Items you can inflate different ViewHolders depending on some criteria. Here is the sample code for two types of views.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == FILE_FLAG) {
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
.inflate(R.layout.file_item, parent, false);
return new FileViewH(view);
} else if (viewType == DIR_FLAG) {
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
.inflate(R.layout.dir_item, parent, false);
return new DirViewH(view);
}
}
I am trying to create a chat application with RecyclerView for displaying the list of messages in chatBubble form.
In recyclerView, in each row layout I have two text views. One for displaying the message and other for displaying the timestamp. For short messages, it works. However, for long messages, the chat bubble grows too big and the corresponding TextView for displaying timestamp can't be seen in this case.
Why is this happening and how to correct this,
Also, the space between each item in RecyclerView needs to be increased, I tried using android:dividerHeight="12dp" but it didn't work.
As #Mohammed Atif commented, instead of using
android:layout_toRightOf="#+id/message
use this
android:layout_alignParentRight="true"
Now, for adding space between recyclerview's items, you need to add itemDecorator
public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int mVerticalSpaceHeight;
public VerticalSpaceItemDecoration(int mVerticalSpaceHeight) {
this.mVerticalSpaceHeight = mVerticalSpaceHeight;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
outRect.bottom = mVerticalSpaceHeight;
}
}
}
Then add this item decorator to recyclerview like this
recyclerview.addItemDecoration(new VerticalSpaceItemDecoration(2));
Here, 2 is the space between the recyclerview list items.
i am building an app on android and am using several recyclerviews.
in the first page that i used a recyclerview, everything worked flawlessly and my custom ItemDecoration (divider) was applied to all views.
then i started a new page in which i use the same divider on a similar RecyclerView, but on the last list item the bottom divider is not present.
seeing that it worked perfectly in one place, i don't believe the issue is with the custom ItemDecoration class, nor with the xml. I also tried using the same viewholder for the one that worked, but still the last divider was not drawn.
here is the code where is set up my adapter in the problematic recyclerview:
private void setUpPracticesList() {
lstPractices = (RecyclerView) getActivity().findViewById(R.id.lstPractices);
lstPractices.setLayoutManager(new LinearLayoutManager(getActivity()));
RecyclerView.Adapter<PracticeHolder> adapter = new RecyclerView.Adapter<PracticeHolder>() {
String[] titles = getResources().getStringArray(R.array.practices_names);
int[] imageIds = {R.drawable.consultation_meeting_icon,
R.drawable.monitoring_meeting_icon,
R.drawable.parent_lectures_icon,
R.drawable.parent_support_groups_icon,
R.drawable.staff_courses_icon};
#Override
public PracticeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.kidsense_practices_list_item, parent, false);
return new PracticeHolder(v);
}
#Override
public void onBindViewHolder(PracticeHolder holder, int position) {
holder.setName(titles[position]);
holder.setImage(imageIds[position]);
}
#Override
public int getItemCount() {
return titles.length;
}
};
lstPractices.setAdapter(adapter);
lstPractices.setHasFixedSize(true);
lstPractices.addItemDecoration(new DividerItemDecoration(getActivity(), null));
}
does anyone have any ideas?
I have found the solution:
what i have found is that a recyclerview will not show a divider at the bottom of the last view if there is no more space left in the recyclerview.
in my case, the problem was that my recyclerview was in a layout that had a height of "wrap_content", meaning that there was no extra space left under the recyclerview to display the divider. as soon as i rearranged my layout so that my recyclerview had more space underneath with a parent layout height of "match_parent" the final divider was displayed.
I have a problem with making negative margin for view of item which belongs to listview.
My items look like this:
I would like to lift second item and third and so on. The final effect should look like this
I tried with setTop method.
private class MyCustomAdapter extends ArrayAdapter<Integer> {
public MyCustomAdapter()
{
super(ListOfBeaconPlaces.this, R.layout.list_of_places_item_view, drawables);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View takenView = convertView;
if (takenView == null)
{
takenView = getLayoutInflater().inflate(R.layout.list_of_places_item_view, null, false);
}
final CuttedImageView cuttedImage = (CuttedImageView) takenView.findViewById(R.id.list_item_view);
cuttedImage.setImageResource(drawables.get(position));
if (cuttedImage.getHeightOfDrawnTransparentTriangle() != 0)
{
cuttedImage.setTop( (int)-cuttedImage.getHeightOfDrawnTransparentTriangle());
}
return takenView;
}
}
CuttedImageView is my custom class which inheriting from ImageView
Height of this triangle is knew after I first draw it on layout, but it's not a problem. I try to play with LayoutParameters, but it's also doesn't work for my.
Is there any posibility to make whole item margin negative?
I saw question, which talk about setting margin for item in linearlayout or relative layout or inside the item of listview, but I can't find nothing aboout changing margin of whole item.
In your xml file, in your listview set the divider height to a negative number to get an overlaping effect.
like this
android:dividerHeight="-10.0dp"
The following is part of my code for onBindViewHolder (inside MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
StatusItem item = mDataset.get(position);
//......
//Add content and timing to the textview
String content = item.getContent();
holder.mTextViewTime.setText(timing);
//Set the img
holder.imgViewIcon.setImageDrawable(item.getProfileDrawable());
//Set content image (for Instagram)
holder.mImageViewContentPic.setImageDrawable(item.getContentDrawable());
//HIDE THE VIEW Start
if(item.getContentDrawable() == null){
holder.mImageViewContentPic.setVisibility(View.GONE);
}
//HIDE THE VIEW End
}
The part HIDE THE VIEW is not working as expected.
When I am scrolling downwards, the views are working normally. However, when I start to scroll upwards, i.e. revisited the previous views, the ImageViews that are supposed to be VISIBLE becomes GONE, although I checked my dataset and verified that it has not been modified. Try calling other methods on the views also give erratic results(positions and items in dataset do not match).
It seems that the view holders are not binded to specific positions inside the RecyclerView.
The code works as expected if I remove the HIDE THE VIEW part.
Is there any way to solve this issue and dynamically hide views in my case?
Note: I used some AsyncTasks to update the dataset and call notifyDataSetChanged(), if that is relevant.
###This is the solution to your problem:###
holder.mImageViewContentPic.setVisibility(View.VISIBLE);
if(item.getContentDrawable() == null){
holder.mImageViewContentPic.setVisibility(View.GONE);
}
Because RecyclerView use recycle very well, ViewHolder A may be used to be ViewHolder B, so you need to specific every attribute of a ViewHolder in case of some attributes attach to a wrong object.