Giter Club home page Giter Club logo

stickyheaders's Introduction

StickyHeaders

Adapter and LayoutManager for Android RecyclerView which enables sticky header positioning.


Download

minSdkVersion: 14

compile 'org.zakariya.stickyheaders:stickyheaders:0.7.10'

StickyHeaders are section headers in a RecyclerView which are positioned "stickily" to the top of the scrollview during scrolling. A common use-case is an address book where the list of people's last names are grouped into sections by the first letter of the last name, and the header for each section shows that letter.

For example:

AddressBookSample

StickyHeaders also supports a callback (org.zakariya.stickyheaders.StickyHeaderLayoutManager.HeaderPositionChangedCallback) when a header becomes "sticky" or returns to normal positioning. For example, it is used here to set the elevation on the header to cast a subtle drop shadow when the header is in sticky position.

For example:

CallbacksSample

Usage

To use StickyHeaders, you need to do two things.

  1. Implement an adapter by subclassing org.zakariya.stickyheaders.SectioningAdapter
  2. Assign a org.zakariya.stickyheaders.StickyHeaderLayoutManager to your recyclerview.
  3. When handling modifications to your dataset, never call the RecyclerView.Adapter::notify* methods, instead, call the corresponding methods in org.zakariya.stickyheaders.SectioningAdapter::notifySection*. The reason for this is SectioningAdapter maintains internal state, and the notifySection* methods are tailored for adding and removing sections, adding and removing items from sections, etc.

Notes

  1. StickyHeaders uses androidx.recyclerview.*
  2. You can use sectioning adapter with a normal androidx.recyclerview.widget.LinearLayoutManager. it works fine, and could be a good way to implement a list like at the root of Android's Settings app.

stickyheaders's People

Contributors

amgadserry avatar braisgabin avatar clzola avatar jcyuyi avatar mmangliers avatar patloew avatar shamylzakariya avatar ziem avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stickyheaders's Issues

Header Position

Hi first of all thanks for nice library, Is there a way to show header at the end of each section?

notifySectionFooterRemoved wrong index logic

At the end of the method notifySectionFooterRemoved you have such piece of code:

notifyItemRemoved(section.adapterPosition + section.length - 1);

Suppose i have 24 items in my section, one header and one footer (total item count -27),. I want to remove my footer So after my call notifySectionFooterRemoved buildSectionIndex() will assign to section.length = 26 (24 (items)+ 2(header and ghost header)).

So notifyItemRemoved(25) called - and thats wrong, should be notifyItemRemoved(26)

Calling notifyAllSectionsDataSetChanged does not work as expected

When refreshing a data set, the suggested method call is notifyAllSectionsDataSetChanged().

I would imagine this to clear all collapsed states, ensuring that each section is no longer collapsed. This is not the case, as can be seen in the example app's 'Collapsing Headers' demo. Try collapsing a section, then hit 'Reload' from the menu. The header view's state is restored to appear not collapsed, but the items remain hidden.

I believe this is due to the ordering of method calls:

public void notifyAllSectionsDataSetChanged() {
    buildSectionIndex();
    notifyDataSetChanged();
    collapsedSections.clear();
    selectionStateBySection.clear();
}

should rather be:

public void notifyAllSectionsDataSetChanged() {
    collapsedSections.clear();
    selectionStateBySection.clear();
    buildSectionIndex();
    notifyDataSetChanged();
}

because buildSectionIndex() uses isSectionCollapsed(s) (which checks the collapsedSections map) to determine section length and numberOfItems.

I'm happy to make a PR, but thought I would just check to see if this is the intended behavior?

Manifest merge failed - application@label

The manifest merge task will fail when trying to set the application label if the project also set the label for the application.
Is the label really needed ? Couldn't find an easy way to avoid this as tools:replace does not seem to work.

Manifest merger failed : Attribute application@label value=(@string/APP_NAME) from AndroidManifest.xml:61:9-43
is also present at [org.zakariya.stickyheaders:stickyheaders:0.7.5] AndroidManifest.xml:12:9-41 value=(@string/app_name).
Suggestion: add 'tools:replace="android:label"' to element at AndroidManifest.xml:9:5-20:19 to override.

IndexOutOfBoundsException: onBindItemViewHolder

I found one issue

@Override
    public void onBindItemViewHolder(ItemViewHolder viewHolder, int sectionIndex, int itemIndex, int itemType) {
        int sectionPosition = includeHeader ? sectionIndex - 1 : sectionIndex;
        switch (itemType) {
            case ITEM_HEADER:
               ...
                break;
            case ITEM_TILE:
                initTile((FeedViewHolder) viewHolder, feedDataProviders.get(sectionPosition).getTileViewModelList().get(itemIndex), sectionPosition);
                break;
            case ITEM_FOOTER:
                ...
                break;
            default:
                break;
        }
    }

Where feedDataProviders is List<FeedDataProvider>. FeedDataProvider has list of custom objects TileViewModel.

I got IndexOutOfBoundsException: Invalid index 0, size is 0 in line initTile() because getTileViewModelList() return empty list and itemIndex is 0. I think if getNumberOfItemsInSection return 0 then is should not called the onBindItemViewHolder right?

@Override
    public int getNumberOfItemsInSection(int sectionIndex) {
        if((includeHeader && sectionIndex == 0) || (includeFooter && sectionIndex == getNumberOfSections() - 1)) {
            return 1;
        }
        return feedDataProviders.get(includeHeader ? sectionIndex - 1 : sectionIndex).getTileViewModelList().size();
    }

Error: "Scrapped or attached views may not be recycled" with LinearLayoutManager

Hi, I need to use the LinearLayoutManager instead of StickyHeaderLayoutManager. But while using the LinearLayoutManager it's constantly crashing with the following error message:

E/AndroidRuntime: FATAL EXCEPTION: main java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true at android.support.v7.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:5659) at android.support.v7.widget.RecyclerView$Recycler.recycleView(RecyclerView.java:5603) at android.support.v7.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:277) at android.support.v7.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:324) at android.support.v7.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:337) at android.support.v7.widget.GapWorker.prefetch(GapWorker.java:344) at android.support.v7.widget.GapWorker.run(GapWorker.java:370) 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:6126) 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)

How can I fix this issue? Thank you very much in advance! :)

Delete all selection Failed.

when I use toggleSectionSelected(index) method select all the selection.

use traverseSelection() to delete the select, use notifySectionRemoved(index) refresh data, but this no work. only delete one section once.

I find you code in SectioningAdapter-->notifySectionRemoved() --> notifyAllSectionsDataSetChanged() --> selectionStateBySection.clear();

I guess the problem here.

Can't Save after Detach

Because we remove the adapter on detach, we can't save after the view is detached (another library I'm using performs the save there, so it's not ideal for me).

A tweak which shouldn't adversely affect anything would be to updateFirstAdapterPosition() in onDetachedFromWindow before removing the adapter, and then we can wrap the call to update in onSaveInstanceState to only occur if the adapter is not null.

When use with SwipeRefreshLayout, cannot swipe to refresh

when i use this layout
`<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/top_line"
android:background="@color/gray_background">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_study_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</android.support.v4.widget.SwipeRefreshLayout>`

i can not swipe to refresh.

Null object reference SectioningAdapter.getItemViewType(int)

Hi , i am using your lib to sticky header , i have an Tab layout with 2 fragments and when i try to get data from database in background and try to set adpater in the fragment onCreateView() method , i am getting

java.lang.NullPointerException: Attempt to invoke virtual method 'int org.zakariya.stickyheaders.SectioningAdapter.getItemViewType(int)' on a null object reference

Process: competent.groove.swalok, PID: 28820
java.lang.NullPointerException: Attempt to invoke virtual method 'int org.zakariya.stickyheaders.SectioningAdapter.getItemViewType(int)' on a null object reference
at org.zakariya.stickyheaders.StickyHeaderLayoutManager.getViewType(StickyHeaderLayoutManager.java:707)
at org.zakariya.stickyheaders.StickyHeaderLayoutManager.onLayoutChildren(StickyHeaderLayoutManager.java:183)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3028)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2906)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3283)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1695)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:122)
at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1170)
at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:814)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
at android.view.View.layout(View.java:15671)
at android.view.ViewGroup.layout(ViewGroup.java:5038)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)

in my fragment

public class GetStartedFragment extends Fragment{

RecyclerView recyclerView;
PersonalAdapter adapter;

DatabaseHelper db;
Database_Result db_insert;
ProgressDialog pd ;
SharedPreferences pref;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.personal_recyclerview, container, false);

    recyclerView = (RecyclerView) view.findViewById(R.id.personal_recycler);

    db = new DatabaseHelper(getActivity());
    db_insert = new Database_Result(getActivity());

    pref = PreferenceManager.getDefaultSharedPreferences(getActivity());

    adapter = new PersonalAdapter(getActivity());

    try {
        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();

                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        pd = ProgressDialog.show(getActivity(), "", "Loading messages...", true);
                        pd.setCancelable(false);
                        pd.setCanceledOnTouchOutside(false);
                        //bar.setVisibility(View.VISIBLE);
                    }
                });

                if(db_insert.isTableExists(DatabaseHelper.CALL_TABLE) == false){
                    boolean table = db_insert.Create_CALL_TABLE();
                    Log.e("-----isTableExists Create_CALL_TABLE-----", "="+table);
                }

                final List<Sms> lstSms = getAllSms();

                Log.e("==Personal Fragment=lstSms.size=====", "" + lstSms.size());

                db_insert.Update_DB_FLAG();

                db_insert.ADD_SMS_DATA(lstSms);

                try {
                    db_insert.Insert_CALLOG_DATA(Call_LogUtils.logCallLog(getActivity()));
                } catch (Exception e) {
                    e.printStackTrace();
                }



                    final List<Sms> SmsList = db_insert.getAllSMSList();
                    Log.e("=2==Personal=getAllSMSList===", "" + SmsList.size());


                adapter.setSMS(SmsList);

                Log.e("==setSMS==getAllSMSList===", "" + SmsList.size());

                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            recyclerView.setLayoutManager(new StickyHeaderLayoutManager());

                            recyclerView.setAdapter(adapter);

                            pd.dismiss();

                        }
                    });

            }
        };
        thread.start();
    } catch (Exception e) {
        e.printStackTrace();
        //bar.setVisibility(View.GONE);
        pd.dismiss();
    }


    return view;
}

Many sections cause "...too much work on its main thread"

Hi,

I'm developing an app where I use your library to show list of speficic documents. There are around 35 sections with 3 items in each of them. On HTC10 everything is fine, but on older phones such as Nexus 5, view is really choppy and I can see in console: Skipped 703 frames! The application may be doing too much work on its main thread. - almost all the time. When I sort the list to 5 sections with 15 items there is no such problem so I guess the problem is linked to too much section headers in one list.

Is there any way around it?

Need Tutorial

Hello Zak, I really like your project and I'm interested in using it in a beautiful app am building. Anyway, I would like to request for a tutorial to be made on such a nice project. Finding it difficult to implement.

Thanks
Regards

Sliding Caton

hello.I just do like this:
in stickyHeaderLayoutManager.setHeaderPositionChangedCallback(...(){

//do left recyclerView smoothScrollToPosition(sectionIndex);
cause to Rv StickyHeader Sliding Caton.

})
can you tell me why?

Add notifySectionHeader*

We have the notifySectionFooterInserted, notifySectionFooterRemoved and notifySectionFooterChanged.

But we don't have notifySectionHeaderInserted, notifySectionHeaderRemoved and notifySectionHeaderChanged. Add them would be usefull.

Wrong ItemViewHolder.getPositionInSection() value

Since ItemViewHoldersetPositionInSection(positionInSection) is only called in onBindViewHolder the method ItemViewHolder.getPositionInSection() returns wrong value when new items were inserted and SectionAdapter.notifySectionItemInserted was called.

PagedLoadScrollListener issue

Hi,

I added PagedLoadScrollListener after setting adapter to recyclerview to adapter.
Its works properly. But sometimes it does not work. I have to add PagedLoadScrollListener method after setting data to adapter.

Can you explain me why it works that way???

How to get properly getItemId

Hello

I have List object of FeedProvider one feedprovider included List of ViewModels. I want to get hashcode of one viewmodel object.

@Override
    public long getItemId(int position) {
        int sectionPostion = getSectionForAdapterPosition(position);

        int positionItem = getPositionOfItemInSection(sectionPostion, position);
        return feedDataProviders.get(sectionPostion - 1).getTileViewModelList().get(positionItem).hashCode();
    }

But I got IndexOutOfBoundsException. What I am doing wrong?

2 columns or more of Items

How can i say that in 1 section, the item will be displayed in 2 columns with the StickyHeaderLayoutManager ?

thanks in advance

different view types

hi,
is it possible to implement different types of view for item row ?
i tried to do so according to the adapter functions but i found it not really possible.
if there is a way please share
thank you for your time !

Edge fading not working..

Edge fading not working.. of RecyclerView
When set StickyHeaderLayoutManager as LayoutManager of RecyclerView


          <android.support.v7.widget.RecyclerView
		android:id="@+id/recyclerView"
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:requiresFadingEdge="vertical"
                android:fadingEdgeLength="50dp"
		app:layout_behavior="@string/appbar_scrolling_view_behavior"
		/>

Add payloads

it's mentionned in the documentation tahat we should avoid th use of notifyItemChanged();
But the problem is there is no method in the library that allows us to pass the payloads

public final void notifyItemChanged(int position, Object payload)

May I ask why this error occurred?

First of all thanks for this lib, it's great!

I don't know why this error occurs.
i just click on the item very quickly.

java.lang.NullPointerException at org.zakariya.stickyheaders.StickyHeaderLayoutManager.getViewViewHolder(StickyHeaderLayoutManager.java:599) at org.zakariya.stickyheaders.StickyHeaderLayoutManager.getViewAdapterPosition(StickyHeaderLayoutManager.java:603) at org.zakariya.stickyheaders.StickyHeaderLayoutManager.getBottommostChildView(StickyHeaderLayoutManager.java:447) at org.zakariya.stickyheaders.StickyHeaderLayoutManager.scrollVerticallyBy(StickyHeaderLayoutManager.java:274) at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1529) at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2486) at android.view.View.dispatchTouchEvent(View.java:7758) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2224) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2230) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1973) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2071) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1518) at android.app.Activity.dispatchTouchEvent(Activity.java:2531) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:60)

Thanks in advance

ScrollToPosition Issue

I added StickyheaderLayoutManager. It works well. But when I use scrollToPosition(int position) of this layout manager, it doesn't work well. How should I use scrollToPosition function?
What is position on recycler view of stickyheaders.

Margin properties on Items in StickyHeaderLayoutManager

Hey,
I'm using a RecyclerView which contains CardViews and want to have StickyHeaders.

When using a LinearLayout in my RecyclerView, I can't get a Sticky Header only a header separating the cards (it's already a huge improvement actually). I'm guessing that this is correct behaviour with this layout.

But when using the provided layout it seems like the margin properties on my card have no effect and takes the whole screen.
linear
sticky

Scrolling gets progressively slower the more sections there are

First of all thanks for this lib, it's great!

I'm running into some performance issues when there are a large number of sections, my use case is a list of events, each section is labeled with a date, and the items are events for that date.

It starts off smooth as butter, but the farther down the list you go the slower it gets. I profiled it and it looks like updateHeaderPositions takes more and more cycles the deeper down the list you go, to the point of being unusable at around the 500th section for my use case. I understand that number may vary depending on the implementation of the view holder methods, but nothing I'm doing is a long running blocking operation, I'm simply loading some data into a handful of views.

Is this a known issue with the library? If not, I am happy to provide my profiler .trace file if that would help

OnClick

Hello, is there any way to use onClickITem...?

use inside NestedScrollView

my xml layout is:
`<android.support.v4.widget.NestedScrollView
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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:fillViewport="true"
tools:showIn="@layout/fragment_product_details">

<LinearLayout
    android:id="@+id/content_product_details"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lay_product_name"
        app:cardElevation="1dp"
        app:cardCornerRadius="0dp"
        app:cardUseCompatPadding="false"
        app:cardPreventCornerOverlap="false"
        android:layout_marginBottom="2dp"
        app:contentPadding="2dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:gravity="center">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:gravity="center|left"
                    android:layout_weight="1">

                    <ImageButton
                        android:layout_width="35dp"
                        android:layout_height="35dp"
                        android:layout_margin="8dp"
                        android:id="@+id/btn_share"
                        style="@style/Widget.AppCompat.Button.Borderless"
                        android:tint="@color/textSecondary"
                        app:srcCompat="@drawable/ic_share" />

                    <ImageButton
                        android:layout_width="35dp"
                        android:layout_height="35dp"
                        android:layout_margin="8dp"
                        android:id="@+id/btn_favorite"
                        android:tint="@color/textSecondary"
                        style="@style/Widget.AppCompat.Button.Borderless"
                        app:srcCompat="@drawable/ic_favorite" />

                </LinearLayout>

                <com.iarcuschin.simpleratingbar.SimpleRatingBar
                    android:layout_width="wrap_content"
                    android:id="@+id/comment_rate"
                    app:srb_gravity="right"
                    app:srb_numberOfStars="5"
                    app:srb_stepSize="0.5"
                    app:srb_rating="0"
                    app:srb_starCornerRadius="0"
                    app:srb_starBorderWidth="1"
                    app:srb_borderColor="@color/divider_color"
                    app:srb_fillColor="@color/rate_fill_color"
                    android:layout_height="25dp" />

            </LinearLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                android:id="@+id/txt_product_name"
                android:textSize="18dp"
                android:layout_margin="8dp"
                android:gravity="right"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorSecondary"
                android:textSize="16sp"
                android:id="@+id/txt_product_eng_name"
                android:layout_margin="8dp"
                android:gravity="right"/>

        </LinearLayout>

    </android.support.v7.widget.CardView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/title_btn_compare"
            android:drawableLeft="@drawable/ic_compare"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:drawablePadding="10dp"
            android:drawableTint="@color/textSecondary"
            android:textColor="@color/textPrimary"
            android:textSize="18sp"
            android:id="@+id/btn_compare"
            android:background="@drawable/btn_white_background"
            android:layout_margin="8dp"/>

        <Button
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/title_btn_product_comments"
            android:drawableLeft="@drawable/ic_user_comments"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:drawablePadding="10dp"
            android:drawableTint="@color/textSecondary"
            android:textColor="@color/textPrimary"
            android:textSize="18sp"
            android:id="@+id/btn_comments"
            android:background="@drawable/btn_white_background"
            android:layout_margin="8dp"/>

    </LinearLayout>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/lay_product_property"
        app:cardElevation="1dp"
        app:cardCornerRadius="0dp"
        app:cardUseCompatPadding="true"
        app:cardPreventCornerOverlap="false"
        android:layout_marginBottom="2dp"
        app:contentPadding="2dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/colorAccent"
                android:id="@+id/txt_product_property"
                android:text="@string/title_card_properties"
                android:layout_margin="8dp"
                android:gravity="right"/>

                <android.support.v7.widget.RecyclerView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:clipToPadding="false"
                    android:id="@+id/rec_property"/>

        </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>

</android.support.v4.widget.NestedScrollView>`

when i run the app recyclerView push top layers up outside the screen. How fix it?

Null object reference

I am trying to set header for every item but getting crash.

Attempt to invoke virtual method 'int org.zakariya.stickyheaders.SectioningAdapter.getItemViewType(int)' on a null object reference at org.zakariya.stickyheaders.StickyHeaderLayoutManager.getViewType(StickyHeaderLayoutManager.java:590)
public class AdapterTimeline extends SectioningAdapter {

    public ArrayList<Video> results;
    private LeadActionView.onClickListener listener;

    public AdapterTimeline(ArrayList<Video> results) {
        this.results = results;
    }

    @Override
    public ItemViewHolder onCreateItemViewHolder(ViewGroup parent) {
        return new ItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view, parent, false), parent.getContext(), listener);
    }

    @Override
    public HeaderViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
        return new HeaderHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.header_view_timeline, parent, false), parent.getContext());
    }

    @Override
    public void onBindHeaderViewHolder(HeaderViewHolder holder, int position) {
        super.onBindHeaderViewHolder(holder, position);
        if (results.size() == 0)
            return;
        Video item = results.get(position);
        HeaderHolder vh = (HeaderHolder) holder;
        vh.itemContainerView.setTag(item);
        vh.profileImage.setTag(item.owner.uuid);
        GlideLoader(vh.profileImage, item.owner.avatar_url_small);
        vh.username.setText(item.owner.username);
        vh.date.setText(DateUtils.parse(item.created_at, item.publish_date));
    }

    @Override
    public void onBindItemViewHolder(ItemViewHolder holder, int sectionIndex, int position) {
        super.onBindItemViewHolder(holder, sectionIndex, position);
        if (results.size() == 0)
            return;
        Video item = results.get(position);
        final ItemHolder vh = (ItemHolder) holder;
        GlideLoader(vh.placeHolder, item.thumbnail_small_url);
        vh.actionView.setItem(item, position);
        vh.explain.setText(item.description);
        vh.placeHolder.setTag(item.video_url);
        if (item.video_url == null)
            vh.imageNotYet.setVisibility(View.VISIBLE);
        else
            vh.imageNotYet.setVisibility(View.GONE);
        vh.placeHolder.setVisibility(View.VISIBLE);
        vh.scalableView.setVisibility(View.GONE);
        vh.setItem(item);
        HashTagHelper.Creator.create(vh.getContext().getResources().getColor(android.R.color.black), new HashTagHelper.OnHashTagClickListener() {
            @Override
            public void onHashTagClicked(String hashTag) {
                vh.getContext().startActivity(new Intent(vh.getContext(), ActivityHashTag.class).putExtra(Common.HASH_TAG, hashTag));
            }
        }).handle(vh.explain);
    }

    @Override
    public int getNumberOfSections() {
        return (null != results ? results.size() : 0);
    }

    @Override
    public int getNumberOfItemsInSection(int sectionIndex) {
        return 1;
    }

    @Override
    public boolean doesSectionHaveHeader(int sectionIndex) {
        return true;
    }

    @Override
    public boolean doesSectionHaveFooter(int sectionIndex) {
        return false;
    }

    @Override
    public void onViewAttachedToWindow(ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
//        ItemHolder itemHolder = (ItemHolder) holder;
//        itemHolder.scalableView.finish();
    }

    public class HeaderHolder extends SectioningAdapter.HeaderViewHolder implements View.OnClickListener {

        final Context context;
        LeadTextView date;
        CircleImageView profileImage;
        LeadTextView username;
        LinearLayout itemContainerView;

        public HeaderHolder(View itemView, Context context) {
            super(itemView);
            this.context = context;
            itemContainerView = (LinearLayout) itemView.findViewById(R.id.item_view_container);
            profileImage = (CircleImageView) itemView.findViewById(R.id.profile_image_timeline);
            profileImage.setOnClickListener(this);
            username = (LeadTextView) itemView.findViewById(R.id.user_name);
            date = (LeadTextView) itemView.findViewById(R.id.post_date);
        }

        public Context getContext() {
            return context;
        }

        @Override
        public void onClick(View v) {
            context.startActivity(new Intent(context, ActivityProfile.class).putExtra(ActivityProfile.PROFILE_UUID, ((String) v.getTag())));
        }
    }

    public class ItemHolder extends SectioningAdapter.ItemViewHolder implements View.OnClickListener {

        final Context context;
        LeadActionView actionView;
        SquareImageView placeHolder;
        LeadTextView explain;
        ScalableView scalableView;
        ImageView mediaPlayer;
        AnimationSet animationSet;
        CircleImageView imageNotYet;
        private Video item;

        public ItemHolder(View itemView, Context context, LeadActionView.onClickListener listener) {
            super(itemView);
            this.context = context;
            scalableView = (ScalableView) itemView.findViewById(R.id.scalableVideoView);
            actionView = (LeadActionView) itemView.findViewById(R.id.actionView);
            actionView.setOnClickListener(listener);
            placeHolder = (SquareImageView) itemView.findViewById(R.id.place_holder);
            imageNotYet = (CircleImageView) itemView.findViewById(R.id.image_not_yet);
            placeHolder.setMaxHeight(itemView.getWidth());
            placeHolder.setOnClickListener(this);
            scalableView.setOnClickListener(this);
            explain = (LeadTextView) itemView.findViewById(R.id.explain);
            mediaPlayer = (ImageView) itemView.findViewById(R.id.button_media_player);
        }

        public Context getContext() {
            return context;
        }

        @Override
        public void onClick(View v) {
            if (!scalableView.isPrepared() && item.video_url != null) {
                animationSet = startAnimation(mediaPlayer);
                scalableView.prepareAsync(item, new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        scalableView.setPrepared(true);
                        if (animationSet != null)
                            animationSet.cancel();
                        scalableView.post(new Runnable() {
                            @Override
                            public void run() {
                                scalableView.setVisibility(View.VISIBLE);
                            }
                        });
                        mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                            @Override
                            public void onCompletion(MediaPlayer mp) {
                                placeHolder.setVisibility(View.VISIBLE);
                                scalableView.setVisibility(View.GONE);
                                scalableView.finish();
                            }
                        });
                        scalableView.start();
                        placeHolder.setVisibility(View.GONE);
                    }
                });
            } else if (scalableView.isPlaying()) {
                scalableView.pause();
            } else if (scalableView.isPaused())
                scalableView.start();

        }

        private AnimationSet startAnimation(ImageView mediaPlayer) {
            Animation fadeIn = new AlphaAnimation(0, 1);
            fadeIn.setInterpolator(new DecelerateInterpolator());
            fadeIn.setDuration(900);

            Animation fadeOut = new AlphaAnimation(1, 0);
            fadeOut.setInterpolator(new AccelerateInterpolator());
            fadeOut.setStartOffset(1000);
            fadeOut.setDuration(900);

            AnimationSet animation = new AnimationSet(false);
            animation.addAnimation(fadeIn);
            animation.addAnimation(fadeOut);
            mediaPlayer.setAnimation(animation);
            mediaPlayer.startAnimation(animation);
            return animation;
        }

        public void setItem(Video item) {
            this.item = item;
        }

        public Video getItem() {
            return item;
        }

    }


    public void setListener(LeadActionView.onClickListener listener) {
        this.listener = listener;
    }

    private void GlideLoader(final ImageView targetImageView, final String url) {
        Glide.with(targetImageView.getContext())
                .load(url)
                .dontAnimate().into(targetImageView);
    }

}
        mAdapter = new AdapterTimeline(results);
        mAdapter.setListener(this);
        mLayoutManager = new StickyHeaderLayoutManager();
        mRecyclerView.setLayoutManager(mLayoutManager);
        mLayoutManager.setHeaderPositionChangedCallback(new StickyHeaderLayoutManager.HeaderPositionChangedCallback() {
            @Override
            public void onHeaderPositionChanged(int sectionIndex, View header, StickyHeaderLayoutManager.HeaderPosition oldPosition, StickyHeaderLayoutManager.HeaderPosition newPosition) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    boolean elevated = newPosition == StickyHeaderLayoutManager.HeaderPosition.STICKY;
                    header.setElevation(elevated ? 8 : 0);
                }
            }
        });
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mAdapter);

Scroll to position not working in your adapter.

When i want to scroll to a specific item in recyclerview with for example: mRecyclerview.scrollToPosition(20), the adapter list will not move, but start normally by the first item.
It also happens when i call scroll to position from your StickyLayoutManager.

Is there an way i can fix this issue?

Thanks in advance,

Yilzer

Get current visible item on screen

Hi, is there a way to find out which item (that is not a section header) is currently being displayed on the screen?

Thanks in advance

how to use animation?

Hi
I use this lib to animate recyclerview : https://github.com/wasabeef/recyclerview-animators
but when i use SectioningAdapter i get this cast error :

Caused by: java.lang.ClassCastException: StickyHeaderLayoutManager must be used with a RecyclerView where the adapter is a kind of SectioningAdapter at org.zakariya.stickyheaders.StickyHeaderLayoutManager.onAdapterChanged(StickyHeaderLayoutManager.java:103) at android.support.v7.widget.RecyclerView.setAdapterInternal(RecyclerView.java:920) at android.support.v7.widget.RecyclerView.setAdapter(RecyclerView.java:877) at com.farahefaz.app.activities.SpecActivity.onCreate(SpecActivity.java:98) at android.app.Activity.performCreate(Activity.java:6285) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2417) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2524)  at android.app.ActivityThread.access$900(ActivityThread.java:154)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1391)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:234)  at android.app.ActivityThread.main(ActivityThread.java:5526)  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) 

is there any other way to animate this StickyHeaders?
thanks in advance...

animateLayoutChanges -> exception

java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true
at android.support.v7.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:5420)
at android.support.v7.widget.RecyclerView$Recycler.recycleView(RecyclerView.java:5364)
at android.support.v7.widget.RecyclerView$LayoutManager.removeAndRecycleView(RecyclerView.java:7698)
at org.zakariya.stickyheaders.StickyHeaderLayoutManager.recycleViewsOutOfBounds(StickyHeaderLayoutManager.java:624)
at org.zakariya.stickyheaders.StickyHeaderLayoutManager.scrollVerticallyBy(StickyHeaderLayoutManager.java:435)
at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1640)
at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2759)
at android.view.View.dispatchTouchEvent(View.java:10023)

Possible inclusion in FlexibleAdapter

Hello @ShamylZakariya,
I was wondering if your LayoutManager could be included (and adapted) in my FlexibleAdapter library. Currently, I use a different solution to make headers sticky and clickable(!), it works fair enough, but it has some bugs due to different internal state of the default LayoutManagers especially when removing items.
Basically, I searched a way, since long time now, to create a custom LayoutManager, but never had time to work on it.
Adaptation is necessary to cover:

  • SmoothScroll for the expandable items.
  • Identification of headers based on my implementation (probably I will change again).

Let me know. Thanks,
Davide

Wrong animation

When we delete the last item, the animation is wrong, because all items move up, but they need to move down.

Collapsed Header overlaps with last item of previous section

With headers A, B, and C:

Collapse header B. Scroll up so that C is the sticky header. Scroll back down to section A; the last item in the section now overlaps with header B.

Looks to be an issue with the layoutmanager class; I'll do some digging.

How to modify dataset?

First of all thanks for this lib, it's great!

I call the notifySectionItemChanged(sectionIndex, itemIndex) method.

But had a problem is
java.lang.IllegalArgumentException: view is not a child, cannot hide android.widget.LinearLayout{21e33088 V.E...CL ......I. 0,612-600,683}
java.lang.IllegalArgumentException: Tmp detached view should be removed from RecyclerView before it can be recycled

Thanks in advance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.