lisawray / groupie Goto Github PK
View Code? Open in Web Editor NEWGroupie helps you display and manage complex RecyclerView layouts.
License: MIT License
Groupie helps you display and manage complex RecyclerView layouts.
License: MIT License
and possibly isEmpty
to Group ... although this could be confusing because it might not be clear if it indicated at the current moment itemCount == 0
or some logical state of emptiness
Otherwise we get stuff like:
override fun bind(binding: ItemBlockOverflowBinding?, position: Int)
which is not fun, and Kotlin should be fun!
Right now, the example app reorders an input list on creation.
But there's no reason it couldn't preserve the input list and use an algorithm to map the input list to adapter outputs, given a constant column span size and total span count.
the example references for example
import com.genius.groupie.example.databinding.ItemSquareCardBinding;
but there is no databinding
folder…
Problem here is that I scroll the vertical RecyclerView from top to bottom again and again, the item decoration which is a customized space gap item decoration will get bigger height each time, the customized decoration's code are below:
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) {
outRect.bottom = mVerticalSpaceHeight;
}
}
Seems groupie is more buggy in my code.
As per RecyclerView Animations and Behind the Scenes (Android Dev Summit 2015)
https://youtu.be/imsr8NrIAMs?t=36m2s you should check the ViewHolder's position before triggering an onItemClick that was pass in via GroupAdapter#setOnItemClickListener()
onClick error
NestedGroup uses getPosition(Group)
to calculate a notification position when forwarding OnItem/Change/Inserted/Removed etc. For example:
public void onItemRangeChanged(Group group, int positionStart, int itemCount) {
if (parentDataObserver != null) {
parentDataObserver.onItemRangeChanged(this, getPosition(group) + positionStart, itemCount);
}
}
The implementation of getPosition(Group)
in Section and ExpandableGroup appear to just return the index of the group within the subclass. Adding the following test to SectionTest illustrates the problem:
@Test
public void addItemToNestedSectionNotifiesAtCorrectIndex() throws Exception {
final Section rootSection = new Section();
rootSection.setGroupDataObserver(groupAdapter);
groupAdapter.add(rootSection);
final Section nestedSection1 = new Section(Arrays.<Group>asList(new DummyItem(), new DummyItem(), new DummyItem()));
rootSection.add(nestedSection1);
final Section nestedSection2 = new Section();
rootSection.add(nestedSection2);
reset(groupAdapter);
nestedSection2.add(new DummyItem());
verify(groupAdapter).onItemInserted(rootSection, 3);
}
At first glance, it looks like there are two possible ways to fix this.
getPosition(Group)
.getPosition(Group)
to return the number of items prior to the passed in group.adapter.setOnItemClickListener(new OnItemClickListener() {
@OverRide public void onItemClick(Item item, View view) {
Toast.makeText(MainActivity.this, "down", Toast.LENGTH_SHORT).show();
}
});
onItemClickListener a error
When item onClick listeners are set up external to groupie it gets overwritten during groupie item binding even though an item click listener has not been set on the GroupAdapter. For example, I'm using data binding and setting the onClick listener in XML and it gets disabled by groupie.
Hi,
thanks for that awesome library! I struggle a bit to find the best way to hide/show entire groups.
A have a view that shows two different sets of items depending on the view state. So I created two groups and want to show/hide them. Any suggestions?
If you're lucky, your design has Groups that can be creatively decomposed into Items using a GridLayout.
But what if you have a huge Group where there's no getting around rendering it as a single, huge Item? Your choices are to write a custom LayoutManager (no one wants to do that) or render it as one huge ViewHolder / Item, causing poor performance.
Could we compose Items inside a single FrankenItem ... by pulling normal Items from the RecyclerView pool and returning them when we're done?
The call to notifyItemRangeRemoved
inside Section.remove
uses position calculated from getPosition
. If I understand the code correctly, it should instead use getItemCountBeforeGroup
in order to take into account the nested items inside the groups. Was this perhaps missed in 45987d7? If so, I'd be happy to send you a pull request.
Causes conflicts with projects when groupie's build tools are > project build tools
Null's make my head hurt. How do you feel about making setHeader
@nonnull and adding removeHeader
.
The way the Item object is designed, it only has bind() methods. It does not seem there are methods expose for cleaning up the ViewHolder/Binding.
Example, if you have a chat recyclerview, you have a VideoViewItemBinding. User can click to play the VideoView, when user scroll it away, we do not receive any callback to stop() or release any resources.
In order to decorate groups easily, a viewholder should be able to answer questions like
"Do you belong to group X?"
and
"What position are you in group X?"
therefore
getGroupPosition()
isn't sufficientcurrent thought:
when you add an Item to a Group, the Group tags this position & belonging information onto it (and updates it for every time the Group is rearranged)
Group:
String getGroupId()
ViewHolder:
int getGroupLayoutPosition(String groupId)
If it does not belong to the group, it would have NO_POSITION
.
problems:
If we set the view's group position to NO_POSITION
as soon as it's removed from the group and a notification is dispatched, then group position is similar to adapter position. This means it will cause jumping/ disappearing decorations while items are animated out on removal. What we want is more similar to layout position. However, a group doesn't have any knowledge of the adapter or layout manager.
Maybe there's a good time (when the view is well and truly removed from the whole RV) for the adapter or even LM to clear this data.
I have a Section
, a section header and a CarouselItem.
I want this section to hide when CarouselItem is empty and show when Carousel has items.
How do i setup this behavior?
// onCreate
Section section = new Section(new HeaderItem("Header"));
section.setHideWhenEmpty(true);
CarouselItem carousel = new CarouselItem();
section.add(carousel);
// after network response
carousel.addAll(cardItemList);
carousel.notifyChange(); // to trigger getItemCount()
I modify the CarouselItem to return 0 or 1 based on the carousel adapter.
public int getItemCount() {
return (adapter == null || adapter.getItemCount() == 0) ? 0 : 1;
}
Result: The Carousel is displayed but section header is still hidden.
Hello @lisawray ,
Thanks for nice library. I want to ask question that is it possible to return different layout for same model class?
My use case is :
I have to show products and it may with picture and without picture.
Is is possible now or is any feature request for it?
Thanks,
Bhavin
Expandable group is not smooth as how Epoxy handle expand and collapse which is so much smooth as compare to groupie is there is way achieved custom expand or collapse animation and how can i achieved the underline data model in Adapter like Epoxy which i found very flexible
It would be nice for a given Section to allow 3 different divider items:
I realize you could build 1 and 2 into the layouts for the header and footer, and that for 3, you could create a custom Item object and place it in between each content item, but it seems like it would be simplier to just say:
setHeaderDivider(Item item)
setFooterDivider(Item item)
setItemDivider(Item item)
Groupie makes a lot of requests to methods like getIndex(Item)
which internally iterate through all the children of a group. In practice, this is rarely problematic, but it could become an issue with very deeply nested groups and items at the end of extremely long lists.
Hi @lisawray
I tried today for the first time the example app and it keeps crashing on the newly added onClickListener code with this stacktrace:
java.lang.NullPointerException: Attempt to invoke interface method 'void com.genius.groupie.OnItemClickListener.onItemClick(com.genius.groupie.Item, android.view.View)' on a null object reference at com.genius.groupie.ViewHolder$1.onClick(ViewHolder.java:22)at android.view.View.performClick(View.java:5637)at android.view.View$PerformClick.run(View.java:22429)at android.os.Handler.handleCallback(Handler.java:751)at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Debugging show me that in this piece of code:
if (getAdapterPosition() != NO_POSITION) { onItemClickListener.onItemClick(getItem(), v); }
onItemClickListener it's always null. At first, I thoughts it was an error in the ViewHolder bind method but I'm not quite sure now.
Before writing this, I tried to find a duplicate issue in the list and it seems not present.Anyway, I could be wrong so...sorry, just in case :)
First of all thanks a lot for such a brilliant lib for RecyclerViews!
I will break my question into two parts.
1. Context
When using the RecyclerView Adapter as provided by Android Support library, we generally pass the 'Context' objects from Activities to the RVAdapter via RVAdapter constructor like below:
RVAdapter.java:
public class RVAdapter extends RecyclerView.Adapter{
private Context context;
private ImageHelper.CircleTransform
public RVAdapter(Context context,CircleTransform circleTransform){
this.context = context;
this.circleTransform = circleTransform;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RowHolder(inflater.inflate(R.layout.item_row,parent,false)) ;
}
//Here we use the context object passed via activity
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
RowHolder holder = (RowHolder) viewHolder;
Glide.with(context)
.load(TextHelper.formatUrl(<profie_url>))
.bitmapTransform(circleTransform)
.placeholder(R.drawable.ic_user_default)
.error(R.drawable.ic_user_default)
.into(holder.img);
}
}
Now, when using Groupie
this is how we create Row Item for that particular row:
RowItem.java
public class RowItem extends Item<RowItemBinding> {
String profile_url;
ImageHelper.CircleTransform circleTransform;
public SGroupsRowItem(String profile_url,ImageHelper.CircleTransform circleTransform){
this.profile_url = profile_url;
this.circleTransform = circleTransform;
}
@Override
public int getLayout() {
return R.layout.row_item;
}
@Override
public void bind(GroupieSgroupsItemRowItemBinding viewBinding, int position) {
Glide.with(viewBinding.getRoot().getContext())
.load(TextHelper.formatUrl(<profile_url>))
.bitmapTransform(circleTransform)
.placeholder(R.drawable.ic_user_default)
.error(R.drawable.ic_user_default)
.into(viewBinding.img);
}
}
As can be seen we need to call viewBinding.getRoot().getContext()
for every row item to get Context
object.Isn't that expensive operation for every row item?
OR
In another way what we could do is pass the Context
object in RowItem's constructor.
BUT again, we need to pass Context
every time we create that RowItem object like:
Section section = new Section();
section.add(new RowItem(profile_url,this));
section.add(new RowItem(profile_url,this));
What is the ideal way to do when dealing with Context
object inside Item class?
2. Objects created inside Activity
As can be seen in the above example ImageHelper.CircleTransform
object created inside Activity needs to be used inside RowItem
to apply bitmapTransform to the image.
In case of RvAdapter we can pass it one time using RVAdapter constructor.
But when using Groupie
I need to pass ImageHelper.CircleTransform
object every time i create
rowitem.
How do you deal with above scenarios of passing in objects one time from Activity ?
Thanks again! 👍
I want to have items drag part to sort items in RecyclerView, when user touching particular part(ImageView) of RecyclerView item
If you turn on debug drawing, then re-launch the settings controls, the switches both appear "off". You have to toggle them on, then off again to get them to turn off. They should initialize at the correct values from Prefs.
Delegate work from UpdatingCallback.getChangePayload
to currently non-existing oldItem.getChangePayload(newItem)
.
My problem is that I have three fragments in an Activity, they all contains a RecyclerView which contains two groups of RecyclerView, these RecyclerViews were data loaded and scroll to the bottom, but when I switch these three fragments, the second RecyclerView they contains will automatically scroll to the top while no add or other operation, and the first RecyclerView is not visible. Currently I have no idea why this happened, any help?
Is a grid layout manager supported. To order the groups as a grid?
W/RecyclerView: Cannot call this method in a scroll callback. Scroll callbacks might be run during a measure & layout pass where you cannot change the RecyclerView data. Any method call that might change the structure of the RecyclerView or the adapter contents should be postponed to the next frame.
java.lang.IllegalStateException:
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:2403)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeInserted(RecyclerView.java:4634)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeInserted(RecyclerView.java:10472)
at android.support.v7.widget.RecyclerView$Adapter.notifyItemInserted(RecyclerView.java:6214)
at com.genius.groupie.GroupAdapter.onItemInserted(GroupAdapter.java:204)
at com.genius.groupie.NestedGroup.notifyItemInserted(NestedGroup.java:195)
at com.genius.groupie.Section.notifyItemInserted(Section.java:205)
at com.genius.groupie.Section.add(Section.java:53)
at com.genius.groupie.example.MainActivity$1.onLoadMore(MainActivity.java:88)
at com.genius.groupie.example.InfiniteScrollListener.onScrolled(InfiniteScrollListener.java:41)
at android.support.v7.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:4305)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:4463)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
If not remove the unneeded one, add a few tests.
cc @Teovald , thanks for bringing my attention to this question :)
Either to support them, or throw an Exception and say they're not supported. In the latter case, we should consider whether it should really extend NestedGroup.
I am displaying lot of product items in recyclerview . Every product will have banner and items. so i have decided to use Recyclerview as Vertical(for banner) and Recyclerview as horizontal(product items)
When i scroll down the vertical recyclerview . it gets struck a bit but if scroll up there is no struck
and if all the banners and items loaded once. then no struck at all. why recyclerview gets strcuk at
first time? . for you reference below i have attached the screenshot
You can see because items below the group blink.
not just Lists
This better supports non-homogeneous groups of Items
This is useful on items like WebViews or ads (ugh)
Using an UpdatingGroup
as a child of an ExpandableGroup
seems to cause the following error:
E/UncaughtException: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{2fe4242 position=30 id=-1, oldPos=5, pLpos:5 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5046)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5177)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5158)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2061)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1445)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1408)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:580)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3330)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3186)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3632)
I noticed that UpdatingGroup
dispatches updates even though the ExpandableGroup
is collapsed, which is probably the issue. I've solved this by passing a boolean flag (dispatchUpdates
) to UpdatingGroup.update
which is set to true if the ExpandableGroup
is expanded. This seems to work, although there might be a better solution.
... because why not
Currently, the GroupAdapter class is badly tested. Turns out one test doesn't run at all bc it doesn't have the @test annotation .. but funny story, if it did, it would fail because it references an Android class!
addAll(position, groups)
and add(position, group)
are not correctly calculating the current number of items prior to the position where the new item(s) will be added.
add(group)
is only notifying for an item count of 1 even when a group with multiple items is added.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.