A modified version of Android's experimental StaggeredGridView. Includes own OnItemClickListener and OnItemLongClickListener, selector, and fixed position restore.

Overview

StaggeredGridView

Introduction

This is a modified version of Android's experimental StaggeredGridView. The StaggeredGridView allows the user to create a GridView with uneven rows similar to how Pinterest looks. Includes own OnItemClickListener and OnItemLongClickListener, selector, and fixed position restore.

Setup

To use StaggeredGridView in your projects, simply add this project to your workspace then add it as a library project to your current project.

Usage

StaggeredGridView can be added as a custom view to any layout.

Attributes supported (same behavior as GridView):

  • numColumns : determines the amount of columns to be drawn
  • drawSelectorOnTop : determine if selector should be drawn on top
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:staggered="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mainLayout">

    <com.origamilabs.library.views.StaggeredGridView
        android:id="@+id/staggeredGridView1"
        staggered:numColumns="2"
        staggered:drawSelectorOnTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

The StaggeredGridView includes its own interface's OnItemClickListener, and OnItemLongClickListener since StaggeredGridView does not extend an AdapterView. Behavior is the same.

onItemClick(StaggeredGridView parent, View view, int position, long id);

onItemLongClick(StaggeredGridView parent, View view, int position, long id);

Tests

No tests have been written however I have tested this View manually with 2.2.2+ devices. Please report any issues.

TODO:

  • implement more custom attributes to mirror GridView's attributes
  • develop tests
  • hideSelector()
  • support multiple choice mode
  • currently restoring position can result in the views to be slightly offset when user flings to the top. This is corrected by checking the offsets when position 0 is reached. Would like to dig deeper into the issue.
Comments
  • NullPointerExceptin

    NullPointerExceptin

    Hi,

    Sometimes getting this error, not sure what causes.

    java.lang.NullPointerException at android.os.Parcel.readIntArray(Parcel.java:678) com.test.example..StaggeredGridView$SavedState.(StaggeredGridView.java:2105) com.test.example.viewpager.StaggeredGridView$SavedState.(StaggeredGridView.java:2101) at com.test.example.viewpager.StaggeredGridView$SavedState$1.createFromParcel(StaggeredGridView.java:2129) at com.test.example.viewpager.StaggeredGridView$SavedState$1.createFromParcel(StaggeredGridView.java:1) at android.os.Parcel.readParcelable(Parcel.java:1919) at android.os.Parcel.readValue(Parcel.java:1784) at android.os.Parcel.readSparseArrayInternal(Parcel.java:2050) at android.os.Parcel.readSparseArray(Parcel.java:1506) at android.os.Parcel.readValue(Parcel.java:1841) at android.os.Parcel.readMapInternal(Parcel.java:2021) at android.os.Bundle.unparcel(Bundle.java:208) at android.os.Bundle.getSparseParcelableArray(Bundle.java:1167) at com.android.internal.policy.impl.PhoneWindow.restoreHierarchyState(PhoneWindow.java:1463) at android.app.Activity.onRestoreInstanceState(Activity.java:843) at android.app.Activity.performRestoreInstanceState(Activity.java:815) at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1096) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2641) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679) at android.app.ActivityThread.access$2300(ActivityThread.java:125) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:4627) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:521) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) at dalvik.system.NativeStart.main(Native Method)

    Btw, here is line 2105:

        private SavedState(Parcel in) {
            super(in);
            firstId = in.readLong();
            position = in.readInt();
            in.readIntArray(topOffsets);
            in.readTypedList(mapping, ColMap.CREATOR);  
        }
    
    opened by ogulcan 10
  • Position/column mappings: using HashSet instead of ArrayList for better performances - Some better handling of integer boxing

    Position/column mappings: using HashSet instead of ArrayList for better performances - Some better handling of integer boxing

    The class was using an ArrayList of ArrayList of Integers to simply map the column where an item was placed. This solution is overly complicated and poor in performances, especially when the adapter holds hundreds (or more) items: some of the operations (contains() and remove() in particular) called on the ArrayList(s) containing the positions for a single column in fillUp() and fillDown() have a O(n) complexity. That required traversing the array multiple times for each position, which is a very expensive operation in a cpu-bound context (= user scrolling or flinging the list).

    Since we don't need ordering in the columns mapping, I just replaced the internal ArrayList with an HashSet, whose complexity is O(1) for the same operations. We could have done even better with a HashMap<Integer, Integer> or a SparseIntArray but the performance optimizations are not enough to justify drastically modifying the save/restore state code for the purpose of my pull request (SparseIntArray is not even parcelable or serializable).

    I've also made a small optimization to avoid using multiple autoboxing for the same int value when iterating through the columns values.

    opened by marcosalis 7
  • NullPointerException when number of child Views decreases

    NullPointerException when number of child Views decreases

    hi guys,

    sorry in advance to @briangriffey for still being a noob who can't do pull requests.

    so basically, StaggeredGridView.layoutChildren() can trigger an NPE when it removes child Views because it iterates on the original number of child Views. the fix is super super simple and i don't have time to learn git so i'm posting it here with fingers crossed that one of the wonderful contributors will add it into the main branch.

    both changes are in StaggeredGridView.layoutChildren()

    first, we adjust the looping condition.
    final int childCount = getChildCount();
    int amountRemoved = 0;
    
    for (int i = 0; i < childCount; i++) {
        View child = getChildAt(i);
    

    becomes

    final int childCount = getChildCount();
    int amountRemoved = 0;
    
    for (int i = 0; i < childCount-amountRemoved; i++) {
        View child = getChildAt(i);
    
    second, we adjust the increment so we don't skip over new ith element.
    // child has been removed
    removeViewAt(i);
    if(i-1>=0) invalidateLayoutRecordsAfterPosition(i-1);
    amountRemoved++;
    continue;
    

    becomes

    // child has been removed
    removeViewAt(i);
    if(i-1>=0) invalidateLayoutRecordsAfterPosition(i-1);
    amountRemoved++;
    i--;
    continue;
    

    and that's it. hope this helps :)

    opened by accounts01 4
  • customize selection color

    customize selection color

    hi,

    thanks for this awesome view btw. i noticed there was no way of customizing the selection color so i added in this feature. unfortunately, i'm a total git and github noob and since the changes are super simple, i figured i'd post them here and cross my fingers they end up in the main source rather than learn to make pull requests.

    i added 2 lines: a. in res/values/attrs.xml, add this line with the other attribute declarations

    <attr name="selector" format="color|reference" />

    b. in src/.../StaggeredGridView.java, add this line inside the StaggeredGridView(Context context, AttributeSet attrs, int defStyle) constructor, alongside the other attribute parsings

    mSelector = a.getDrawable(R.styleable.StaggeredGridView_selector);

    that's it! sorry for being useless with git. hope you enjoy the new feature!

    opened by accounts01 4
  • Scrolling Back up does not work

    Scrolling Back up does not work

    I am able to scroll down but when I try to scroll up I am unable to.It just seems that the list ends there. I am facing this problem in android 4.2.2 both on emulator and actual device.

    opened by utopiadevelopers 4
  • setItemMargin() disables 'scrolling up'

    setItemMargin() disables 'scrolling up'

    It worked great until I started to make it look better with setitemMargin()

    The view won't scroll up once I set it. and it crashed as well.

    I tested on gallaxy s2 with 2.3.3

    opened by pcompassion 4
  • NullPointerException after back to foreground

    NullPointerException after back to foreground

    09-27 15:47:40.352: W/dalvikvm(21531): threadid=1: thread exiting with uncaught exception (group=0x41581700) 09-27 15:47:40.352: E/AndroidRuntime(21531): FATAL EXCEPTION: main 09-27 15:47:40.352: E/AndroidRuntime(21531): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.staggeredgridviewdemo/com.example.staggeredgridviewdemo.activities.MainActivity}: java.lang.NullPointerException 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread.access$600(ActivityThread.java:141) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Handler.dispatchMessage(Handler.java:99) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Looper.loop(Looper.java:137) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread.main(ActivityThread.java:5103) 09-27 15:47:40.352: E/AndroidRuntime(21531): at java.lang.reflect.Method.invokeNative(Native Method) 09-27 15:47:40.352: E/AndroidRuntime(21531): at java.lang.reflect.Method.invoke(Method.java:525) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 09-27 15:47:40.352: E/AndroidRuntime(21531): at dalvik.system.NativeStart.main(Native Method) 09-27 15:47:40.352: E/AndroidRuntime(21531): Caused by: java.lang.NullPointerException 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readIntArray(Parcel.java:784) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.origamilabs.library.views.StaggeredGridView$SavedState.(StaggeredGridView.java:2108) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.origamilabs.library.views.StaggeredGridView$SavedState.(StaggeredGridView.java:2104) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.origamilabs.library.views.StaggeredGridView$SavedState$1.createFromParcel(StaggeredGridView.java:2132) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.origamilabs.library.views.StaggeredGridView$SavedState$1.createFromParcel(StaggeredGridView.java:1) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readParcelable(Parcel.java:2062) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readValue(Parcel.java:1971) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readSparseArrayInternal(Parcel.java:2284) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readSparseArray(Parcel.java:1693) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readValue(Parcel.java:2028) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Parcel.readMapInternal(Parcel.java:2255) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Bundle.unparcel(Bundle.java:223) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.os.Bundle.getSparseParcelableArray(Bundle.java:1237) 09-27 15:47:40.352: E/AndroidRuntime(21531): at com.android.internal.policy.impl.PhoneWindow.restoreHierarchyState(PhoneWindow.java:1644) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.Activity.onRestoreInstanceState(Activity.java:938) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.Activity.performRestoreInstanceState(Activity.java:910) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1138) 09-27 15:47:40.352: E/AndroidRuntime(21531): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2189) 09-27 15:47:40.352: E/AndroidRuntime(21531): ... 11 more

    Thx!!!!

    opened by futer24 3
  • NullPointerException in onTouchEvent

    NullPointerException in onTouchEvent

    No idea how to repeat it. It occasionally happen.

    java.lang.NullPointerException
        at com.origamilabs.library.views.StaggeredGridView.onTouchEvent(SourceFile:545)
        at android.view.View.dispatchTouchEvent(View.java:7143)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2238)
    

    The line number may be slightly different at my local version. It refers to the "if" line and the NPE is caused by a null mAdapter in "mAdapter.isEnabled(motionPosition)". A patch is as follows:

    
        public boolean onTouchEvent(MotionEvent ev) {
                    /**
                     * PATCHED: mAdapter may cause NPE
                     */
                    if (!mDataChanged && mAdapter!=null && mAdapter.isEnabled(motionPosition)) { /** line 545 */
                        // TODO : handle
                        mTouchMode = TOUCH_MODE_TAP;
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                    }
    
    
    opened by mingfai 3
  • Crash when using different List Items in StaggeredGridView

    Crash when using different List Items in StaggeredGridView

    When using multiple List Item Type, the recycling view given back to your adapter is wrong type for the asked Type. So it crashes when your code tries to get the viewHolder

    It is similar to this issue http://stackoverflow.com/questions/16526291/listview-with-different-items-and-viewholders-leading-to-classcastexception

    When i debugged the code, i found that when offscreen views are added to scrapview List, it was giving wrong ViewType for that view

    private void recycleOffscreenViews() {

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
            System.out.println("######### recycleOffscreenViews child ######### "+child.getTag().getClass().getCanonicalName()+" : "+lp.viewType);
            mRecycler.addScrap(child);
    

    }

    I checked the viewType obtained from the child LayoutParams. It doesn't have the proper value for that view. It was always 0.

    So the problem is, in obtainView() function,

        final LayoutParams sglp = (LayoutParams) lp;
        sglp.position = position;
        sglp.viewType = positionViewType;
    
       // FIX. 
       view.setLayoutParams(sglp);
    

    The layoutParams is not set to the view. Which is why it is always 0 and while adding to ScrapView list.

    So after the setting the LayoutParams to the view before returning the view from obtainView() function, everthing works fine. I had tested with 6 different list items in StaggeredGridView. It handles the recycling of views properly.

    opened by smanikandan14 3
  • Stopped CheckForTap from laying out all children from the adapter

    Stopped CheckForTap from laying out all children from the adapter

    Every time i clicked on an item with the first item spanned, it would re-layout the children and after a few clicks it was 1 column. I saw no need for laying out the children during CheckForTap and everything now behaves correctly since applying this and the other PR's.

    opened by Ruxton 3
  • Binary XML file line #9 error

    Binary XML file line #9 error

    I try it many times but it give me errors...

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.staggeredgridviewdemo/com.example.staggeredgridviewdemo.MainActivity}: android.view.InflateException: Binary XML file line #9: Error inflating class com.origamilabs.library.views.StaggeredGridView

    Can you Please send me 1 full source code example with library ? If possible then Please mail me:[email protected]

    opened by bkothari99 3
  • setOnItemLongClickListener not work's :/

    setOnItemLongClickListener not work's :/

    Hey guys :)

    Someone know why this event not works?

    I don't see the Log and the Dialog

    
    final StaggeredGridView listViewCards = (StaggeredGridView) rootView.findViewById(R.id.listViewCards);
    listViewCards.setLongClickable(true);
    listViewCards.setOnItemLongClickListener(new StaggeredGridView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
                    Logger.e("onItemLongClick");
                    new MaterialDialog.Builder(getActivity())
                            .title("Options")
                            .items(R.array.card_options)
                            .itemsCallback(new MaterialDialog.ListCallback() {
                                @Override
                                public void onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
                                }
                            })
                            .show();
                    return true;
                }
            });
    
    opened by bkawakami 0
  • Error inflating class com.origamilabs.library.views.StaggeredGridView

    Error inflating class com.origamilabs.library.views.StaggeredGridView

    http://stackoverflow.com/questions/28875962/error-inflating-class-com-origamilabs-library-views-staggeredgridview

    Can u check this link ? I got some error and not fix yet.

    opened by ademcan25 0
  • Is it possible to set a header view crossing columns?

    Is it possible to set a header view crossing columns?

    Hi, i've been using this code for a while, but i can't find the way to create a header view which matchs the whole width of the StaggeredGridView. I would like to know if someone was able to implement it, and how to do it please.

    I know that other StaggeredGridView libs or forks are able to do it, but since i've implemented my app with this one, i would like to stick to it if possible.

    thanks in advance

    opened by hugogz 0
A very easy-to-use and non-intrusive implement of Swipe to dismiss for RecyclerView.

RecyclerViewSwipeDismiss A very easy-to-use and non-intrusive implement of Swipe to dismiss for RecyclerView. Preview How to use Add these lines to yo

xcodebuild 431 Nov 23, 2022
Android library to display a ListView whose cells are not rigid but flabby and react to ListView scroll.

FlabbyListView This library is not maintained anymore and there will be no further releases Android library to display a ListView which cells are not

JPARDOGO 762 Nov 23, 2022
An Android custom ListView and ScrollView with pull to zoom-in.

PullZoomView An Android custom ListView and ScrollView with pull to zoom-in. Features Set ZoomView enable Add HeaderView Custom ZoomView Parallax or N

Frank-Zhu 2.3k Dec 26, 2022
Android ListView that mimics a GridView with asymmetric items. Supports items with row span and column span

AsymmetricGridView An Android custom ListView that implements multiple columns and variable sized elements. Please note that this is currently in a pr

Felipe Lima 1.8k Jan 7, 2023
Drag and drop GridView for Android

DynamicGrid Drag and drop GridView for Android. Depricated It's much better to use solutions based on recycler view. For example https://github.com/h6

Alex Askerov 920 Dec 2, 2022
*** WARNING: This library is no longer maintained *** An easy way to add a simple 'swipe-and-do-something' behavior to your `RecyclerView` items. Just like in Gmail or Inbox apps.

SwipeToAction An easy way to add a simple 'swipe-and-do-something' behavior to your RecyclerView items. Just like in Gmail or Inbox apps. Integration

Victor Calvello 223 Nov 16, 2022
RecyclerView extension library which provides advanced features. (ex. Google's Inbox app like swiping, Play Music app like drag and drop sorting)

Advanced RecyclerView This RecyclerView extension library provides Google's Inbox app like swiping, Play Music app like drag-and-drop sorting and expa

Haruki Hasegawa 5.2k Dec 23, 2022
👇 Easy Google Photos style multi-selection for RecyclerViews, powered by Kotlin and AndroidX.

Drag Select Recycler View This library allows you to implement Google Photos style multi-selection in your apps! You start by long pressing an item in

Aidan Follestad 1.9k Dec 7, 2022
A GridView which can addHeaderView and addFooterView

Please follow me on GitHub, I need your support Github: https://github.com/liaohuqiu twitter: https://twitter.com/liaohuqiu 中文版文档 GridView with Header

Huqiu Liao 1.3k Nov 30, 2022
A drag-and-drop scrolling grid view for Android

DraggableGridView¶ ↑ a drag-and-drop scrolling grid view for Android Including in your project¶ ↑ To start using DraggableGridView: Place libs/Draggab

Tom Quinn 565 Dec 27, 2022
A smart colored time selector. Users can select just free time with a handy colorful range selector.

Colored Time Range Selector A smart colored time range selector. Users can select just free time with a handy colorful range selector. Screen Shots Fe

Ehsan Mehranvari 154 Oct 3, 2022
A third-party modified version of Phonograph

Phonograph Modified Version Phonograph 修改版 Phonograph 第三方修改版 A third-party modified version of Phonograph This is a fork! -> 原仓库/Original Project Repo

chr_56 105 Dec 20, 2022
Small utility to create/restore encrypted backups

Quick Backup Choose some files and quickly create a complete encrypted and compressed file. Usage Clone the repository Run gradlew installShadowDist T

Leonardo Colman 5 Sep 18, 2021
androidx window manager sample taken from the original source and modified for easy deploy and test

androidx-window-samples This project contains the WindowManager samples located in the androidx WM project location The goal of this project is to pro

Cesar Valiente 0 Nov 22, 2021
A simple app to showcase Androids Material Design and some of the cool new cool stuff in Android Lollipop. RecyclerView, CardView, ActionBarDrawerToggle, DrawerLayout, Animations, Android Compat Design, Toolbar

#Android-LollipopShowcase This is a simple showcase to show off Android's all new Material Design and some other cool new stuff which is (new) in Andr

Mike Penz 1.8k Nov 10, 2022
Androids EditText that animates the typed text. EditText is extended to create AnimatedEditText and a PinEntryEditText.

AnimatedEditText for Android This repository contains AnimatedEditText and TextDrawable all of which extend the behaviour of EditText and implement fe

Ali Muzaffar 439 Nov 29, 2022
A simple app to showcase Androids Material Design and some of the cool new cool stuff in Android Lollipop. RecyclerView, CardView, ActionBarDrawerToggle, DrawerLayout, Animations, Android Compat Design, Toolbar

#Android-LollipopShowcase This is a simple showcase to show off Android's all new Material Design and some other cool new stuff which is (new) in Andr

Mike Penz 1.8k Nov 10, 2022
A simple app to showcase Androids Material Design and some of the cool new cool stuff in Android Lollipop. RecyclerView, CardView, ActionBarDrawerToggle, DrawerLayout, Animations, Android Compat Design, Toolbar

#Android-LollipopShowcase This is a simple showcase to show off Android's all new Material Design and some other cool new stuff which is (new) in Andr

Mike Penz 1.8k Nov 10, 2022
Xposed module to set the Signature Scheme for Android 30 >= to 1. This allows system apps to be modified

SetSignatureSchemeV1 Xposed module to set the Signature Scheme for Android 30+ to 1. This allows system apps to be modified. This module makes the met

null 4 Sep 20, 2022