Giter Site home page Giter Site logo

jaychang0917 / simplerecyclerview Goto Github PK

View Code? Open in Web Editor NEW
936.0 19.0 104.0 159.42 MB

A RecyclerView extension for building list more easily.

License: Apache License 2.0

Java 99.60% Kotlin 0.40%
android recyclerview multi-type diff-utils drag-drop swipe-to-dismiss snappy section-header

simplerecyclerview's Introduction

SimpleRecyclerView

Download Android Weekly

A RecyclerView extension for building list more easily.

Table of Contents

Sample Project

Get it on Google Play

Installation

In your app level build.gradle :

dependencies {
    implementation 'com.jaychang:simplerecyclerview:2.0.5'
    // for kotlin android extensions
    implementation 'com.jaychang:simplerecyclerview-kotlin-android-extensions:2.0.5'
}

Basically, there are three steps to build your list.

1. Configure the SimpleRecyclerView

Full attributes list

<com.jaychang.srv.SimpleRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:srv_layoutMode="linearVertical|linearHorizontal|grid" 
    app:srv_gridSpanCount="integer"
    app:srv_gridSpanSequence="integer string (e.g. 2233)"
    ... />

2. Define the cell by extending SimpleCell<T, VH>

/**
 * Accept two type arguments,
 * 1st is the data model this cell represents, 2nd is the view holder.
 * */
public class BookCell extends SimpleCell<Book, BookCell.ViewHolder> {

  /** 
   * Mandatory constructor, pass your data model as argument 
   * */
  public BookCell(Book item) {
    super(item);
  }

  /**
   * Define the layout resource of this cell
   * */
  @Override
  protected int getLayoutRes() {
    return R.layout.cell_book;
  }

  @NonNull
  @Override
  protected ViewHolder onCreateViewHolder(ViewGroup parent, View cellView) {
    return new ViewHolder(cellView);
  }

  @Override
  protected void onBindViewHolder(ViewHolder holder, int position, Context context, Object payload) {
    holder.textView.setText(getItem().getTitle());
  }
  
  /**
   * Optional
   * */
  @Override
  protected void onUnbindViewHolder(ViewHolder holder) {
    // do your cleaning jobs here when the item view is recycled.
  }

  /**
   * Define your view holder, which must extend SimpleViewHolder.
   * */
  static class ViewHolder extends SimpleViewHolder {
    TextView textView;

    ViewHolder(View itemView) {
      super(itemView);
      textView = itemView.findViewById(R.id.textView);
    }
  }

}

If you are using Kotlin android extensions, the cell can be simplified as following:

class BookCell(item: Book) : SimpleCell<Book>(item) {
  override fun getLayoutRes(): Int {
    return R.layout.cell_book
  }

  override fun onBindViewHolder(holder: SimpleViewHolder, position: Int, context: Context, payload: Any) {
    holder.textView.text = item.title
  }
}

3. Create cell(s) and add them to the SimpleRecyclerView

List<Book> books = DataUtils.getBooks();
List<BookCell> cells = new ArrayList<>();

for (Book book : books) {
  BookCell cell = new BookCell(book);
  // There are two default cell listeners: OnCellClickListener<T> and OnCellLongClickListener<T>
  cell.setOnCellClickListener(new SimpleCell.OnCellClickListener<Book>() {
    @Override
    public void onCellClicked(Book item) {
      ...
    }
  });
  cell.setOnCellLongClickListener(new SimpleCell.OnCellLongClickListener<Book>() {
    @Override
    public void onCellLongClicked(Book item) {
      ...
    }
  });
  cells.add(cell);
}

simpleRecyclerView.addCells(cells);

Then, there you go!

SimpleRecyclerView supports multiple cell types. You can add different type of cells to it just like adding different type of objects to a list. The SimpleRecyclerView will handle the rest for you.

List<Book> books = DataUtils.getBooks();
List<Ad> ads = DataUtils.getAds();
List<SimpleCell> cells = new ArrayList<>();

for (Book book : books) {
  BookCell cell = new BookCell(book);
  cells.add(cell);
}

for (Ad ad : ads) {
  BookAdCell cell = new BookAdCell(ad);
  int position = (ads.indexOf(ad) + 1) * 3;
  // take up full row
  cell.setSpanSize(simpleRecyclerView.getGridSpanCount());
  cells.add(position, cell);
}

simpleRecyclerView.addCells(cells);

SimpleRecyclerView provides basic CRUD cell operations.

Full cell operations list

It is common that loading cache data first and then fetch new data from network to update the list. The library provides addOrUpdateCell() and addOrUpdateCells() operation to achieve that (It uses DiffUtils under the hood). The cells will not be updated (i.e. receive onBindViewHolder() callback) if their bounded data models are the same, otherwsie they will be added to the end of list. To enable this feature, the cells must be implemented Updatable interface.

public interface Updatable<T> {

  boolean areContentsTheSame(T newItem);

  Object getChangePayload(T newItem);

}
public class BookCell extends SimpleCell<Book, BookCell.ViewHolder>
  implements Updatable<Book> {

  ...

  @Override
  protected void onBindViewHolder(ViewHolder holder, int position, Context context, Object payload) {
    if (payload != null) {
      // partial update
      if (payload instanceof Bundle) {
        Bundle bundle = ((Bundle) payload);
        for (String key : bundle.keySet()) {
          if (KEY_TITLE.equals(key)) {
            holder.textView.setText(bundle.getString(key));
          }
        }
      }
      return;
    }
    ...
  }
  
  /**
   * If the titles of books are same, no need to update the cell, onBindViewHolder() will not be called.
   */
  @Override
  public boolean areContentsTheSame(Book newItem) {
    return getItem().getTitle().equals(newItem.getTitle());
  }

  /**
   * If getItem() is the same as newItem (i.e. their return value of getItemId() are the same)
   * and areContentsTheSame()  return false, then the cell need to be updated,
   * onBindViewHolder() will be called with this payload object.
   * */
  @Override
  public Object getChangePayload(Book newItem) {
    Bundle bundle = new Bundle();
    bundle.putString(KEY_TITLE, newItem.getTitle());
    return bundle;
  }
  
  ...
}
<com.jaychang.srv.SimpleRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:srv_layoutMode="linearVertical" 
    app:srv_showDivider="true|false"
    app:srv_showLastDivider="true|false"
    app:srv_dividerOrientation="vertical|horizontal|both"
    app:srv_dividerColor="@color/your_color"
    app:srv_dividerPaddingLeft="dp"
    app:srv_dividerPaddingRight="dp"
    app:srv_dividerPaddingTop="dp"
    app:srv_dividerPaddingBottom="dp" />
<com.jaychang.srv.SimpleRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:srv_layoutMode="linearVertical" 
    app:srv_spacing="dp"
    app:srv_verticalSpacing="dp"
    app:srv_horizontalSpacing="dp"
    app:srv_isSpacingIncludeEdge="true|false" />

The empty state view will be shown automatically when there is no data. If you want to show the empty state view explicitly, you can set srv_showEmptyStateView attribute to true (Default false).

<com.jaychang.srv.SimpleRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:srv_layoutMode="linearVertical" 
    app:srv_emptyStateView="@layout/view_empty_state" 
    app:srv_showEmptyStateView="true|false" />

You can group cells together by providing a SectionHeaderProvider<T> to setSectionHeader(provider). A shorthand method SimpleSectionHeaderProvider<T> is also provided. The section header is not interative (e.g. can't be clicked)

SectionHeaderProvider<Book> sectionHeaderProvider = new SimpleSectionHeaderProvider<Book>() {
  // Your section header view here
  @NonNull
  @Override
  public View getSectionHeaderView(Book item, int position) {
    View view = LayoutInflater.from(SectionHeaderActivity.this).inflate(R.layout.view_section_header, null, false);
    TextView textView = (TextView) view.findViewById(R.id.textView);
    textView.setText(String.format(getString(R.string.category), item.getCategoryName()));
    return view;
  }
  // Your grouping logic here
  @Override
  public boolean isSameSection(Book item, Book nextItem) {
    return item.getCategoryId() == nextItem.getCategoryId();
  }

  // Optional, whether the header is sticky, default false
  @Override
  public boolean isSticky() {
    return stickyCheckbox.isChecked();
  }

  // Optional, top margin of each section header
  @Override
  public int getSectionHeaderMarginTop(Book item, int position) {
    return position == 0 ? 0 : Utils.dp2px(SectionHeaderActivity.this, 16);
  }
};

simpleRecyclerView.setSectionHeader(sectionHeaderProvider);
// if the total beneath hidden cells count <= 4 and shouldLoadMore() is true, onLoadMore() will be called. Default threshold is 0.
simpleRecyclerView.setAutoLoadMoreThreshold(4);

simpleRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() {
  @Override
  public boolean shouldLoadMore() {
    return hasMoreData;
  }
  
  @Override
  public void onLoadMore() {
    loadBooks();
  }
});
<com.jaychang.srv.SimpleRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:srv_layoutMode="linearVertical"
    app:srv_loadMoreView="@layout/view_load_more" />

If you are going to build a list like chatting, i.e. the cells are added to top of the list, you should set setLoadMoreToTop(true). This instructs the SimpleRecyclerView to check threshold for the top hidden cells.

simpleRecyclerView.setLoadMoreToTop(true);

You can enable drag and drop by providing a DragAndDropCallback<T> for enableDragAndDrop(callback) or enableDragAndDrop(dragHandleResId, callback), the latter one accepts a drag handle view resource id, only pressing this view will trigger drag behavior. Default long press to trigger drag behavior. Also, all callback methods of DragAndDropCallback<T> are optional.

DragAndDropCallback<Book> dragAndDropCallback = new DragAndDropCallback<Book>() {
  // Optional, return false if you manipulate custom drag effect in the rest of callbacks.
  @Override
  public boolean enableDefaultRaiseEffect() {
    // default return true
    return super.enableDefaultRaiseEffect();
  }

  // Optional
  @Override
  public void onCellDragStarted(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position) {
    resultView.setText("Started dragging " + item);
  }

  // Optional
  @Override
  public void onCellMoved(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int fromPosition, int toPosition){
    resultView.setText("Moved " + item + " from " + fromPosition + " to " + toPosition);
  }

  // Optional
  @Override
  public void onCellDropped(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int fromPosition, int toPosition) {
    resultView.setText("Dragged " + item + " from " + fromPosition + " to " + toPosition);
  }

  // Optional
  @Override
  public void onCellDragCancelled(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int currentPosition) {
    resultView.setText("Cancelled dragging " + item);
  }
};

simpleRecyclerView.enableDragAndDrop(R.id.dragHandle, dragAndDropCallback); 
// or
simpleRecyclerView.enableDragAndDrop(dragAndDropCallback);

You can enable swipe to dismiss by providing a SwipeToDismissCallback<T> to enableSwipeToDismiss(callback, swipeDirections). All callback methods of SwipeToDismissCallback<T> are optional.

SwipeToDismissCallback<Book> swipeToDismissCallback = new SwipeToDismissCallback<Book>() {
  // Optional, return false if you manipulate custom swipe effect in the rest of callbacks.
  @Override
  public boolean enableDefaultFadeOutEffect() {
    // default return true
    return super.enableDefaultFadeOutEffect();
  }

  // Optional
  @Override
  public void onCellSwiping(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position, Canvas canvas, float dX, float dY, boolean isControlledByUser) {
    resultView.setText("Item " + item + " is swiping.");
  }

  // Optional
  @Override
  public void onCellSettled(SimpleRecyclerView simpleRecyclerView, View itemView, Book item, int position) {
    resultView.setText("Item " + item + " is settled.");
  }

  // Optional
  @Override
  public void onCellDismissed(SimpleRecyclerView simpleRecyclerView, Book item, int position) {
    resultView.setText("Item: " + item + " is dismissed.");
  }
};

// enable swipe left or right to dismiss
simpleRecyclerView.enableSwipeToDismiss(swipeToDismissCallback, LEFT, RIGHT);
<com.jaychang.srv.SimpleRecyclerView
   android:id="@+id/recyclerView"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   app:srv_layoutMode="linearHorizontal"
   app:srv_snappy="true|false"
   app:srv_snap_alignment="center|start" />

All attrs have coressponding java method.

attr Description
srv_layoutMode Set which layout mode to be used. Support linearVertical, linearHorizontal and grid. Default linearVertical
srv_gridSpanCount Set span count for grid layout mode
srv_gridSpanSequence Set span sequence for grid layout mode
srv_spacing Cell spacing, if srv_verticalSpacing or srv_horizontalSpacing are also set, this takes precedence over them
srv_verticalSpacing Vertical cell spacing for grid layout mode
srv_horizontalSpacing Horizontal cell spacing for grid layout mode
srv_isSpacingIncludeEdge If set to true, spacing will be included in the edges of recyclerview. i.e. top & bottom for linear, all edges for grid. Default false
srv_showDivider If set to true, add dividers between cells. Default false
srv_showLastDivider If set to true, show last divider. Default false
srv_dividerOrientation Divider orientation, works with grid layout mode. Support vertical, horizontal and both. Default both
srv_dividerColor Divider color. Default #e0e0e0
srv_dividerPaddingLeft Divider padding left
srv_dividerPaddingRight Divider padding right
srv_dividerPaddingTop Divider padding top
srv_dividerPaddingBottom Divider padding bottom
srv_emptyStateView Layout resource of empty state view to be shown when there is no data.
srv_showEmptyStateView Show empty state view explicitly. Default false
srv_loadMoreView Layout resource of load more view to be shown when loading more.
srv_snappy If set to true, snappy mode is enabled. Default false
srv_snap_alignment Snap alignment. Support center and start. Default center
Operation Remark
addCell(SimpleCell cell) Add the cell to the end of list
addCell(int atPosition, SimpleCell cell) Add the cell to a specific position of list
addCells(List<? extends SimpleCell> cells) Add the cells to the end of list
addCells(SimpleCell... cells) Same as above
addCells(int fromPosition, List<? extends SimpleCell> cells) Add the cells to list from a specific position
addCells(int fromPosition, SimpleCell... cells) Same as above
addOrUpdateCell(T cell) Add or udpate the cell. The cell should be implemented Updatable interface
addOrUpdateCells(List cells) Add or update the cells. The cells should be implemented Updatable interface
addOrUpdateCells(T... cells) Same as above
removeCell(SimpleCell cell) Remove the cell from list
removeCell(int atPosition) Remove the cell at specific position
removeCells(int fromPosition, int toPosition) Remove range of cells [fromPosition..toPosition] from list
removeCells(int fromPosition) Remove range of cells [fromPosition..end] from list
removeAllCells() Remove all cells from list
removeAllCells(boolean showEmptyStateView) Remove all cells from list and tell the SimpleRecyclerView if need to show empty state view. Default true
updateCell(int atPosition, Object payload) Update the specific cell with payload.
updateCells(int fromPosition, int toPosition, List payloads) Update the range of cells [fromPosition..toPosition] with payloads.|
getCell(int atPosition) Get the cell at specific postion
getCells(int fromPosition, int toPosition) Get a range of cells [fromPosition..toPosition]
getAllCells() Get all cells

License

Copyright 2017 Jay Chang

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

simplerecyclerview's People

Contributors

deividasstr avatar jaychang0917 avatar jaychang0917redso 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

simplerecyclerview's Issues

Documentation issues

I've found two problems with the documentation. First, the signature of onBindViewHolder is incorrect. The example code shows it as

onBindViewHolder(ViewHolder holder, int position, Context context, List<Object> payloads)

but it is actually

onBindViewHolder(ViewHolder holder, int position, Context context, Object payload)

Second, the example code uses Butterknife but does not mention anything about installing or configuring it. If this library relies on (or is intended to be used with) Butterknife, that should be explicitly called out. If it does not, then example code should be provided that does not require Butterknife.

Tapped cell moves to 1st position in recyclerview

Hi there, first of all i'd like to say thanks for making SimpleRecyclerView.

I noticed a strange issue recently. I've added cell.setOnCellClickListener2 in bind data which intents to a new window. Strangely, when I come back to the RecyclerView, that tapped item/cell moves to the top of the recyclerview. It's difficult for me to put it down in words but I hope you understand.

Item show not correct

When i scroll my recycler view to end and scroll again to top, some item in the top change and become not correct. Please tell me if i miss something. Thank you!

Load more footer

Thanks for awesome lib !
About the auto load more feature, is it possible to add the footer (loading progress bar, etc.) ?

feature request headers and footers

hi love this library , one possible enhance is headers and footers , mostly for when the actual layout is grid and need a header to linear

onCellClickListener not working

I have added an onCellClickListener to the cells in my recyclerview, which is a list of podcasts. The selected podcast should start playing when the user taps a cell in the list, but the onCellClicked method is never called. I have also added an onCellLongClicked method, and this one works fine, but it is not my intended functionality for the app.

Here is the code where I bind the data and create the listeners:

    List<DataManager.Podcast> podcasts = DownloadData.podcastList;
    List<DataManager.PodcastCell> cells = new ArrayList<>();
    for (DataManager.Podcast podcast:podcasts) {
        DataManager.PodcastCell cell = new DataManager.PodcastCell(podcast);
        cell.setOnCellClickListener(new SimpleCell.OnCellClickListener<DataManager.Podcast>() {
            @Override
            public void onCellClicked(DataManager.Podcast item) {
                Log.d("test", "CLICK");
            }
        });
        cell.setOnCellLongClickListener(new SimpleCell.OnCellLongClickListener<DataManager.Podcast>() {
            @Override
            public void onCellLongClicked(DataManager.Podcast item) {
                Log.d("test", "LONGCLICK");
            }
        });
        cells.add(cell);
    }
    recyclerView.addCells(cells);

And here's the console output when I attempt both types of clicking:
08-23 11:48:55.811 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:48:56.767 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:48:57.579 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:48:58.410 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:49:02.141 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:49:03.442 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:49:04.155 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK
08-23 11:49:05.382 8394-8394/com.gmail.lpizzanakin.myfirstvbgapp D/test: LONGCLICK

I don't see any differences between my implementations of both listeners, so I don't think there should be anything wrong with my code.

How to get View when click cell?

I use

ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(view, 0, 0, 0, 0);

to startActivity, but cell.setOnCellClickListener not have view. How to get view when use default cell. Thanks

insertion api with section

Something like:
recyclerView.addCellInSectionHeader(int position, SimpleCell cell, SectionHeaderProvider provider);

Where position is relative to the section.
Insertion can take optional params of insert to top/bottom.

AutoLoader issue

Hi man, your lib is awesome. I've found an issue with autoloader.
I don't even know if it's a bug, autoloader doesn't work if all elements are visible. For example, I have endless list with 10 start elements on the screen. On the big screen these elements don't fill a whole screen, but I still expect recycler to call more elements to download, but it doesn't.
But it's ok if I SimpleRecyclerView#setLoadMoreToTop() with true flag.

Reloading SimpleRecyclerView causes extra cells

When I hit a refresh button in my app to reload the SimpleRecyclerView with section headers, I use an AsyncTask to get the data to create the sections and cells. I run the .removeAllCells() onPreExecute, create the cells in the doInBackground, and add the cells to the recylerView in the onPostExecute. However, the recyclerView seems to do some sort of caching and adds an extraneous section to the beginning and then adds an extraneous cell to the end of each section after each refresh.

I've added images below for reference:

On initial load...
screenshot_20170602-125143

After first refresh...
screenshot_20170602-125148

After second refresh...
screenshot_20170602-125153

You can see the pattern, and it continues with each refresh. Any thoughts on how to solve this issue? Thanks

Does header remove on removeAll ?

Hey,

I have and filter and I have to call notifiyDatasetChanged but its not working so I am called removeAll and then add new cells so cells are working fine, but headers are not working fine because my headers are also different so I have to call addRecyclerHeaders, headers names appears fine but there is blank space on above the headers. What I understand there is an space of previous headers.

Please lemme know how can I remove all headers too ?

Autoloading

Hi again, I have found another problem: loading view doesn't work with grid layout.

Remove/Clear items from Recyclerview with sticky header

I want to remove items from recyclerview with the sticky header, but no luck at all. I tried with clearing all ArrayList before loading but no luck. I tried with rView.removeAllCells(true);. It will remove items with sticky header, but I tried to add items again (in same activity) first sticky header gets doubled and empty spaces are adding to the recyclerview.

Cannot resolve method 'addOrUpdateCells<com..jaychang...SimpleCell'

does the add or update not work with simpleCell , because for these operation

 public void onNext(List<SimpleCell> value) {
                        new WeakHandler().postDelayed(() -> {
                            mSwipeRefreshLayout.setRefreshing(false);
                            if (value.size() > 0) {
                                mRecyclerview.addOrUpdateCells(value); // cannot resolve method 'addOrUpdateCells
                            }
                        }, 500);
                    }

Am getting cannot resolve method 'addOrUpdateCells
library version
compile 'com.github.jaychang0917:SimpleRecyclerView:1.1.7'

Method count issue.

This is a nice library to use, thank you for your hard work! However the recent change has the side effect of adding lots of method count because of using Kotlin library I guess.

Can this be resolved in near the future? e.g. have a different branch which doesn't include kotlin.

Crash on swipe to dismiss sample

Quite hard to reproduce, but I played with it a little, and it crashed. Here's the log:

02-05 22:28:13.343 19941-19941/com.jaychang.demo.srv E/InputEventReceiver: Exception dispatching input event.
02-05 22:28:13.372 19941-19941/com.jaychang.demo.srv E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.jaychang.demo.srv, PID: 19941
java.lang.ArrayIndexOutOfBoundsException: length=10; index=-1
at java.util.ArrayList.get(ArrayList.java:413)
at com.jaychang.srv.SimpleAdapter.getCell(SimpleAdapter.java:262)
at com.jaychang.srv.SimpleRecyclerView.getCell(SimpleRecyclerView.java:724)
at com.jaychang.srv.behavior.SwipeToDismissItemCallback.getMovementFlags(SwipeToDismissItemCallback.java:37)
at android.support.v7.widget.helper.ItemTouchHelper$Callback.getAbsoluteMovementFlags(ItemTouchHelper.java:1568)
at android.support.v7.widget.helper.ItemTouchHelper.checkSelectForSwipe(ItemTouchHelper.java:960)
at android.support.v7.widget.helper.ItemTouchHelper$2.onInterceptTouchEvent(ItemTouchHelper.java:340)
at android.support.v7.widget.RecyclerView.dispatchOnItemTouch(RecyclerView.java:2602)
at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2730)
at android.view.View.dispatchTouchEvent(View.java:10023)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2626)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2307)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:413)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808)
at android.app.Activity.dispatchTouchEvent(Activity.java:3070)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:375)
at android.view.View.dispatchPointerEvent(View.java:10243)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4438)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4306)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3999)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4056)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6246)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6220)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6349)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
02-05 22:28:13.372 19941-19941/com.jaychang.demo.srv E/AndroidRuntime: at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6320)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6372)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
at android.view.Choreographer.doCallbacks(Choreographer.java:686)
at android.view.Choreographer.doFrame(Choreographer.java:615)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
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:6169)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)
02-05 22:28:13.729 904-15827/system_process E/ActivityManager: Found activity ActivityRecord{36079ba u0 com.jaychang.demo.srv/.MainActivity t2877 f} in proc activity list using null instead of expected ProcessRecord{64b8120 19941:com.jaychang.demo.srv/u0a307}
02-05 22:28:13.916 3326-3326/com.touchtype.swiftkey.beta E/FullInputEventModel: onStartInput event aborted: com.touchtype.keyboard.d.am: could not obtain extracted text (class com.touchtype.keyboard.d.am)

Issue with autoloader

Hi again, thanks for fixes ! I think there's a bug with setLoadingMore(). I think there should be check if loading is already shown.

Section in grid

Hi, dude! It's a really cool view, thank you for this!
But category for grid looks so strange. It's working only for full lines. For example, I have 2 columns in my grid. And if I add catagory after 3 elements, 4 elements added to this category too.
And can you add "multiselect" function?

Unable to get it working with Kotlin

Im using kotlin and have been following the guide in the readme.

Problem 1
I came across the section below in the readme and i cannot get it to work.

class BookCell(item: Book) : SimpleCell<Book>(item) {
  override fun getLayoutRes(): Int {
    return R.layout.cell_book
  }

  override fun onBindViewHolder(holder: SimpleViewHolder, position: Int, context: Context, payload: Any) {
    holder.textView.text = item.title
  }
}

Android Studio does not recognize textView in this line:
holder.textView.text = item.title

I did create the layout file and have a textView with the matching Id so im not sure whats going on.

I was under the impression that maybe you were doing some sort of compile time generation to generate the holder to be used based off of the layout file, but that cant be because com.jaychang.srv.kae.SimpleCell uses SimpleViewHolder explicitly which only extends com.jaychang.srv.SimpleViewHolder.

Problem 2
Cant create list of SimpleCell type in kotlin that is shown in the Multiple Types section of the readme.

List<Book> books = DataUtils.getBooks();
List<Ad> ads = DataUtils.getAds();
List<SimpleCell> cells = new ArrayList<>();

My version, In Kotlin

val books:MutableList<Book> = DataUtils.getBooks();
val ads:MutableList<Ad> = DataUtils.getAds();
val cells:MutableList<SimpleCell> = mutableListOf()

Android Studio is complaining about SimpleCell in the list declaration ( MutableList<SimpleCell> ) stating that I must add the Type argument.

One type argument expected for class SimpleCell<T>

I am very confused and would greatly appreciate it if you could provide a more detailed guide for using this library with kotlin and perhaps several kotlin example activities in the source.

I suppose for the time being i can write this in java but that also means other areas of my app that are already in kotlin will have to be converted back to java, which is a bummer. :(

Header rows ignore ConstraintLayout/RelativeLayout directives

Header items appear to be unable to use either percentage guidelines (if
using ConstraintLayout) or align-to-right (if using RelativeLayout). This is
unfortunate, because the data items themselves work perfectly with ConstraintLayout
percentage guidelines, useful for aligning data into columns. In our case
we want the subsection header row items to show labels for those columns,
but due to this issue the header row layout directives are ignored, causing
(severe) misalignment.

Even using ancient RelativeLayout is problematic as it also ignores directive
to align to parent right edge -- the workaround for now is to use RelativeLayout
and progressively lay items out left to right, but this puts us back in old-school
dpi level territory, which was eliminated when ConstraintLayout percentages
were introduced.

The image attached below demonstrates the same ConstraintLayout .xml (using percentage guidelines)
when used standalone vs. when added via SimpleRecylerView "SimpleSectionHeaderProvider"
(note that the data items themselves successfully use ConstraintLayout percentage
guidelines to arrange data in columns, but the header rows ignore those directives)
simplerecyclerview_header_rows_pull_left_not_expanding

Not doing anything fancy, should be similar to the bundled demo app (in kotlin) e.g.

    private fun addRecyclerHeaders(inflater: LayoutInflater, simpleRecyclerView: SimpleRecyclerView, historyListType: HistoryListType) {
        val sh = object : SimpleSectionHeaderProvider<SKResultsUIList>() {
            override fun getSectionHeaderView(skResultsUIList: SKResultsUIList, i: Int): View {
                val view = inflater.inflate(R.layout.result_history_list_header_card_view, null, false)
                ...
                return view
            }
            override fun isSameSection(currItem: SKResultsUIList, nextItem: SKResultsUIList): Boolean {
                return currItem.simpleRVCategory === nextItem.simpleRVCategory
            }

            // Optional, whether the header is sticky, default false
            override fun isSticky(): Boolean {
                return true
            }
        }
        simpleRecyclerView.setSectionHeader(sh)
    }

Empty state view does not appear when the recycler view is initially empty

If you create a SimpleRecyclerView with an empty state view, it doesn't show the empty state view unless you add items first then remove them later.

I replicated with the sample project. If loadBookingsFromNetwork() is removed from the onCreate of EmptyStateViewActivity.java:

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_empty_view);
    ButterKnife.bind(this);

    init();
    //loadBooksFromNetwork();
  }

Then when the activity is opened, the empty state view is not shown. Once you hit add then remove all, it will appear.

Issue with autoloader

Hi again. Thatnks for fixer. I have found another one thing. There's no way to disable autoloading.
I mean I have loaded all elements, but there's no way to disable loading progress.

One section header for multiple cell types

Hello, I have a recycler view that displays list of different events, each event type is represented by different Cell type, however I would like to have section header that would group them by date. Currently I do not see a way to have one section header for multiple cells types.

Any advise welcome,
Thanks!

Section view

Hi, thanks for library!
But i have issue with section header in list. If I have Relative layout like view for header, it's showing wrong. It ssems like width = "wrap_content", although it match parent.
See screenshot. I use identical view for items and header.
screenshot_2017-09-19-00-07-23-312_com jaychang demo srv

getAllCells after updateCell returning stale data

getCell and getAllCells are not updated.

I verified this with break points showing that the two get calls will occur before the MyCell.onBindViewHolder with the changedPayload, even when updateCell is called before the two gets.

recyclerView.updateCell(1, new Text("1000", 0));

        Log.i("GETAFTERUPDATE", ((TextCell) recyclerView.getCell(1)).getItem().text);

        int total = 0;
        for (SimpleCell sc : recyclerView.getAllCells()) {

Add cell to be placed under section header

Currently if your section SECTION A {1,2,3,4,5}, then adding element 0 will result in it being placed under the section view and not visible to the user. Perhaps instead of the views moving up with the addition, they could move down making room for the add element in the 0th spot.

Multi type viewholder casting crash

See this branch - https://github.com/ersin-ertan/Recycler/tree/multiTypeCrash

I'm testing two different types, TextCell and TextCell2, each of which uses their own data model of Text and Text2, respectively.

Press ADD to add a new TextCell2 to the list - > crash

java.lang.ClassCastException: com.nullcognition.recycler.TextCell2$ViewHolder cannot be cast to com.nullcognition.recycler.TextCell$ViewHolder at com.nullcognition.recycler.TextCell.onBindViewHolder(TextCell.java:15)

Drag and drop is crashing app

When making small drag and drops on demo app one after another, very quickly, activity crashes and is restarted by ActivityManager

02-08 15:54:15.986 10754-26023/? E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!
02-08 15:54:15.996 10754-26023/? I/ActivityManager: Restarting because process died: ActivityRecord{120ab7db u0 com.jaychang.demo.srv/.MainActivity t3043}
02-08 15:54:15.996 10754-26023/? E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!
02-08 15:54:15.996 10754-26023/? W/ActivityManager: Exception when starting activity com.jaychang.demo.srv/.MainActivity
                                                    android.os.TransactionTooLargeException
                                                        at android.os.BinderProxy.transactNative(Native Method)
                                                        at android.os.BinderProxy.transact(Binder.java:496)
                                                        at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:814)
                                                        at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1301)
                                                        at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1407)
                                                        at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1978)
                                                        at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1536)
                                                        at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1523)
                                                        at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:960)
                                                        at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:2881)
                                                        at com.android.server.am.ActivityStack.finishTopRunningActivityLocked(ActivityStack.java:2738)
                                                        at com.android.server.am.ActivityStackSupervisor.finishTopRunningActivityLocked(ActivityStackSupervisor.java:2744)
                                                        at com.android.server.am.ActivityManagerService.handleAppCrashLocked(ActivityManagerService.java:13743)
                                                        at com.android.server.am.ActivityManagerService.makeAppCrashingLocked(ActivityManagerService.java:13640)
                                                        at com.android.server.am.ActivityManagerService.crashApplication(ActivityManagerService.java:14352)
                                                        at com.android.server.am.ActivityManagerService.handleApplicationCrashInner(ActivityManagerService.java:13868)
                                                        at com.android.server.am.NativeCrashListener$NativeCrashReporter.run(NativeCrashListener.java:86)

FastScroll!

An amazing library that makes work even smoother and faster.
One feature to be added if possible which is FastScroll ability!

Headers are not showing up on init

Headers are not showing up on init, only after I scroll down and up they appear to be drawn.
If I have only one item, I can't scroll and I can't see the header at all.
Do you have any idea why would that happen?

Object returned in onBindViewHolder is always null!

Something is really weird happening here, he object is always null!

Although, I tried to follow the exact way you did in the sample app but still, the object it null!
Anything I need to consider in here?

Thank you.

Calling setLoadingMore(false) immediately after setLoadingMore(true) breaks the state of the view

When setLoadingMore(true) is called (which in turn calls showLoadMoreView()), a call to addCell method is added to the UI message queue and isLoadMoreViewShown is set to true.

If setLoadingMore(false) is called right after that, removeCell method is called immediately and isLoadMoreViewShown is set to false.

The problem is that at this moment the runnable that calls addCell is still in the message queue, therefore it will be called later. But when it's called, it adds this cell despite the fact that isLoadMoreViewShown is false. Now the cell is displayed, and it's not possible to hide it with another call to setLoadingMore(false), because hideLoadMoreView() thinks that it's already hidden.

Bug in removeCells?

public void removeCells(int fromPosition, int toPosition) {
    for(int i = fromPosition; i <= toPosition; ++i) {
        SimpleCell cell = (SimpleCell)this.cells.get(i);
        this.cells.remove(cell);
        this.removeCellType(cell);
    }

    this.notifyItemRangeRemoved(fromPosition, toPosition - fromPosition + 1);
}

isin't this always going to crash (Outofrange Index exception) at the position ((toPos - fromPos / 2) + 1)? Because this,cells is mutating..

We should replace SimpleCell cell = (SimpleCell)this.cells.get(i); with SimpleCell cell = (SimpleCell)this.cells.get(fromPosition);

or simply delete reverse

  for(int i = toPosition; i >= fromPosition; i--) {
        SimpleCell cell = (SimpleCell)this.cells.get(i);
        this.cells.remove(cell);
        this.removeCellType(cell);
    }

SimpleCell Bug

  protected abstract long getItemId();

When DownloadCell getItemId() return 0. the recycler cell method onBindViewHolder will never be called.

The log of my debug are as follow.
Why onBindViewHolder called, must call getItemId?
I must provide a valid id for cell?

E: getItemId: a(cell data)
E: getItemId: a(cell data)
E: onBindViewHolder: position=1; aa(cell data)
E: getItemId: b(cell data)
E: getItemId: b(cell data)
E: onBindViewHolder: position=2; b(cell data)
E: getItemId: c(cell data)
E: getItemId: c(cell data)
E: onBindViewHolder: position=3; c(cell data)
    private class DownloadCell extends SimpleCell<DownloadBean, DownloadViewHolder> {

        private DownloadCell(DownloadBean item) {
            super(item);
        }

        @Override
        protected int getLayoutRes() {
            return R.layout.adapter_offline_download_item;
        }

        @NonNull
        @Override
        protected DownloadViewHolder onCreateViewHolder(ViewGroup viewGroup, View view) {
            return new DownloadViewHolder(view);
        }

        @Override
        protected void onBindViewHolder(DownloadViewHolder holder, int i, Context context, Object o) {
            DownloadBean item = getItem();
            OfflineManager.DownloadTileInfo info = item.downloadTileInfo;
            holder.textTileName.setText(info.getTileName());
        }

        @Override
        protected long getItemId() {
           // don't have a valid id.
            return 0;
        }
    }

addOrUpdateCells fails on an empty RecyclerView

it seems that addOrUpdateCells() fails/crashes when the SimpleRecyclerView is empty.

at some point, the SimpleRecyclerView code checks for the mapping of type/name and since the recyclerview isempty (addCell or addCells not called) it crashes.

As a workaround, I have to add a dummycell at the initialization

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.