├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cncoderx │ │ └── recyclerview │ │ └── helper │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── cncoderx │ │ │ └── test │ │ │ └── recyclerviewhelper │ │ │ ├── activity │ │ │ ├── DataFilterActivity.java │ │ │ ├── ExpandableItemActivity.java │ │ │ ├── HeaderOrFooterActivity.java │ │ │ ├── ItemClickEventActivity.java │ │ │ ├── LoadMoreActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MultiItemActivity.java │ │ │ ├── RecyclerViewActivity.java │ │ │ └── SwipeLayoutActivity.java │ │ │ ├── adapter │ │ │ ├── AlbumAdapter.java │ │ │ ├── AlbumSwipeAdapter.java │ │ │ ├── ExpandableAlbumAdapter.java │ │ │ └── MultiAlbumAdapter.java │ │ │ ├── data │ │ │ ├── Album.java │ │ │ └── AlbumManager.java │ │ │ └── utils │ │ │ ├── Layout.java │ │ │ └── SquareImageView.java │ └── res │ │ ├── drawable-nodpi │ │ ├── cover01.jpg │ │ ├── cover02.jpg │ │ ├── cover03.jpg │ │ ├── cover04.jpg │ │ ├── cover05.jpg │ │ ├── cover06.jpg │ │ ├── cover07.jpg │ │ ├── cover08.jpg │ │ ├── cover09.jpg │ │ ├── cover10.jpg │ │ ├── cover11.jpg │ │ ├── cover12.jpg │ │ ├── cover13.jpg │ │ ├── cover14.jpg │ │ ├── cover15.jpg │ │ ├── cover16.jpg │ │ ├── cover17.jpg │ │ └── cover18.jpg │ │ ├── drawable │ │ └── selector_item_bg.xml │ │ ├── layout │ │ ├── activity_recycler_view.xml │ │ ├── item_album_grid_layout.xml │ │ ├── item_album_grid_swipe_layout.xml │ │ ├── item_album_linear_layout.xml │ │ ├── item_album_linear_swipe_layout.xml │ │ ├── item_album_staggered_layout.xml │ │ ├── item_album_staggered_swipe_layout.xml │ │ ├── item_expandable_group.xml │ │ ├── item_footer_layout.xml │ │ └── item_header_layout.xml │ │ ├── menu │ │ └── menu_layout.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── cncoderx │ └── recyclerview │ └── helper │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── bintray.gradle ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cncoderx │ │ └── recyclerviewhelper │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── cncoderx │ │ │ └── recyclerviewhelper │ │ │ ├── RecyclerViewHelper.java │ │ │ ├── adapter │ │ │ ├── ArrayAdapter.java │ │ │ ├── BaseAdapter.java │ │ │ ├── CursorAdapter.java │ │ │ ├── CursorFilter.java │ │ │ ├── DelegateAdapter.java │ │ │ ├── ExpandableAdapter.java │ │ │ ├── ObjectAdapter.java │ │ │ ├── ResourceCursorAdapter.java │ │ │ ├── SimpleAdapter.java │ │ │ ├── SimpleCursorAdapter.java │ │ │ └── SwipeAdapter.java │ │ │ ├── listener │ │ │ ├── EndlessScrollListener.java │ │ │ ├── OnChildClickListener.java │ │ │ ├── OnChildLongClickListener.java │ │ │ ├── OnGroupClickListener.java │ │ │ ├── OnGroupLongClickListener.java │ │ │ ├── OnItemClickListener.java │ │ │ ├── OnItemLongClickListener.java │ │ │ └── OnLoadMoreListener.java │ │ │ └── utils │ │ │ ├── AdapterArray.java │ │ │ ├── Array.java │ │ │ ├── DividerItemDecoration.java │ │ │ ├── IAdapterArray.java │ │ │ ├── IArray.java │ │ │ ├── ILoadingView.java │ │ │ └── SpacingItemDecoration.java │ └── res │ │ ├── drawable │ │ └── divider.xml │ │ ├── layout │ │ └── layout_loading_view.xml │ │ ├── values-zh │ │ └── strings.xml │ │ └── values │ │ ├── dimens.xml │ │ ├── ids.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── cncoderx │ └── recyclerviewhelper │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | RecyclerViewHelper是基于android 原生库RecyclerView的功能扩展,扩展的功能包括: 3 | * Item的点击/长按事件 4 | * 添加Header/Footer View 5 | * 滑动到底部加载更多(Load More) 6 | * 可收缩/展开的两级列表(类似ExpandableListView) 7 | * 非常简单的添加分割线和列表间距 8 | * Item抽屉效果(![Swipe Layout](https://github.com/daimajia/AndroidSwipeLayout)) 9 | * 拓展了多种适配器Adapter 10 | 11 | #### 增加的适配器 12 | * ![ArrayAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ArrayAdapter.java) 13 | * ![SimpleAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/SimpleAdapter.java) 14 | * ![CursorAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/CursorAdapter.java)、![SimpleCursorAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/SimpleCursorAdapter.java) 15 | * ![ObjectAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ObjectAdapter.java) 16 | * ![ExpandableAdapter](https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/master/library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ExpandableAdapter.java) 17 | 18 | ## 添加依赖 19 | ```gradle 20 | compile 'com.github.CNCoderX:RecyclerViewHelper:1.2.5' 21 | 22 | // 如果需要添加抽屉功能,添加依赖: 23 | compile "com.daimajia.swipelayout:library:1.2.0@aar" 24 | ``` 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.cncoderx.recyclerview.helper" 9 | minSdkVersion 15 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | testImplementation 'junit:junit:4.12' 25 | implementation project(':library') 26 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 27 | implementation "com.daimajia.swipelayout:library:1.2.0@aar" 28 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' 29 | } 30 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\wujie\AndroidStudio_SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/cncoderx/recyclerview/helper/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerview.helper; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/DataFilterActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.DialogInterface; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | import android.text.TextUtils; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.widget.EditText; 10 | 11 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 12 | import com.cncoderx.test.recyclerviewhelper.R; 13 | import com.cncoderx.test.recyclerviewhelper.adapter.AlbumAdapter; 14 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 15 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 16 | 17 | public class DataFilterActivity extends RecyclerViewActivity { 18 | private String mSearchKey; 19 | 20 | @Override 21 | protected void onLayoutManagerChanged(Layout layout) { 22 | super.onLayoutManagerChanged(layout); 23 | 24 | RecyclerView.Adapter adapter = null; 25 | switch (layout) { 26 | case linear: 27 | adapter = new AlbumAdapter(R.layout.item_album_linear_layout, AlbumManager.obtainAlbumList()); 28 | break; 29 | case grid: 30 | adapter = new AlbumAdapter(R.layout.item_album_grid_layout, AlbumManager.obtainAlbumList()); 31 | break; 32 | case staggered: 33 | adapter = new AlbumAdapter(R.layout.item_album_staggered_layout, AlbumManager.obtainAlbumList()); 34 | break; 35 | } 36 | 37 | RecyclerViewHelper.setAdapter(mRecyclerView, adapter); 38 | if (!TextUtils.isEmpty(mSearchKey)) { 39 | RecyclerViewHelper.setFilterText(mRecyclerView, mSearchKey); 40 | } 41 | } 42 | 43 | @Override 44 | public boolean onCreateOptionsMenu(Menu menu) { 45 | super.onCreateOptionsMenu(menu); 46 | menu.findItem(R.id.action_search).setVisible(true); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onMenuItemSelected(int featureId, MenuItem item) { 52 | super.onMenuItemSelected(featureId, item); 53 | if (item.getItemId() == R.id.action_search) { 54 | final EditText editText = new EditText(this); 55 | editText.setSingleLine(); 56 | new AlertDialog.Builder(this) 57 | .setCancelable(false) 58 | .setTitle(android.R.string.search_go) 59 | .setView(editText) 60 | .setNegativeButton(android.R.string.cancel, null) 61 | .setPositiveButton(android.R.string.search_go, new DialogInterface.OnClickListener() { 62 | @Override 63 | public void onClick(DialogInterface dialog, int which) { 64 | mSearchKey = editText.getText().toString(); 65 | RecyclerViewHelper.setFilterText(mRecyclerView, mSearchKey); 66 | } 67 | }).show(); 68 | } 69 | return true; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/ExpandableItemActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.cncoderx.recyclerviewhelper.adapter.ExpandableAdapter; 8 | import com.cncoderx.recyclerviewhelper.listener.OnChildClickListener; 9 | import com.cncoderx.recyclerviewhelper.listener.OnChildLongClickListener; 10 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 11 | import com.cncoderx.test.recyclerviewhelper.R; 12 | import com.cncoderx.test.recyclerviewhelper.adapter.ExpandableAlbumAdapter; 13 | import com.cncoderx.test.recyclerviewhelper.data.Album; 14 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | public class ExpandableItemActivity extends RecyclerViewActivity { 20 | 21 | @Override 22 | protected void onLayoutManagerChanged(Layout layout) { 23 | super.onLayoutManagerChanged(layout); 24 | 25 | ArrayList group = new ArrayList<>(); 26 | group.add("Classical"); 27 | group.add("Country"); 28 | group.add("Jazz"); 29 | group.add("Pop"); 30 | group.add("Rock"); 31 | 32 | ArrayList> child = new ArrayList<>(); 33 | child.add(AlbumManager.obtainAlbumList("classical")); 34 | child.add(AlbumManager.obtainAlbumList("country")); 35 | child.add(AlbumManager.obtainAlbumList("jazz")); 36 | child.add(AlbumManager.obtainAlbumList("pop")); 37 | child.add(AlbumManager.obtainAlbumList("rock")); 38 | 39 | ExpandableAdapter adapter = null; 40 | switch (layout) { 41 | case linear: 42 | adapter = new ExpandableAlbumAdapter(group, child, 43 | R.layout.item_expandable_group, R.layout.item_album_linear_layout); 44 | break; 45 | case grid: 46 | adapter = new ExpandableAlbumAdapter(group, child, 47 | R.layout.item_expandable_group, R.layout.item_album_grid_layout); 48 | break; 49 | case staggered: 50 | adapter = new ExpandableAlbumAdapter(group, child, 51 | R.layout.item_expandable_group, R.layout.item_album_staggered_layout); 52 | break; 53 | } 54 | mRecyclerView.setAdapter(adapter); 55 | adapter.setOnChildClickListener(new OnChildClickListener() { 56 | @Override 57 | public void onChildClick(RecyclerView parent, View v, int groupPosition, int childPosition, long id) { 58 | Toast.makeText(getApplicationContext(), "click child item, position:" + childPosition, Toast.LENGTH_SHORT).show(); 59 | } 60 | }); 61 | adapter.setOnChildLongClickListener(new OnChildLongClickListener() { 62 | @Override 63 | public boolean onChildLongClick(RecyclerView parent, View v, int groupPosition, int childPosition, long id) { 64 | Toast.makeText(getApplicationContext(), "long click child item, position:" + childPosition, Toast.LENGTH_SHORT).show(); 65 | return true; 66 | } 67 | }); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/HeaderOrFooterActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | 6 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 7 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 8 | import com.cncoderx.test.recyclerviewhelper.R; 9 | 10 | public class HeaderOrFooterActivity extends ItemClickEventActivity { 11 | 12 | @Override 13 | protected void onLayoutManagerChanged(Layout layout) { 14 | super.onLayoutManagerChanged(layout); 15 | 16 | // new header view 17 | View headerView = LayoutInflater.from(this).inflate(R.layout.item_header_layout, mRecyclerView, false); 18 | headerView.setOnClickListener(new View.OnClickListener() { 19 | @Override 20 | public void onClick(View v) { 21 | RecyclerViewHelper.removeHeaderView(mRecyclerView, v); 22 | } 23 | }); 24 | RecyclerViewHelper.addHeaderView(mRecyclerView, headerView); 25 | 26 | // new footer view 27 | View footerView = LayoutInflater.from(this).inflate(R.layout.item_footer_layout, mRecyclerView, false); 28 | footerView.setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | RecyclerViewHelper.removeFooterView(mRecyclerView, v); 32 | } 33 | }); 34 | RecyclerViewHelper.addFooterView(mRecyclerView, footerView); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/ItemClickEventActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 8 | import com.cncoderx.recyclerviewhelper.listener.OnItemClickListener; 9 | import com.cncoderx.recyclerviewhelper.listener.OnItemLongClickListener; 10 | import com.cncoderx.test.recyclerviewhelper.R; 11 | import com.cncoderx.test.recyclerviewhelper.adapter.AlbumAdapter; 12 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 13 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 14 | 15 | /** 16 | * @author cncoderx 17 | */ 18 | public class ItemClickEventActivity extends RecyclerViewActivity { 19 | 20 | @Override 21 | protected void onLayoutManagerChanged(Layout layout) { 22 | super.onLayoutManagerChanged(layout); 23 | 24 | RecyclerView.Adapter adapter = null; 25 | switch (layout) { 26 | case linear: 27 | adapter = new AlbumAdapter(R.layout.item_album_linear_layout, AlbumManager.obtainAlbumList()); 28 | break; 29 | case grid: 30 | adapter = new AlbumAdapter(R.layout.item_album_grid_layout, AlbumManager.obtainAlbumList()); 31 | break; 32 | case staggered: 33 | adapter = new AlbumAdapter(R.layout.item_album_staggered_layout, AlbumManager.obtainAlbumList()); 34 | break; 35 | } 36 | 37 | RecyclerViewHelper.setAdapter(mRecyclerView, adapter); 38 | RecyclerViewHelper.setOnItemClickListener(mRecyclerView, new OnItemClickListener() { 39 | @Override 40 | public void onItemClick(RecyclerView parent, View view, int position, long id) { 41 | Toast.makeText(getApplicationContext(), "click item, position:" + position, Toast.LENGTH_SHORT).show(); 42 | } 43 | }); 44 | RecyclerViewHelper.setOnItemLongClickListener(mRecyclerView, new OnItemLongClickListener() { 45 | @Override 46 | public boolean onItemLongClick(RecyclerView parent, View view, int position, long id) { 47 | Toast.makeText(getApplicationContext(), "long click item, position:" + position, Toast.LENGTH_SHORT).show(); 48 | return true; 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/LoadMoreActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.os.AsyncTask; 4 | import androidx.annotation.Nullable; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 7 | 8 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 9 | import com.cncoderx.recyclerviewhelper.listener.OnLoadMoreListener; 10 | import com.cncoderx.recyclerviewhelper.utils.ILoadingView; 11 | import com.cncoderx.test.recyclerviewhelper.R; 12 | import com.cncoderx.test.recyclerviewhelper.adapter.AlbumAdapter; 13 | import com.cncoderx.test.recyclerviewhelper.data.Album; 14 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 15 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * @author cncoderx 21 | */ 22 | public class LoadMoreActivity extends RecyclerViewActivity { 23 | AlbumAdapter mAdapter; 24 | 25 | @Override 26 | protected void onLayoutManagerChanged(Layout layout) { 27 | super.onLayoutManagerChanged(layout); 28 | switch (layout) { 29 | case linear: 30 | mAdapter = new AlbumAdapter(R.layout.item_album_linear_layout, AlbumManager.obtainAlbumList(0, 10)); 31 | break; 32 | case grid: 33 | mAdapter = new AlbumAdapter(R.layout.item_album_grid_layout, AlbumManager.obtainAlbumList(0, 10)); 34 | break; 35 | case staggered: 36 | mAdapter = new AlbumAdapter(R.layout.item_album_staggered_layout, AlbumManager.obtainAlbumList(0, 10)); 37 | break; 38 | } 39 | 40 | RecyclerViewHelper.setAdapter(mRecyclerView, mAdapter); 41 | RecyclerViewHelper.setLoadMoreListener(mRecyclerView, new OnLoadMoreListener() { 42 | @Override 43 | public void load(RecyclerView recyclerView, ILoadingView view) { 44 | new LoadingTask(mAdapter, null, view).execute(); 45 | } 46 | }); 47 | 48 | mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 49 | @Override 50 | public void onRefresh() { 51 | if (!mAdapter.isEmpty()) { 52 | mAdapter.clear(); 53 | } 54 | new LoadingTask(mAdapter, mRefreshLayout, null).execute(); 55 | } 56 | }); 57 | } 58 | 59 | @Override 60 | protected boolean isRefreshable() { 61 | return true; 62 | } 63 | 64 | static class LoadingTask extends AsyncTask> { 65 | AlbumAdapter adapter; 66 | ILoadingView view; 67 | SwipeRefreshLayout refresh; 68 | 69 | public LoadingTask(AlbumAdapter adapter, 70 | @Nullable SwipeRefreshLayout refresh, 71 | @Nullable ILoadingView view) { 72 | this.adapter = adapter; 73 | this.refresh = refresh; 74 | this.view = view; 75 | } 76 | 77 | @Override 78 | protected List doInBackground(Integer... params) { 79 | try { 80 | Thread.sleep(1000); 81 | } catch (InterruptedException e) { 82 | e.printStackTrace(); 83 | } 84 | return AlbumManager.obtainAlbumList(adapter.size(), refresh == null ? 4 : 10); 85 | } 86 | 87 | @Override 88 | protected void onPostExecute(List albums) { 89 | if (refresh != null) 90 | refresh.setRefreshing(false); 91 | 92 | final int count = albums.size(); 93 | if (count == 0) { 94 | if (view != null) 95 | view.gone(); 96 | } else { 97 | adapter.addAll(albums); 98 | if (view != null) 99 | view.hidden(); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.app.ListActivity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.ArrayAdapter; 8 | import android.widget.ListView; 9 | 10 | public class MainActivity extends ListActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setListAdapter(new ArrayAdapter<>(this, 16 | android.R.layout.simple_list_item_1, 17 | android.R.id.text1, 18 | new String[] { 19 | "Item Click/LongClick", 20 | "Header/Footer View", 21 | "Load More Data", 22 | "Expandable Item", 23 | "Swipe Layout", 24 | "Data Filter", 25 | "Multiple View Type" 26 | })); 27 | } 28 | 29 | @Override 30 | protected void onListItemClick(ListView l, View v, int position, long id) { 31 | switch (position) { 32 | case 0: 33 | startActivity(new Intent(this, ItemClickEventActivity.class)); 34 | break; 35 | case 1: 36 | startActivity(new Intent(this, HeaderOrFooterActivity.class)); 37 | break; 38 | case 2: 39 | startActivity(new Intent(this, LoadMoreActivity.class)); 40 | break; 41 | case 3: 42 | startActivity(new Intent(this, ExpandableItemActivity.class)); 43 | break; 44 | case 4: 45 | startActivity(new Intent(this, SwipeLayoutActivity.class)); 46 | break; 47 | case 5: 48 | startActivity(new Intent(this, DataFilterActivity.class)); 49 | break; 50 | case 6: 51 | startActivity(new Intent(this, MultiItemActivity.class)); 52 | break; 53 | default: 54 | break; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/MultiItemActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.os.Bundle; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | 6 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 7 | import com.cncoderx.test.recyclerviewhelper.adapter.MultiAlbumAdapter; 8 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 9 | 10 | public class MultiItemActivity extends RecyclerViewActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | RecyclerView.Adapter adapter = new MultiAlbumAdapter(AlbumManager.obtainAlbumList()); 16 | RecyclerViewHelper.setAdapter(mRecyclerView, adapter); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/RecyclerViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 6 | import androidx.recyclerview.widget.GridLayoutManager; 7 | import androidx.recyclerview.widget.LinearLayoutManager; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 10 | import android.util.TypedValue; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | 14 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 15 | import com.cncoderx.recyclerviewhelper.utils.DividerItemDecoration; 16 | import com.cncoderx.recyclerviewhelper.utils.SpacingItemDecoration; 17 | import com.cncoderx.test.recyclerviewhelper.R; 18 | 19 | /** 20 | * @author cncoderx 21 | */ 22 | public class RecyclerViewActivity extends Activity { 23 | SwipeRefreshLayout mRefreshLayout; 24 | RecyclerView mRecyclerView; 25 | RecyclerView.ItemDecoration mItemDecoration; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_recycler_view); 31 | mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout); 32 | mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); 33 | setLinearLayoutManager(); 34 | mRefreshLayout.setEnabled(isRefreshable()); 35 | } 36 | 37 | protected boolean isRefreshable() { 38 | return false; 39 | } 40 | 41 | @Override 42 | public boolean onCreateOptionsMenu(Menu menu) { 43 | getMenuInflater().inflate(R.menu.menu_layout, menu); 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean onMenuItemSelected(int featureId, MenuItem item) { 49 | switch (item.getItemId()) { 50 | case R.id.action_linear: 51 | setLinearLayoutManager(); 52 | break; 53 | case R.id.action_grid: 54 | setGridLayoutManager(); 55 | break; 56 | case R.id.action_staggered_grid: 57 | setStaggeredGridLayoutManager(); 58 | break; 59 | } 60 | return true; 61 | } 62 | 63 | protected void onLayoutManagerChanged(Layout layout) { 64 | 65 | } 66 | 67 | private void setLinearLayoutManager() { 68 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 69 | 70 | if (mItemDecoration != null) mRecyclerView.removeItemDecoration(mItemDecoration); 71 | mItemDecoration = new DividerItemDecoration(getResources().getDrawable(R.drawable.divider), 72 | (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1f, getResources().getDisplayMetrics())); 73 | mRecyclerView.addItemDecoration(mItemDecoration); 74 | onLayoutManagerChanged(Layout.linear); 75 | } 76 | 77 | private void setGridLayoutManager() { 78 | mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3)); 79 | 80 | if (mItemDecoration != null) mRecyclerView.removeItemDecoration(mItemDecoration); 81 | mItemDecoration = new SpacingItemDecoration( 82 | (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, getResources().getDisplayMetrics())); 83 | mRecyclerView.addItemDecoration(mItemDecoration); 84 | onLayoutManagerChanged(Layout.grid); 85 | } 86 | 87 | private void setStaggeredGridLayoutManager() { 88 | mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)); 89 | 90 | if (mItemDecoration != null) mRecyclerView.removeItemDecoration(mItemDecoration); 91 | mItemDecoration = new SpacingItemDecoration( 92 | (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5f, getResources().getDisplayMetrics())); 93 | mRecyclerView.addItemDecoration(mItemDecoration); 94 | onLayoutManagerChanged(Layout.staggered); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/activity/SwipeLayoutActivity.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.activity; 2 | 3 | import com.cncoderx.recyclerviewhelper.RecyclerViewHelper; 4 | import com.cncoderx.test.recyclerviewhelper.R; 5 | import com.cncoderx.test.recyclerviewhelper.adapter.AlbumSwipeAdapter; 6 | import com.cncoderx.test.recyclerviewhelper.data.AlbumManager; 7 | import com.cncoderx.test.recyclerviewhelper.utils.Layout; 8 | import com.daimajia.swipe.util.Attributes; 9 | 10 | /** 11 | * @author cncoderx 12 | */ 13 | public class SwipeLayoutActivity extends RecyclerViewActivity { 14 | 15 | @Override 16 | protected void onLayoutManagerChanged(Layout layout) { 17 | super.onLayoutManagerChanged(layout); 18 | AlbumSwipeAdapter adapter = null; 19 | switch (layout) { 20 | case linear: 21 | adapter = new AlbumSwipeAdapter(R.layout.item_album_linear_swipe_layout, AlbumManager.obtainAlbumList()); 22 | break; 23 | case grid: 24 | adapter = new AlbumSwipeAdapter(R.layout.item_album_grid_swipe_layout, AlbumManager.obtainAlbumList()); 25 | break; 26 | case staggered: 27 | adapter = new AlbumSwipeAdapter(R.layout.item_album_staggered_swipe_layout, AlbumManager.obtainAlbumList()); 28 | break; 29 | } 30 | adapter.setMode(Attributes.Mode.Multiple); 31 | RecyclerViewHelper.setAdapter(mRecyclerView, adapter); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/adapter/AlbumAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.adapter; 2 | 3 | import androidx.annotation.LayoutRes; 4 | import android.widget.ImageView; 5 | import android.widget.TextView; 6 | 7 | import com.cncoderx.recyclerviewhelper.adapter.ObjectAdapter; 8 | import com.cncoderx.test.recyclerviewhelper.R; 9 | import com.cncoderx.test.recyclerviewhelper.data.Album; 10 | 11 | import java.util.Collection; 12 | 13 | /** 14 | * @author cncoderx 15 | */ 16 | public class AlbumAdapter extends ObjectAdapter { 17 | 18 | public AlbumAdapter(@LayoutRes int resource) { 19 | super(resource); 20 | } 21 | 22 | public AlbumAdapter(@LayoutRes int resource, Album... data) { 23 | super(resource, data); 24 | } 25 | 26 | public AlbumAdapter(@LayoutRes int resource, Collection data) { 27 | super(resource, data); 28 | } 29 | 30 | @Override 31 | public void onBindViewHolder(BaseViewHolder holder, Album album, final int position) { 32 | ImageView ivCover = holder.getView(R.id.cover); 33 | ivCover.setImageResource(album.getCover()); 34 | 35 | TextView ivName = holder.getView(R.id.name); 36 | ivName.setText(album.getName()); 37 | 38 | TextView ivPrice = holder.getView(R.id.price); 39 | ivPrice.setText(album.getPrice()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/adapter/AlbumSwipeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.adapter; 2 | 3 | import androidx.annotation.LayoutRes; 4 | import androidx.annotation.NonNull; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | import com.cncoderx.recyclerviewhelper.adapter.SwipeAdapter; 10 | import com.cncoderx.test.recyclerviewhelper.R; 11 | import com.cncoderx.test.recyclerviewhelper.data.Album; 12 | 13 | import java.util.Collection; 14 | 15 | /** 16 | * @author cncoderx 17 | */ 18 | public class AlbumSwipeAdapter extends SwipeAdapter { 19 | 20 | public AlbumSwipeAdapter(@LayoutRes int resource) { 21 | super(resource); 22 | } 23 | 24 | public AlbumSwipeAdapter(@LayoutRes int resource, @NonNull Album[] objects) { 25 | super(resource, objects); 26 | } 27 | 28 | public AlbumSwipeAdapter(@LayoutRes int resource, @NonNull Collection objects) { 29 | super(resource, objects); 30 | } 31 | 32 | @Override 33 | public void onBindViewHolder(BaseViewHolder holder, Album album, final int position) { 34 | ImageView ivCover = holder.getView(R.id.cover); 35 | ivCover.setImageResource(album.getCover()); 36 | 37 | TextView ivName = holder.getView(R.id.name); 38 | ivName.setText(album.getName()); 39 | 40 | TextView ivPrice = holder.getView(R.id.price); 41 | ivPrice.setText(album.getPrice()); 42 | 43 | View vDelete = holder.getView(R.id.delete); 44 | vDelete.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | remove(position); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/adapter/ExpandableAlbumAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.adapter; 2 | 3 | import androidx.annotation.LayoutRes; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.cncoderx.recyclerviewhelper.adapter.ExpandableAdapter; 12 | import com.cncoderx.test.recyclerviewhelper.R; 13 | import com.cncoderx.test.recyclerviewhelper.data.Album; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * @author cncoderx 19 | */ 20 | public class ExpandableAlbumAdapter extends ExpandableAdapter { 21 | private List mGroupData; 22 | private List> mChildData; 23 | private @LayoutRes int mGroupLayout, mChildLayout; 24 | 25 | public ExpandableAlbumAdapter(List groupData, 26 | List> childData, 27 | @LayoutRes int groupLayout, 28 | @LayoutRes int childLayout) { 29 | mGroupData = groupData; 30 | mChildData = childData; 31 | mGroupLayout = groupLayout; 32 | mChildLayout = childLayout; 33 | } 34 | 35 | @Override 36 | public GroupViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) { 37 | View view = LayoutInflater.from(parent.getContext()).inflate(mGroupLayout, parent, false); 38 | return new GroupViewHolder(view); 39 | } 40 | 41 | @Override 42 | public void onBindGroupViewHolder(GroupViewHolder holder, int groupPosition) { 43 | holder.onBind(mGroupData.get(groupPosition), groupPosition); 44 | } 45 | 46 | @Override 47 | public int getGroupCount() { 48 | return mGroupData.size(); 49 | } 50 | 51 | @Override 52 | public ChildViewHolder onCreateChildViewHolder(ViewGroup parent, int viewType) { 53 | View view = LayoutInflater.from(parent.getContext()).inflate(mChildLayout, parent, false); 54 | return new ChildViewHolder(view); 55 | } 56 | 57 | @Override 58 | public void onBindChildViewHolder(ChildViewHolder holder, int groupPosition, int childPosition) { 59 | holder.onBind(mChildData.get(groupPosition).get(childPosition), groupPosition, childPosition); 60 | } 61 | 62 | @Override 63 | public int getChildCount(int groupPosition) { 64 | return mChildData.get(groupPosition).size(); 65 | } 66 | 67 | static class GroupViewHolder extends RecyclerView.ViewHolder { 68 | TextView mTextView; 69 | 70 | public GroupViewHolder(View itemView) { 71 | super(itemView); 72 | mTextView = (TextView) itemView.findViewById(R.id.text); 73 | } 74 | 75 | public void onBind(String text, int groupPosition) { 76 | mTextView.setText(text); 77 | } 78 | } 79 | 80 | static class ChildViewHolder extends RecyclerView.ViewHolder { 81 | ImageView ivCover; 82 | TextView tvName; 83 | TextView tvPrice; 84 | 85 | public ChildViewHolder(View itemView) { 86 | super(itemView); 87 | ivCover = (ImageView) itemView.findViewById(R.id.cover); 88 | tvName = (TextView) itemView.findViewById(R.id.name); 89 | tvPrice = (TextView) itemView.findViewById(R.id.price); 90 | } 91 | 92 | public void onBind(Album album, int groupPosition, int childPosition) { 93 | ivCover.setImageResource(album.getCover()); 94 | tvName.setText(album.getName()); 95 | tvPrice.setText(album.getPrice()); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/adapter/MultiAlbumAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.adapter; 2 | 3 | import com.cncoderx.test.recyclerviewhelper.R; 4 | import com.cncoderx.test.recyclerviewhelper.data.Album; 5 | 6 | import java.util.Collection; 7 | 8 | public class MultiAlbumAdapter extends AlbumAdapter { 9 | public static final int LINEAR_LAYOUT_VIEW_TYPE = 0; 10 | public static final int GRID_LAYOUT_VIEW_TYPE = 1; 11 | public static final int STAGGERED_LAYOUT_VIEW_TYPE = 2; 12 | 13 | public MultiAlbumAdapter() { 14 | super(0); 15 | } 16 | 17 | public MultiAlbumAdapter(Album... data) { 18 | super(0, data); 19 | } 20 | 21 | public MultiAlbumAdapter(Collection data) { 22 | super(0, data); 23 | } 24 | 25 | @Override 26 | protected int getLayoutResource(int viewType) { 27 | int layoutRes = super.getLayoutResource(viewType); 28 | switch (viewType) { 29 | case LINEAR_LAYOUT_VIEW_TYPE: 30 | layoutRes = R.layout.item_album_linear_layout; 31 | break; 32 | case GRID_LAYOUT_VIEW_TYPE: 33 | layoutRes = R.layout.item_album_grid_layout; 34 | break; 35 | case STAGGERED_LAYOUT_VIEW_TYPE: 36 | layoutRes = R.layout.item_album_staggered_layout; 37 | break; 38 | default: 39 | break; 40 | } 41 | return layoutRes; 42 | } 43 | 44 | @Override 45 | public int getItemViewType(int position) { 46 | int viewType; 47 | switch (position % 3) { 48 | case 1: 49 | viewType = GRID_LAYOUT_VIEW_TYPE; 50 | break; 51 | case 2: 52 | viewType = STAGGERED_LAYOUT_VIEW_TYPE; 53 | break; 54 | case 0: 55 | default: 56 | viewType = LINEAR_LAYOUT_VIEW_TYPE; 57 | break; 58 | } 59 | return viewType; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/data/Album.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.data; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | /** 6 | * @author cncoderx 7 | */ 8 | public class Album { 9 | private int cover; 10 | private String name; 11 | private String price; 12 | private String category; 13 | 14 | public int getCover() { 15 | return cover; 16 | } 17 | 18 | public void setCover(int cover) { 19 | this.cover = cover; 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public void setName(String name) { 27 | this.name = name; 28 | } 29 | 30 | public String getPrice() { 31 | return price; 32 | } 33 | 34 | public void setPrice(String price) { 35 | this.price = price; 36 | } 37 | 38 | public String getCategory() { 39 | return category; 40 | } 41 | 42 | public void setCategory(String category) { 43 | this.category = category; 44 | } 45 | 46 | @NonNull 47 | @Override 48 | public String toString() { 49 | return name; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/data/AlbumManager.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.data; 2 | 3 | import com.cncoderx.test.recyclerviewhelper.R; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author cncoderx 10 | */ 11 | public class AlbumManager { 12 | 13 | public static List obtainAlbumList() { 14 | List albums = new ArrayList<>(); 15 | albums.addAll(ALBUMS); 16 | return albums; 17 | } 18 | 19 | public static List obtainAlbumList(int start, int size) { 20 | List albums = new ArrayList<>(); 21 | int end = Math.min(ALBUMS.size(), start + size); 22 | for (int i = start; i < end; i++) { 23 | albums.add(ALBUMS.get(i)); 24 | } 25 | return albums; 26 | } 27 | 28 | public static List obtainAlbumList(String category) { 29 | List albums = new ArrayList<>(); 30 | for (Album album : ALBUMS) { 31 | if (album.getCategory().equals(category)) 32 | albums.add(album); 33 | } 34 | return albums; 35 | } 36 | 37 | static ArrayList ALBUMS = new ArrayList<>(); 38 | static 39 | { 40 | { 41 | Album album = new Album(); 42 | album.setCover(R.drawable.cover01); 43 | album.setName("Nicola Benedetti - Mendelssohn / MacMillan / Mozart"); 44 | album.setPrice("$15.97"); 45 | album.setCategory("classical"); 46 | ALBUMS.add(album); 47 | } 48 | { 49 | Album album = new Album(); 50 | album.setCover(R.drawable.cover02); 51 | album.setName("Martha Argerich - Argerich Plays Chopin"); 52 | album.setPrice("$15.97"); 53 | album.setCategory("classical"); 54 | ALBUMS.add(album); 55 | } 56 | { 57 | Album album = new Album(); 58 | album.setCover(R.drawable.cover03); 59 | album.setName("Alfred Brendel - Beethoven: Piano Concerto No.5 \"Emperor\" / Piano Sonata No.23 \"Appassionata\""); 60 | album.setPrice("$15.97"); 61 | album.setCategory("classical"); 62 | ALBUMS.add(album); 63 | } 64 | { 65 | Album album = new Album(); 66 | album.setCover(R.drawable.cover04); 67 | album.setName("Various Artists - Figure Skating's Greatest Hits"); 68 | album.setPrice("$15.97"); 69 | album.setCategory("classical"); 70 | ALBUMS.add(album); 71 | } 72 | { 73 | Album album = new Album(); 74 | album.setCover(R.drawable.cover05); 75 | album.setName("Brett Eldredge - Brett Eldredge"); 76 | album.setPrice("$12.88"); 77 | album.setCategory("country"); 78 | ALBUMS.add(album); 79 | } 80 | { 81 | Album album = new Album(); 82 | album.setCover(R.drawable.cover06); 83 | album.setName("Chris Stapleton - From A Room Vol. 1"); 84 | album.setPrice("$10"); 85 | album.setCategory("country"); 86 | ALBUMS.add(album); 87 | } 88 | { 89 | Album album = new Album(); 90 | album.setCover(R.drawable.cover07); 91 | album.setName("Dean Brody - Beautiful Freakshow"); 92 | album.setPrice("$12.88"); 93 | album.setCategory("country"); 94 | ALBUMS.add(album); 95 | } 96 | { 97 | Album album = new Album(); 98 | album.setCover(R.drawable.cover08); 99 | album.setName("Cinque - Catch A Corner"); 100 | album.setPrice("$15.97"); 101 | album.setCategory("jazz"); 102 | ALBUMS.add(album); 103 | } 104 | { 105 | Album album = new Album(); 106 | album.setCover(R.drawable.cover09); 107 | album.setName("The Paul Desmond Quartet - Like Someone In Love"); 108 | album.setPrice("$9.97"); 109 | album.setCategory("jazz"); 110 | ALBUMS.add(album); 111 | } 112 | { 113 | Album album = new Album(); 114 | album.setCover(R.drawable.cover10); 115 | album.setName("Count Basie - The Jazz Biography"); 116 | album.setPrice("$5.97"); 117 | album.setCategory("jazz"); 118 | ALBUMS.add(album); 119 | } 120 | { 121 | Album album = new Album(); 122 | album.setCover(R.drawable.cover11); 123 | album.setName("The Chainsmokers - Memories… Do Not Open"); 124 | album.setPrice("$12.88"); 125 | album.setCategory("pop"); 126 | ALBUMS.add(album); 127 | } 128 | { 129 | Album album = new Album(); 130 | album.setCover(R.drawable.cover12); 131 | album.setName("Taylor Swift - Fearless"); 132 | album.setPrice("$10"); 133 | album.setCategory("pop"); 134 | ALBUMS.add(album); 135 | } 136 | { 137 | Album album = new Album(); 138 | album.setCover(R.drawable.cover13); 139 | album.setName("Sara Bareilles - The Blessed Unrest"); 140 | album.setPrice("$8"); 141 | album.setCategory("pop"); 142 | ALBUMS.add(album); 143 | } 144 | { 145 | Album album = new Album(); 146 | album.setCover(R.drawable.cover14); 147 | album.setName("Miley Cyrus - The Time Of Our Lives (Walmart Exclusive)"); 148 | album.setPrice("$8"); 149 | album.setCategory("pop"); 150 | ALBUMS.add(album); 151 | } 152 | { 153 | Album album = new Album(); 154 | album.setCover(R.drawable.cover15); 155 | album.setName("Little Mix - DNA"); 156 | album.setPrice("$12.88"); 157 | album.setCategory("pop"); 158 | ALBUMS.add(album); 159 | } 160 | { 161 | Album album = new Album(); 162 | album.setCover(R.drawable.cover16); 163 | album.setName("The Summer Set - Everything's Fine"); 164 | album.setPrice("$8.97"); 165 | album.setCategory("pop"); 166 | ALBUMS.add(album); 167 | } 168 | { 169 | Album album = new Album(); 170 | album.setCover(R.drawable.cover17); 171 | album.setName("Papa Roach - Crooked Teeth"); 172 | album.setPrice("$12.88"); 173 | album.setCategory("rock"); 174 | ALBUMS.add(album); 175 | } 176 | { 177 | Album album = new Album(); 178 | album.setCover(R.drawable.cover18); 179 | album.setName("Bruce Springsteen - Greatest Hits"); 180 | album.setPrice("$6.97"); 181 | album.setCategory("rock"); 182 | ALBUMS.add(album); 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/utils/Layout.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.utils; 2 | 3 | /** 4 | * @author cncoderx 5 | */ 6 | public enum Layout { 7 | linear, grid, staggered 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/cncoderx/test/recyclerviewhelper/utils/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.test.recyclerviewhelper.utils; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | 8 | public class SquareImageView extends ImageView { 9 | 10 | public SquareImageView(Context context) { 11 | super(context); 12 | } 13 | 14 | public SquareImageView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | public SquareImageView(Context context, AttributeSet attrs, int defStyle) { 19 | super(context, attrs, defStyle); 20 | } 21 | 22 | @Override 23 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 24 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 25 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 26 | if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) { 27 | int width = MeasureSpec.getSize(widthMeasureSpec); 28 | int height = width; 29 | if (heightMode == MeasureSpec.AT_MOST) { 30 | height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec)); 31 | } 32 | setMeasuredDimension(width, height); 33 | }else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) { 34 | int height = MeasureSpec.getSize(heightMeasureSpec); 35 | int width = height; 36 | if (widthMode == MeasureSpec.AT_MOST) { 37 | width = Math.min(width, MeasureSpec.getSize(widthMeasureSpec)); 38 | } 39 | setMeasuredDimension(width, height); 40 | } else { 41 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover01.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover02.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover03.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover04.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover05.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover06.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover07.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover08.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover09.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover11.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover12.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover13.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover14.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover15.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover16.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover17.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-nodpi/cover18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/drawable-nodpi/cover18.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_grid_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 24 | 25 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_grid_swipe_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_linear_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 28 | 29 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_linear_swipe_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_staggered_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_staggered_swipe_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 23 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_expandable_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_footer_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_header_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 16 | 17 | 21 | 22 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #e0e0e0 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RecyclerViewHelper 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/test/java/com/cncoderx/recyclerview/helper/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerview.helper; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 12 | */ 13 | public class ExampleUnitTest { 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | 18 | ArrayList array = new ArrayList<>(); 19 | for (int i = 0; i < 10; i++) { 20 | array.add(i); 21 | } 22 | 23 | System.out.println(Arrays.toString(array.toArray())); 24 | 25 | array.add(array.size(), 10); 26 | 27 | System.out.println(Arrays.toString(array.toArray())); 28 | } 29 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.6.3' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0' 14 | classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.7.2" 15 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | google() 23 | maven { url "https://jitpack.io" } 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | android.enableJetifier=true 20 | android.useAndroidX=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CNCoderX/RecyclerViewHelper/9fab4cf2ada4652be455838164cee2403bc58b36/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/bintray.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | def siteUrl = 'https://github.com/CNCoderX/RecyclerViewHelper' 5 | def gitUrl = 'https://github.com/CNCoderX/RecyclerViewHelper.git' 6 | 7 | version = "1.2.2" 8 | group = "com.cncoderx.recyclerviewhelper" 9 | def libName = "RecyclerViewHelper" 10 | def libDesc = "the RecyclerView helper" 11 | 12 | task sourcesJar(type: Jar) { 13 | from android.sourceSets.main.java.srcDirs 14 | classifier = 'sources' 15 | } 16 | 17 | task javadoc(type: Javadoc) { 18 | source = android.sourceSets.main.java.srcDirs 19 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 20 | options.encoding "UTF-8" 21 | options.charSet 'UTF-8' 22 | options.author true 23 | options.version true 24 | //options.links "" 25 | failOnError false 26 | } 27 | 28 | task javadocJar(type: Jar, dependsOn: javadoc) { 29 | classifier = 'javadoc' 30 | from javadoc.destinationDir 31 | } 32 | 33 | task copyDoc(type: Copy) { 34 | from "${buildDir}/docs/" 35 | into "docs" 36 | } 37 | 38 | artifacts { 39 | archives javadocJar 40 | archives sourcesJar 41 | } 42 | 43 | install { 44 | repositories.mavenInstaller { 45 | // This generates POM.xml with proper parameters 46 | pom { 47 | project { 48 | packaging 'aar' 49 | name libDesc 50 | url siteUrl 51 | licenses { 52 | license { 53 | name libDesc 54 | url siteUrl 55 | } 56 | } 57 | developers { 58 | developer { 59 | id 'cncoderx' 60 | name 'cncoderx' 61 | email 'wujie59585@foxmail.com' 62 | } 63 | } 64 | scm { 65 | connection gitUrl 66 | developerConnection gitUrl 67 | url siteUrl 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | Properties properties = new Properties() 75 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 76 | bintray { 77 | user = properties.getProperty("bintray.user") 78 | key = properties.getProperty("bintray.apikey") 79 | configurations = ['archives'] 80 | pkg { 81 | repo = "maven" 82 | name = libName 83 | desc = libDesc 84 | websiteUrl = siteUrl 85 | vcsUrl = gitUrl 86 | licenses = ["Apache-2.0"] 87 | publish = true 88 | } 89 | } -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | 4 | android { 5 | compileSdkVersion 29 6 | buildToolsVersion "29.0.3" 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.4" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | // compileOptions { 21 | // sourceCompatibility JavaVersion.VERSION_1_8 22 | // targetCompatibility JavaVersion.VERSION_1_8 23 | // } 24 | lintOptions { 25 | abortOnError false 26 | checkReleaseBuilds false 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | testImplementation 'junit:junit:4.12' 33 | compileOnly 'androidx.recyclerview:recyclerview:1.1.0' 34 | compileOnly 'com.daimajia.swipelayout:library:1.2.0@aar' 35 | } 36 | 37 | // apply from: 'bintray.gradle' 38 | -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\wujie\AndroidStudio_SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/androidTest/java/com/cncoderx/recyclerviewhelper/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/RecyclerViewHelper.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import androidx.annotation.LayoutRes; 6 | import androidx.annotation.NonNull; 7 | import androidx.recyclerview.widget.GridLayoutManager; 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.widget.Filter; 14 | 15 | import com.cncoderx.recyclerviewhelper.adapter.DelegateAdapter; 16 | import com.cncoderx.recyclerviewhelper.listener.EndlessScrollListener; 17 | import com.cncoderx.recyclerviewhelper.listener.OnItemClickListener; 18 | import com.cncoderx.recyclerviewhelper.listener.OnItemLongClickListener; 19 | import com.cncoderx.recyclerviewhelper.listener.OnLoadMoreListener; 20 | import com.cncoderx.recyclerviewhelper.utils.DividerItemDecoration; 21 | import com.cncoderx.recyclerviewhelper.utils.ILoadingView; 22 | import com.cncoderx.recyclerviewhelper.utils.SpacingItemDecoration; 23 | 24 | /** 25 | * @author cncoderx 26 | */ 27 | public class RecyclerViewHelper { 28 | 29 | public static void setLinearLayout(@NonNull RecyclerView recyclerView) { 30 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext())); 31 | } 32 | 33 | public static void setLinearLayout(@NonNull RecyclerView recyclerView, int orientation) { 34 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext(), orientation, false)); 35 | } 36 | 37 | public static void setLinearLayout(@NonNull RecyclerView recyclerView, int orientation, boolean reverseLayout) { 38 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext(), orientation, reverseLayout)); 39 | } 40 | 41 | public static void setGridLayout(@NonNull RecyclerView recyclerView, int spanCount) { 42 | recyclerView.setLayoutManager(new GridLayoutManager(recyclerView.getContext(), spanCount)); 43 | } 44 | 45 | public static void setGridLayout(@NonNull RecyclerView recyclerView, int spanCount, int orientation) { 46 | recyclerView.setLayoutManager(new GridLayoutManager(recyclerView.getContext(), spanCount, orientation, false)); 47 | } 48 | 49 | public static void setGridLayout(@NonNull RecyclerView recyclerView, int spanCount, int orientation, boolean reverseLayout) { 50 | recyclerView.setLayoutManager(new GridLayoutManager(recyclerView.getContext(), spanCount, orientation, reverseLayout)); 51 | } 52 | 53 | public static void setStaggeredGridLayout(@NonNull RecyclerView recyclerView, int spanCount) { 54 | recyclerView.setLayoutManager(new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL)); 55 | } 56 | 57 | public static void setStaggeredGridLayout(@NonNull RecyclerView recyclerView, int spanCount, int orientation) { 58 | recyclerView.setLayoutManager(new StaggeredGridLayoutManager(spanCount, orientation)); 59 | } 60 | 61 | public static void setAdapter(@NonNull RecyclerView recyclerView, RecyclerView.Adapter adapter) { 62 | if (adapter == null || adapter instanceof DelegateAdapter) { 63 | recyclerView.setAdapter(adapter); 64 | } else { 65 | recyclerView.setAdapter(new DelegateAdapter(adapter)); 66 | } 67 | } 68 | 69 | public static RecyclerView.Adapter getAdapter(@NonNull RecyclerView recyclerView) { 70 | RecyclerView.Adapter adapter = recyclerView.getAdapter(); 71 | if (adapter instanceof DelegateAdapter) { 72 | return ((DelegateAdapter) adapter).getWrappedAdapter(); 73 | } 74 | return adapter; 75 | } 76 | 77 | public static void addHeaderView(@NonNull RecyclerView recyclerView, View headerView) { 78 | obtainProxyAdapter(recyclerView, "addHeaderView()").addHeaderView(headerView); 79 | } 80 | 81 | public static void addHeaderView(@NonNull RecyclerView recyclerView, View headerView, boolean isFullSpan) { 82 | obtainProxyAdapter(recyclerView, "addHeaderView()").addHeaderView(headerView, isFullSpan); 83 | } 84 | 85 | public static void removeHeaderView(@NonNull RecyclerView recyclerView, View headerView) { 86 | obtainProxyAdapter(recyclerView, "removeHeaderView()").removeHeaderView(headerView); 87 | } 88 | 89 | public static void addFooterView(@NonNull RecyclerView recyclerView, View footerView) { 90 | obtainProxyAdapter(recyclerView, "addFooterView()").addFooterView(footerView); 91 | } 92 | 93 | public static void addFooterView(@NonNull RecyclerView recyclerView, View footerView, boolean isFullSpan) { 94 | obtainProxyAdapter(recyclerView, "addFooterView()").addFooterView(footerView, isFullSpan); 95 | } 96 | 97 | public static void removeFooterView(@NonNull RecyclerView recyclerView, View footerView) { 98 | obtainProxyAdapter(recyclerView, "removeFooterView()").removeFooterView(footerView); 99 | } 100 | 101 | @Deprecated 102 | public static RecyclerView.ItemDecoration setDivider(@NonNull RecyclerView recyclerView, Drawable divider, int dividerHeight) { 103 | RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(divider, dividerHeight); 104 | recyclerView.addItemDecoration(itemDecoration); 105 | return itemDecoration; 106 | } 107 | 108 | @Deprecated 109 | public static RecyclerView.ItemDecoration setSpace(@NonNull RecyclerView recyclerView, int space) { 110 | RecyclerView.ItemDecoration itemDecoration = new SpacingItemDecoration(space); 111 | recyclerView.addItemDecoration(itemDecoration); 112 | return itemDecoration; 113 | } 114 | 115 | public static void setOnItemClickListener(@NonNull RecyclerView recyclerView, OnItemClickListener listener) { 116 | obtainProxyAdapter(recyclerView, "setOnItemClickListener()").setOnItemClickListener(listener); 117 | } 118 | 119 | public static void setOnItemLongClickListener(@NonNull RecyclerView recyclerView, OnItemLongClickListener listener) { 120 | obtainProxyAdapter(recyclerView, "setOnItemLongClickListener()").setOnItemLongClickListener(listener); 121 | } 122 | 123 | public static void setLoadMoreListener(@NonNull RecyclerView recyclerView, OnLoadMoreListener listener) { 124 | setLoadMoreListener(recyclerView, R.layout.layout_loading_view, listener); 125 | } 126 | 127 | public static void setLoadMoreListener(@NonNull RecyclerView recyclerView, @LayoutRes int loadingLayout, OnLoadMoreListener listener) { 128 | if (listener == null) return; 129 | if (loadingLayout == 0) { 130 | recyclerView.addOnScrollListener(new EndlessScrollListener(listener)); 131 | } else { 132 | ILoadingView loadingView = createLoadingView(recyclerView, loadingLayout, true); 133 | recyclerView.addOnScrollListener(new EndlessScrollListener(listener, loadingView)); 134 | } 135 | } 136 | 137 | public static void setLoadMoreListener(@NonNull RecyclerView recyclerView, ILoadingView loadingView, OnLoadMoreListener listener) { 138 | if (listener == null) return; 139 | recyclerView.addOnScrollListener(new EndlessScrollListener(listener, loadingView)); 140 | } 141 | 142 | private static ILoadingView createLoadingView(@NonNull RecyclerView recyclerView, @LayoutRes int layout, boolean attached) { 143 | Context context = recyclerView.getContext(); 144 | DelegateAdapter delegateAdapter = obtainProxyAdapter(recyclerView, "createLoadingView()"); 145 | View view = LayoutInflater.from(context).inflate(layout, recyclerView, false); 146 | return delegateAdapter.createLoadViewHolder(view, true); 147 | } 148 | 149 | public static ILoadingView getLoadingView(@NonNull RecyclerView recyclerView) { 150 | DelegateAdapter delegateAdapter = obtainProxyAdapter(recyclerView, "showLoading()"); 151 | return delegateAdapter.getLoadingView(); 152 | } 153 | 154 | public static void setFilterText(@NonNull RecyclerView recyclerView, String filterText) { 155 | Filter filter = obtainProxyAdapter(recyclerView, "setFilterText()").getFilter(); 156 | if (filter != null) { 157 | filter.filter(filterText); 158 | } 159 | } 160 | 161 | private static DelegateAdapter obtainProxyAdapter(@NonNull RecyclerView recyclerView, String methodName) { 162 | RecyclerView.Adapter adapter = recyclerView.getAdapter(); 163 | if (adapter == null) { 164 | throw new IllegalStateException("you must set adapter by RecyclerViewHelper.setAdapter() before call " + methodName); 165 | } 166 | if (!(adapter instanceof DelegateAdapter)) { 167 | throw new IllegalStateException("call RecyclerViewHelper.setAdapter() instead of RecyclerView.setAdapter()"); 168 | } 169 | return (DelegateAdapter) adapter; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ArrayAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.widget.TextView; 4 | 5 | import androidx.annotation.IdRes; 6 | import androidx.annotation.LayoutRes; 7 | import androidx.annotation.NonNull; 8 | 9 | import java.util.Collection; 10 | 11 | /** 12 | * @author cncoderx 13 | */ 14 | public class ArrayAdapter extends ObjectAdapter { 15 | private int mFieldId = android.R.id.text1; 16 | 17 | public ArrayAdapter(@LayoutRes int resource) { 18 | super(resource); 19 | } 20 | 21 | public ArrayAdapter(@LayoutRes int resource, @IdRes int textViewResourceId) { 22 | super(resource); 23 | mFieldId = textViewResourceId; 24 | } 25 | 26 | public ArrayAdapter(@LayoutRes int resource, @NonNull T... objects) { 27 | super(resource, objects); 28 | } 29 | 30 | public ArrayAdapter(@LayoutRes int resource, @NonNull Collection objects) { 31 | super(resource, objects); 32 | } 33 | 34 | public ArrayAdapter(@LayoutRes int resource, @IdRes int textViewResourceId, @NonNull T... objects) { 35 | super(resource, objects); 36 | mFieldId = textViewResourceId; 37 | } 38 | 39 | public ArrayAdapter(@LayoutRes int resource, @IdRes int textViewResourceId, @NonNull Collection objects) { 40 | super(resource, objects); 41 | mFieldId = textViewResourceId; 42 | } 43 | 44 | @Override 45 | public void onBindViewHolder(BaseViewHolder holder, T object, int position) { 46 | TextView text = holder.getView(mFieldId, TextView.class); 47 | if (object instanceof CharSequence) { 48 | text.setText((CharSequence) object); 49 | } else { 50 | text.setText(object.toString()); 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/BaseAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.annotation.IdRes; 6 | import androidx.annotation.NonNull; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | import android.util.SparseArray; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | /** 14 | * @author cncoderx 15 | */ 16 | public abstract class BaseAdapter extends RecyclerView.Adapter { 17 | 18 | @Override 19 | public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 20 | LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 21 | View itemView = onCreateView(inflater, parent, viewType); 22 | return new BaseViewHolder(itemView); 23 | } 24 | 25 | protected abstract View onCreateView(LayoutInflater inflater, ViewGroup parent, int viewType); 26 | 27 | public static class BaseViewHolder extends RecyclerView.ViewHolder { 28 | private SparseArray mIDArray = new SparseArray<>(); 29 | 30 | public Object object; 31 | 32 | public BaseViewHolder(View itemView) { 33 | super(itemView); 34 | } 35 | 36 | public Context getContext() { 37 | return itemView.getContext(); 38 | } 39 | 40 | public @NonNull T getView(@IdRes int id) { 41 | View v = mIDArray.get(id); 42 | if (v == null) { 43 | v = itemView.findViewById(id); 44 | if (v == null) { 45 | throw new RuntimeException("Failed to find view with ID " 46 | + itemView.getResources().getResourceName(id) 47 | + " in item layout"); 48 | } 49 | mIDArray.put(id, v); 50 | } 51 | //noinspection unchecked 52 | return (T) v; 53 | } 54 | 55 | @Deprecated 56 | public @NonNull T getView(@IdRes int id, Class clazz) { 57 | View v = mIDArray.get(id); 58 | if (v == null) { 59 | v = itemView.findViewById(id); 60 | if (v == null) { 61 | throw new RuntimeException("Failed to find view with ID " 62 | + itemView.getResources().getResourceName(id) 63 | + " in item layout"); 64 | } 65 | mIDArray.put(id, v); 66 | } 67 | //noinspection unchecked 68 | return (T) v; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/CursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.database.ContentObserver; 4 | import android.database.Cursor; 5 | import android.database.DataSetObserver; 6 | import android.os.Handler; 7 | import androidx.annotation.WorkerThread; 8 | import android.util.Log; 9 | import android.widget.Filter; 10 | import android.widget.FilterQueryProvider; 11 | import android.widget.Filterable; 12 | 13 | /** 14 | * @author cncoderx 15 | */ 16 | public abstract class CursorAdapter extends BaseAdapter implements Filterable, 17 | CursorFilter.CursorFilterClient { 18 | 19 | protected boolean mDataValid; 20 | protected boolean mAutoRequery; 21 | protected Cursor mCursor; 22 | protected int mRowIDColumn; 23 | protected ChangeObserver mChangeObserver; 24 | protected DataSetObserver mDataSetObserver; 25 | protected CursorFilter mCursorFilter; 26 | protected FilterQueryProvider mFilterQueryProvider; 27 | 28 | @Deprecated 29 | public static final int FLAG_AUTO_REQUERY = 0x01; 30 | public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02; 31 | 32 | @Deprecated 33 | public CursorAdapter(Cursor c) { 34 | init(c, FLAG_AUTO_REQUERY); 35 | } 36 | 37 | public CursorAdapter(Cursor c, boolean autoRequery) { 38 | init(c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER); 39 | } 40 | 41 | public CursorAdapter(Cursor c, int flags) { 42 | init(c, flags); 43 | } 44 | 45 | @Deprecated 46 | protected void init(Cursor c, boolean autoRequery) { 47 | init(c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER); 48 | } 49 | 50 | void init(Cursor c, int flags) { 51 | if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) { 52 | flags |= FLAG_REGISTER_CONTENT_OBSERVER; 53 | mAutoRequery = true; 54 | } else { 55 | mAutoRequery = false; 56 | } 57 | boolean cursorPresent = c != null; 58 | mCursor = c; 59 | mDataValid = cursorPresent; 60 | mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1; 61 | if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) { 62 | mChangeObserver = new ChangeObserver(); 63 | mDataSetObserver = new MyDataSetObserver(); 64 | } else { 65 | mChangeObserver = null; 66 | mDataSetObserver = null; 67 | } 68 | 69 | if (cursorPresent) { 70 | if (mChangeObserver != null) c.registerContentObserver(mChangeObserver); 71 | if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver); 72 | } 73 | 74 | setHasStableIds(true); 75 | } 76 | 77 | public Cursor getCursor() { 78 | return mCursor; 79 | } 80 | 81 | @Override 82 | public int getItemCount() { 83 | if (mDataValid && mCursor != null) { 84 | return mCursor.getCount(); 85 | } else { 86 | return 0; 87 | } 88 | } 89 | 90 | public Object getItem(int position) { 91 | if (mDataValid && mCursor != null) { 92 | mCursor.moveToPosition(position); 93 | return mCursor; 94 | } else { 95 | return null; 96 | } 97 | } 98 | 99 | @Override 100 | public long getItemId(int position) { 101 | if (mDataValid && mCursor != null) { 102 | if (mCursor.moveToPosition(position)) { 103 | return mCursor.getLong(mRowIDColumn); 104 | } else { 105 | return 0; 106 | } 107 | } else { 108 | return 0; 109 | } 110 | } 111 | 112 | @Override 113 | public final void setHasStableIds(boolean hasStableIds) { 114 | super.setHasStableIds(true); 115 | } 116 | 117 | @Override 118 | public void onBindViewHolder(BaseViewHolder holder, int position) { 119 | if (!mDataValid) { 120 | throw new IllegalStateException("this should only be called when the cursor is valid"); 121 | } 122 | if (!mCursor.moveToPosition(position)) { 123 | throw new IllegalStateException("couldn't move cursor to position " + position); 124 | } 125 | onBindViewHolder(holder, mCursor); 126 | } 127 | 128 | public abstract void onBindViewHolder(BaseViewHolder holder, Cursor cursor); 129 | 130 | @Override 131 | public void changeCursor(Cursor cursor) { 132 | Cursor old = swapCursor(cursor); 133 | if (old != null) { 134 | old.close(); 135 | } 136 | } 137 | 138 | public Cursor swapCursor(Cursor newCursor) { 139 | if (newCursor == mCursor) { 140 | return null; 141 | } 142 | Cursor oldCursor = mCursor; 143 | if (oldCursor != null) { 144 | if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver); 145 | if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver); 146 | } 147 | mCursor = newCursor; 148 | if (newCursor != null) { 149 | if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver); 150 | if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver); 151 | mRowIDColumn = newCursor.getColumnIndexOrThrow("_id"); 152 | mDataValid = true; 153 | // notify the observers about the new cursor 154 | notifyDataSetChanged(); 155 | } else { 156 | mRowIDColumn = -1; 157 | mDataValid = false; 158 | // notify the observers about the lack of a data set 159 | notifyDataSetChanged(); 160 | } 161 | return oldCursor; 162 | } 163 | 164 | public CharSequence convertToString(Cursor cursor) { 165 | return cursor == null ? "" : cursor.toString(); 166 | } 167 | 168 | 169 | @WorkerThread 170 | public Cursor runQueryOnBackgroundThread(CharSequence constraint) { 171 | if (mFilterQueryProvider != null) { 172 | return mFilterQueryProvider.runQuery(constraint); 173 | } 174 | 175 | return mCursor; 176 | } 177 | 178 | public Filter getFilter() { 179 | if (mCursorFilter == null) { 180 | mCursorFilter = new CursorFilter(this); 181 | } 182 | return mCursorFilter; 183 | } 184 | 185 | public FilterQueryProvider getFilterQueryProvider() { 186 | return mFilterQueryProvider; 187 | } 188 | 189 | public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) { 190 | mFilterQueryProvider = filterQueryProvider; 191 | } 192 | 193 | protected void onContentChanged() { 194 | if (mAutoRequery && mCursor != null && !mCursor.isClosed()) { 195 | if (false) Log.v("Cursor", "Auto requerying " + mCursor + " due to update"); 196 | mDataValid = mCursor.requery(); 197 | } 198 | } 199 | 200 | private class ChangeObserver extends ContentObserver { 201 | public ChangeObserver() { 202 | super(new Handler()); 203 | } 204 | 205 | @Override 206 | public boolean deliverSelfNotifications() { 207 | return true; 208 | } 209 | 210 | @Override 211 | public void onChange(boolean selfChange) { 212 | onContentChanged(); 213 | } 214 | } 215 | 216 | private class MyDataSetObserver extends DataSetObserver { 217 | @Override 218 | public void onChanged() { 219 | mDataValid = true; 220 | notifyDataSetChanged(); 221 | } 222 | 223 | @Override 224 | public void onInvalidated() { 225 | mDataValid = false; 226 | notifyDataSetChanged(); 227 | } 228 | } 229 | } 230 | 231 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/CursorFilter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.database.Cursor; 4 | import android.widget.Filter; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | class CursorFilter extends Filter { 10 | 11 | CursorFilterClient mClient; 12 | 13 | interface CursorFilterClient { 14 | CharSequence convertToString(Cursor cursor); 15 | Cursor runQueryOnBackgroundThread(CharSequence constraint); 16 | Cursor getCursor(); 17 | void changeCursor(Cursor cursor); 18 | } 19 | 20 | CursorFilter(CursorFilterClient client) { 21 | mClient = client; 22 | } 23 | 24 | @Override 25 | public CharSequence convertResultToString(Object resultValue) { 26 | return mClient.convertToString((Cursor) resultValue); 27 | } 28 | 29 | @Override 30 | protected FilterResults performFiltering(CharSequence constraint) { 31 | Cursor cursor = mClient.runQueryOnBackgroundThread(constraint); 32 | 33 | FilterResults results = new FilterResults(); 34 | if (cursor != null) { 35 | results.count = cursor.getCount(); 36 | results.values = cursor; 37 | } else { 38 | results.count = 0; 39 | results.values = null; 40 | } 41 | return results; 42 | } 43 | 44 | @Override 45 | protected void publishResults(CharSequence constraint, FilterResults results) { 46 | Cursor oldCursor = mClient.getCursor(); 47 | 48 | if (results.values != null && results.values != oldCursor) { 49 | mClient.changeCursor((Cursor) results.values); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/DelegateAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import androidx.annotation.IntDef; 4 | import androidx.annotation.IntRange; 5 | import androidx.annotation.NonNull; 6 | import androidx.recyclerview.widget.GridLayoutManager; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.Filter; 12 | import android.widget.Filterable; 13 | 14 | import com.cncoderx.recyclerviewhelper.R; 15 | import com.cncoderx.recyclerviewhelper.listener.OnItemClickListener; 16 | import com.cncoderx.recyclerviewhelper.listener.OnItemLongClickListener; 17 | import com.cncoderx.recyclerviewhelper.utils.ILoadingView; 18 | 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.ref.WeakReference; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | /** 26 | * @author cncoderx 27 | */ 28 | public class DelegateAdapter extends RecyclerView.Adapter implements Filterable { 29 | private List mHeaderViewHolders = new ArrayList<>(); 30 | private List mFooterViewHolders = new ArrayList<>(); 31 | private LoadingViewHolder mLoadViewHolder = null; 32 | 33 | private final RecyclerView.Adapter mAdapter; 34 | 35 | private OnItemClickListener onItemClickListener; 36 | private OnItemLongClickListener onItemLongClickListener; 37 | 38 | public DelegateAdapter(@NonNull RecyclerView.Adapter adapter) { 39 | mAdapter = adapter; 40 | setHasStableIds(adapter.hasStableIds()); 41 | } 42 | 43 | @Override 44 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 45 | RecyclerView.ViewHolder viewHolder; 46 | final int type = ViewTypeSpec.getType(viewType); 47 | final int value = ViewTypeSpec.getValue(viewType); 48 | 49 | if (type == ViewTypeSpec.HEADER) { 50 | viewHolder = mHeaderViewHolders.get(value); 51 | } else if (type == ViewTypeSpec.FOOTER) { 52 | viewHolder = mFooterViewHolders.get(value); 53 | } else if (type == ViewTypeSpec.LOADER){ 54 | viewHolder = mLoadViewHolder; 55 | } else { 56 | viewHolder = mAdapter.onCreateViewHolder(parent, viewType); 57 | if (onItemClickListener != null) { 58 | viewHolder.itemView.setOnClickListener(new ItemClickEvent( 59 | this, (RecyclerView) parent, viewHolder)); 60 | } 61 | if (onItemLongClickListener != null) { 62 | viewHolder.itemView.setOnLongClickListener(new ItemClickEvent( 63 | this, (RecyclerView) parent, viewHolder)); 64 | } 65 | } 66 | return viewHolder; 67 | } 68 | 69 | @Override 70 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 71 | if (holder instanceof FixedViewHolder) { 72 | ((FixedViewHolder) holder).onBind(); 73 | } else { 74 | int adjPosition = position - mHeaderViewHolders.size(); 75 | mAdapter.onBindViewHolder(holder, adjPosition); 76 | } 77 | } 78 | 79 | @Override 80 | public int getItemCount() { 81 | final int itemCount = mAdapter.getItemCount(); 82 | if (itemCount == 0 && mLoadViewHolder != null) { 83 | mLoadViewHolder.mState = ILoadingView.STATE_HIDDEN; 84 | } 85 | if (mLoadViewHolder == null || mLoadViewHolder.getState() == ILoadingView.STATE_GONE) { 86 | return mHeaderViewHolders.size() + mFooterViewHolders.size() + itemCount; 87 | } else { 88 | return mHeaderViewHolders.size() + mFooterViewHolders.size() + itemCount + 1; 89 | } 90 | } 91 | 92 | @Override 93 | public int getItemViewType(int position) { 94 | final int numHeaderView = mHeaderViewHolders.size(); 95 | final int numFooterView = mFooterViewHolders.size(); 96 | 97 | if (position < numHeaderView) 98 | return ViewTypeSpec.makeItemViewTypeSpec(position, ViewTypeSpec.HEADER); 99 | 100 | final int adjPosition = position - numHeaderView; 101 | final int itemCount = mAdapter.getItemCount(); 102 | if (mLoadViewHolder != null && mLoadViewHolder.getState() != ILoadingView.STATE_GONE 103 | && adjPosition == itemCount + numFooterView) { 104 | return ViewTypeSpec.makeItemViewTypeSpec(0, ViewTypeSpec.LOADER); 105 | } 106 | if (adjPosition >= itemCount) 107 | return ViewTypeSpec.makeItemViewTypeSpec(adjPosition - itemCount, ViewTypeSpec.FOOTER); 108 | 109 | int itemViewType = mAdapter.getItemViewType(adjPosition); 110 | if (itemViewType < 0 || itemViewType > (1 << ViewTypeSpec.TYPE_SHIFT) - 1) { 111 | throw new IllegalArgumentException("Invalid item view type: RecyclerView.Adapter.getItemViewType return " + itemViewType); 112 | } 113 | return itemViewType; 114 | } 115 | 116 | @Override 117 | public void onDetachedFromRecyclerView(RecyclerView recyclerView) { 118 | mAdapter.onDetachedFromRecyclerView(recyclerView); 119 | } 120 | 121 | @Override 122 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 123 | mAdapter.onAttachedToRecyclerView(recyclerView); 124 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 125 | if (layoutManager instanceof GridLayoutManager) { 126 | GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; 127 | final int spanCount = gridLayoutManager.getSpanCount(); 128 | final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); 129 | if (spanSizeLookup != null) { 130 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 131 | 132 | @Override 133 | public int getSpanSize(int position) { 134 | return isFullSpan(position) ? spanCount : spanSizeLookup.getSpanSize(position); 135 | } 136 | }); 137 | } 138 | } 139 | } 140 | 141 | private boolean isFullSpan(int position) { 142 | final int numHeaderView = mHeaderViewHolders.size(); 143 | final int numFooterView = mFooterViewHolders.size(); 144 | 145 | if (position < numHeaderView) { 146 | return mHeaderViewHolders.get(position).isFullSpan; 147 | } 148 | 149 | final int adjPosition = position - numHeaderView; 150 | final int itemCount = mAdapter.getItemCount(); 151 | final int lastPosition = adjPosition - itemCount; 152 | if (mLoadViewHolder != null && mLoadViewHolder.getState() != ILoadingView.STATE_GONE 153 | && lastPosition == numFooterView) { 154 | return mLoadViewHolder.isFullSpan; 155 | } 156 | if (lastPosition >= 0 && lastPosition < numFooterView) { 157 | return mFooterViewHolders.get(lastPosition).isFullSpan; 158 | } 159 | return false; 160 | } 161 | 162 | @Override 163 | public void unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { 164 | mAdapter.unregisterAdapterDataObserver(observer); 165 | } 166 | 167 | @Override 168 | public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer) { 169 | mAdapter.registerAdapterDataObserver(observer); 170 | } 171 | 172 | @Override 173 | public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { 174 | if (holder instanceof FixedViewHolder) return; 175 | mAdapter.onViewDetachedFromWindow(holder); 176 | } 177 | 178 | @Override 179 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 180 | if (holder instanceof FixedViewHolder) { 181 | ViewGroup.LayoutParams lParams = holder.itemView.getLayoutParams(); 182 | if (lParams instanceof StaggeredGridLayoutManager.LayoutParams) { 183 | boolean isFullSpan = isFullSpan(holder.getAdapterPosition()); 184 | ((StaggeredGridLayoutManager.LayoutParams) lParams).setFullSpan(isFullSpan); 185 | } 186 | return; 187 | } 188 | mAdapter.onViewAttachedToWindow(holder); 189 | 190 | } 191 | 192 | @Override 193 | public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) { 194 | if (holder instanceof FixedViewHolder) return false; 195 | return mAdapter.onFailedToRecycleView(holder); 196 | } 197 | 198 | @Override 199 | public void onViewRecycled(RecyclerView.ViewHolder holder) { 200 | if (holder instanceof FixedViewHolder) return; 201 | mAdapter.onViewRecycled(holder); 202 | } 203 | 204 | @Override 205 | public long getItemId(int position) { 206 | int adjPosition = position - mHeaderViewHolders.size(); 207 | if (adjPosition >= 0 && adjPosition < mAdapter.getItemCount()) 208 | return mAdapter.getItemId(adjPosition); 209 | 210 | return RecyclerView.NO_ID; 211 | } 212 | 213 | // @Override 214 | // public void setHasStableIds(boolean hasStableIds) { 215 | // mAdapter.setHasStableIds(hasStableIds); 216 | // } 217 | 218 | private boolean isFixedViewType(int viewType) { 219 | final int type = ViewTypeSpec.getType(viewType); 220 | return type == ViewTypeSpec.HEADER || type == ViewTypeSpec.FOOTER; 221 | } 222 | 223 | public void addHeaderView(@NonNull View view) { 224 | addHeaderView(view, true); 225 | } 226 | 227 | public void addHeaderView(@NonNull View view, boolean isFullSpan) { 228 | if (addFixedViewHolder(view, isFullSpan, mHeaderViewHolders)) { 229 | mAdapter.notifyDataSetChanged(); 230 | if (mAdapter instanceof ObjectAdapter) { 231 | int offset = mHeaderViewHolders.size(); 232 | ((ObjectAdapter) mAdapter).setPositionOffset(offset); 233 | } 234 | } 235 | } 236 | 237 | public void removeHeaderView(@NonNull View view) { 238 | if (removeFixedViewHolder(view, mHeaderViewHolders)) { 239 | mAdapter.notifyDataSetChanged(); 240 | if (mAdapter instanceof ObjectAdapter) { 241 | int offset = mHeaderViewHolders.size(); 242 | ((ObjectAdapter) mAdapter).setPositionOffset(offset); 243 | } 244 | } 245 | } 246 | 247 | public void addFooterView(@NonNull View view) { 248 | addFooterView(view, true); 249 | } 250 | 251 | public void addFooterView(@NonNull View view, boolean isFullSpan) { 252 | if (addFixedViewHolder(view, isFullSpan, mFooterViewHolders)) { 253 | mAdapter.notifyDataSetChanged(); 254 | } 255 | } 256 | 257 | public void removeFooterView(@NonNull View view) { 258 | if (removeFixedViewHolder(view, mFooterViewHolders)) { 259 | mAdapter.notifyDataSetChanged(); 260 | } 261 | } 262 | 263 | private boolean addFixedViewHolder(View view, boolean isFullSpan, List where) { 264 | return where.add(new FixedViewHolder(view, isFullSpan)); 265 | } 266 | 267 | private boolean removeFixedViewHolder(View view, List where) { 268 | for (int i = 0, len = where.size(); i < len; i++) { 269 | FixedViewHolder viewHolder = where.get(i); 270 | if (viewHolder.itemView == view) { 271 | where.remove(i); 272 | return true; 273 | } 274 | } 275 | return false; 276 | } 277 | 278 | public LoadingViewHolder createLoadViewHolder(@NonNull View view, boolean isFullSpan) { 279 | mLoadViewHolder = new LoadingViewHolder(this, view, isFullSpan); 280 | return mLoadViewHolder; 281 | } 282 | 283 | public ILoadingView getLoadingView() { 284 | return mLoadViewHolder; 285 | } 286 | 287 | private void notifyLoadingViewInserted() { 288 | int position = mHeaderViewHolders.size() + mFooterViewHolders.size() + mAdapter.getItemCount(); 289 | mAdapter.notifyItemInserted(position); 290 | } 291 | 292 | private void notifyLoadingViewRemoved() { 293 | int position = mHeaderViewHolders.size() + mFooterViewHolders.size() + mAdapter.getItemCount(); 294 | mAdapter.notifyItemRemoved(position); 295 | } 296 | 297 | public OnItemClickListener getOnItemClickListener() { 298 | return onItemClickListener; 299 | } 300 | 301 | public void setOnItemClickListener(OnItemClickListener listener) { 302 | this.onItemClickListener = listener; 303 | } 304 | 305 | public OnItemLongClickListener getOnItemLongClickListener() { 306 | return onItemLongClickListener; 307 | } 308 | 309 | public void setOnItemLongClickListener(OnItemLongClickListener listener) { 310 | this.onItemLongClickListener = listener; 311 | } 312 | 313 | public RecyclerView.Adapter getWrappedAdapter() { 314 | return mAdapter; 315 | } 316 | 317 | @Override 318 | public Filter getFilter() { 319 | return mAdapter instanceof Filterable ? ((Filterable) mAdapter).getFilter() : null; 320 | } 321 | 322 | static class ViewTypeSpec { 323 | static final int TYPE_SHIFT = 30; 324 | static final int TYPE_MASK = 0x3 << TYPE_SHIFT; 325 | 326 | public static final int UNSPECIFIED = 0 << TYPE_SHIFT; 327 | public static final int HEADER = 1 << TYPE_SHIFT; 328 | public static final int FOOTER = 2 << TYPE_SHIFT; 329 | public static final int LOADER = 3 << TYPE_SHIFT; 330 | 331 | @IntDef({UNSPECIFIED, HEADER, FOOTER, LOADER}) 332 | @Retention(RetentionPolicy.SOURCE) 333 | public @interface ViewTypeSpecMode {} 334 | 335 | public static int makeItemViewTypeSpec(@IntRange(from = 0, to = (1 << TYPE_SHIFT) - 1) int value, 336 | @ViewTypeSpecMode int type) { 337 | return (value & ~TYPE_MASK) | (type & TYPE_MASK); 338 | } 339 | 340 | @ViewTypeSpecMode 341 | public static int getType(int viewType) { 342 | //noinspection ResourceType 343 | return (viewType & TYPE_MASK); 344 | } 345 | 346 | public static int getValue(int viewType) { 347 | return (viewType & ~TYPE_MASK); 348 | } 349 | } 350 | 351 | static class FixedViewHolder extends RecyclerView.ViewHolder { 352 | boolean isFullSpan; 353 | 354 | public FixedViewHolder(View view, boolean fullSpan) { 355 | super(view); 356 | isFullSpan = fullSpan; 357 | } 358 | 359 | public void onBind() { 360 | } 361 | } 362 | 363 | static class LoadingViewHolder extends FixedViewHolder implements ILoadingView { 364 | private View vShow; 365 | private View vError; 366 | private View vEnd; 367 | 368 | private int mState; 369 | 370 | final WeakReference mDelegateAdapterProvider; 371 | 372 | public LoadingViewHolder(DelegateAdapter adapter, View view, boolean fullSpan) { 373 | super(view, fullSpan); 374 | mDelegateAdapterProvider = new WeakReference<>(adapter); 375 | vShow = view.findViewById(R.id.loading_view_show); 376 | vError = view.findViewById(R.id.loading_view_error); 377 | vEnd = view.findViewById(R.id.loading_view_end); 378 | hidden(); 379 | } 380 | 381 | @Override 382 | public void show() { 383 | mState = STATE_SHOW; 384 | itemView.setVisibility(View.VISIBLE); 385 | vShow.setVisibility(View.VISIBLE); 386 | vError.setVisibility(View.GONE); 387 | vEnd.setVisibility(View.GONE); 388 | } 389 | 390 | @Override 391 | public void hidden() { 392 | mState = STATE_HIDDEN; 393 | itemView.setVisibility(View.GONE); 394 | vShow.setVisibility(View.GONE); 395 | vError.setVisibility(View.GONE); 396 | vEnd.setVisibility(View.GONE); 397 | } 398 | 399 | @Override 400 | public void error() { 401 | mState = STATE_ERROR; 402 | itemView.setVisibility(View.VISIBLE); 403 | vShow.setVisibility(View.GONE); 404 | vError.setVisibility(View.VISIBLE); 405 | vEnd.setVisibility(View.GONE); 406 | } 407 | 408 | @Override 409 | public void end() { 410 | mState = STATE_END; 411 | itemView.setVisibility(View.VISIBLE); 412 | vShow.setVisibility(View.GONE); 413 | vError.setVisibility(View.GONE); 414 | vEnd.setVisibility(View.VISIBLE); 415 | } 416 | 417 | @Override 418 | public void gone() { 419 | mState = STATE_GONE; 420 | itemView.setVisibility(View.GONE); 421 | vShow.setVisibility(View.GONE); 422 | vError.setVisibility(View.GONE); 423 | vEnd.setVisibility(View.GONE); 424 | 425 | DelegateAdapter delegateAdapter = mDelegateAdapterProvider.get(); 426 | if (delegateAdapter != null) { 427 | delegateAdapter.notifyLoadingViewRemoved(); 428 | } 429 | } 430 | 431 | @Override 432 | public int getState() { 433 | return mState; 434 | } 435 | 436 | @Override 437 | public View getView() { 438 | return itemView; 439 | } 440 | } 441 | 442 | void notifyItemClickListener(RecyclerView parent, View view, int position, long id) { 443 | int adjPosition = position - mHeaderViewHolders.size(); 444 | if (onItemClickListener != null) 445 | onItemClickListener.onItemClick(parent, view, adjPosition, id); 446 | } 447 | 448 | boolean notifyItemLongClickListener(RecyclerView parent, View view, int position, long id) { 449 | int adjPosition = position - mHeaderViewHolders.size(); 450 | if (onItemLongClickListener != null) 451 | return onItemLongClickListener.onItemLongClick(parent, view, adjPosition, id); 452 | 453 | return false; 454 | } 455 | 456 | static class ItemClickEvent implements View.OnClickListener, View.OnLongClickListener { 457 | final WeakReference mDelegateAdapterProvider; 458 | final WeakReference mRecyclerViewProvider; 459 | final WeakReference mViewHolderProvider; 460 | 461 | public ItemClickEvent(DelegateAdapter delegateAdapter, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 462 | this.mDelegateAdapterProvider = new WeakReference<>(delegateAdapter); 463 | this.mRecyclerViewProvider = new WeakReference<>(recyclerView); 464 | this.mViewHolderProvider = new WeakReference<>(viewHolder); 465 | } 466 | 467 | @Override 468 | public void onClick(View v) { 469 | DelegateAdapter delegateAdapter = mDelegateAdapterProvider.get(); 470 | RecyclerView recyclerView = mRecyclerViewProvider.get(); 471 | RecyclerView.ViewHolder viewHolder = mViewHolderProvider.get(); 472 | if (delegateAdapter != null && recyclerView != null && viewHolder != null) { 473 | int position = viewHolder.getLayoutPosition(); 474 | long id = viewHolder.getItemId(); 475 | delegateAdapter.notifyItemClickListener(recyclerView, v, position, id); 476 | } 477 | } 478 | 479 | @Override 480 | public boolean onLongClick(View v) { 481 | DelegateAdapter delegateAdapter = mDelegateAdapterProvider.get(); 482 | RecyclerView recyclerView = mRecyclerViewProvider.get(); 483 | RecyclerView.ViewHolder viewHolder = mViewHolderProvider.get(); 484 | if (delegateAdapter != null && recyclerView != null && viewHolder != null) { 485 | int position = viewHolder.getLayoutPosition(); 486 | long id = viewHolder.getItemId(); 487 | return delegateAdapter.notifyItemLongClickListener(recyclerView, v, position, id); 488 | } 489 | return false; 490 | } 491 | } 492 | } 493 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ExpandableAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import androidx.recyclerview.widget.GridLayoutManager; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 6 | import android.util.SparseBooleanArray; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.cncoderx.recyclerviewhelper.listener.OnChildClickListener; 11 | import com.cncoderx.recyclerviewhelper.listener.OnChildLongClickListener; 12 | import com.cncoderx.recyclerviewhelper.listener.OnGroupClickListener; 13 | import com.cncoderx.recyclerviewhelper.listener.OnGroupLongClickListener; 14 | 15 | /** 16 | * @author cncoderx 17 | */ 18 | public abstract class ExpandableAdapter extends RecyclerView.Adapter { 19 | public static final int VIEW_TYPE_GROUP = 0; 20 | public static final int VIEW_TYPE_CHILD = 1; 21 | 22 | private OnGroupClickListener onGroupClickListener; 23 | private OnChildClickListener onChildClickListener; 24 | private OnGroupLongClickListener onGroupLongClickListener; 25 | private OnChildLongClickListener onChildLongClickListener; 26 | 27 | private SparseBooleanArray mCollapsedPositions = new SparseBooleanArray(); 28 | 29 | public ExpandableAdapter() { 30 | this.onGroupClickListener = new DefaultOnGroupClickListener(); 31 | } 32 | 33 | @Override 34 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 35 | RecyclerView.ViewHolder viewHolder; 36 | if (viewType == VIEW_TYPE_GROUP) { 37 | viewHolder = onCreateGroupViewHolder(parent, viewType); 38 | GroupClickListener listener = new GroupClickListener((RecyclerView) parent, viewHolder); 39 | viewHolder.itemView.setOnClickListener(listener); 40 | viewHolder.itemView.setOnLongClickListener(listener); 41 | } else { 42 | viewHolder = onCreateChildViewHolder(parent, viewType); 43 | ChildClickListener listener = new ChildClickListener((RecyclerView) parent, viewHolder); 44 | viewHolder.itemView.setOnClickListener(listener); 45 | viewHolder.itemView.setOnLongClickListener(listener); 46 | } 47 | return viewHolder; 48 | } 49 | 50 | @Override 51 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 52 | int[] positions = getRelativePositions(position); 53 | if (positions == null) 54 | return; 55 | 56 | if (positions.length == 1) { 57 | onBindGroupViewHolder((GVH) holder, positions[0]); 58 | return; 59 | } 60 | 61 | if (positions.length == 2) { 62 | onBindChildViewHolder((CVH) holder, positions[0], positions[1]); 63 | } 64 | } 65 | 66 | @Override 67 | public final int getItemCount() { 68 | int groupCount = getGroupCount(); 69 | int itemCount = groupCount; 70 | for (int i = 0; i < groupCount; i++) { 71 | if (!isCollapsed(i)) { 72 | itemCount += getChildCount(i); 73 | } 74 | } 75 | return itemCount; 76 | } 77 | 78 | @Override 79 | public long getItemId(int position) { 80 | int[] positions = getRelativePositions(position); 81 | if (positions == null) 82 | return 0; 83 | 84 | if (positions.length == 1) 85 | return getGroupId(positions[0]); 86 | 87 | if (positions.length == 2) 88 | return getChildId(positions[0], positions[1]); 89 | 90 | return 0; 91 | } 92 | 93 | public abstract GVH onCreateGroupViewHolder(ViewGroup parent, int viewType); 94 | 95 | public abstract void onBindGroupViewHolder(GVH holder, int groupPosition); 96 | 97 | public abstract int getGroupCount(); 98 | 99 | public long getGroupId(int groupPosition) { 100 | return 0; 101 | } 102 | 103 | public abstract CVH onCreateChildViewHolder(ViewGroup parent, int viewType); 104 | 105 | public abstract void onBindChildViewHolder(CVH holder, int groupPosition, int childPosition); 106 | 107 | public abstract int getChildCount(int groupPosition); 108 | 109 | public long getChildId(int groupPosition, int childPosition) { 110 | return 0; 111 | } 112 | 113 | @Override 114 | public final int getItemViewType(int position) { 115 | int[] positions = getRelativePositions(position); 116 | if (positions == null) 117 | return 0; 118 | 119 | if (positions.length == 1) 120 | return getGroupViewType(positions[0]); 121 | 122 | if (positions.length == 2) 123 | return getChildViewType(positions[0], positions[1]); 124 | 125 | return 0; 126 | } 127 | 128 | public final int getGroupViewType(int groupPosition) { 129 | return VIEW_TYPE_GROUP; 130 | } 131 | 132 | public int getChildViewType(int groupPosition, int childPosition) { 133 | return VIEW_TYPE_CHILD; 134 | } 135 | 136 | protected int[] getRelativePositions(int position) { 137 | int currentPosition = 0; 138 | int groupCount = getGroupCount(); 139 | for (int i = 0; i < groupCount; i++) { 140 | if (currentPosition == position) { 141 | return new int[] {i}; 142 | } 143 | currentPosition++; 144 | if (isCollapsed(i)) continue; 145 | 146 | int childCount = getChildCount(i); 147 | for (int j = 0; j < childCount; j++) { 148 | if (currentPosition == position) { 149 | return new int[] {i, j}; 150 | } 151 | currentPosition++; 152 | } 153 | } 154 | return null; 155 | } 156 | 157 | public boolean isCollapsed(int groupPosition) { 158 | return mCollapsedPositions.get(groupPosition); 159 | } 160 | 161 | public boolean collapse(int groupPosition) { 162 | if (isCollapsed(groupPosition)) return false; 163 | 164 | int childCount = getChildCount(groupPosition); 165 | int startPos = getAbsoluteGroupPosition(groupPosition) + 1; 166 | notifyItemRangeRemoved(startPos, childCount); 167 | mCollapsedPositions.put(groupPosition, true); 168 | return true; 169 | } 170 | 171 | public boolean expand(int groupPosition) { 172 | if (!isCollapsed(groupPosition)) return false; 173 | 174 | int childCount = getChildCount(groupPosition); 175 | int startPos = getAbsoluteGroupPosition(groupPosition) + 1; 176 | notifyItemRangeInserted(startPos, childCount); 177 | mCollapsedPositions.put(groupPosition, false); 178 | return true; 179 | } 180 | 181 | public void collapseAll() { 182 | int groupCount = getGroupCount(); 183 | for (int i = 0; i < groupCount; i++) { 184 | mCollapsedPositions.put(i, true); 185 | } 186 | notifyDataSetChanged(); 187 | } 188 | 189 | public void expandAll() { 190 | int groupCount = getGroupCount(); 191 | for (int i = 0; i < groupCount; i++) { 192 | mCollapsedPositions.put(i, false); 193 | } 194 | notifyDataSetChanged(); 195 | } 196 | 197 | private int getAbsoluteGroupPosition(int groupPosition) { 198 | int position = 0; 199 | for (int i = 0; i < groupPosition; i++) { 200 | position++; 201 | if (!isCollapsed(i)) { 202 | position += getChildCount(i); 203 | } 204 | } 205 | return position; 206 | } 207 | 208 | @Override 209 | public void onAttachedToRecyclerView(RecyclerView recyclerView) { 210 | super.onAttachedToRecyclerView(recyclerView); 211 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 212 | if (layoutManager != null && layoutManager instanceof GridLayoutManager) { 213 | GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; 214 | final int spanCount = gridLayoutManager.getSpanCount(); 215 | final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup(); 216 | if (spanSizeLookup != null) { 217 | gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 218 | 219 | @Override 220 | public int getSpanSize(int position) { 221 | return getItemViewType(position) == VIEW_TYPE_GROUP ? 222 | spanCount : spanSizeLookup.getSpanSize(position); 223 | } 224 | }); 225 | } 226 | } 227 | } 228 | 229 | @Override 230 | public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { 231 | super.onViewAttachedToWindow(holder); 232 | ViewGroup.LayoutParams lParams = holder.itemView.getLayoutParams(); 233 | if (lParams instanceof StaggeredGridLayoutManager.LayoutParams) { 234 | boolean isFullSpan = getItemViewType(holder.getAdapterPosition()) == VIEW_TYPE_GROUP; 235 | ((StaggeredGridLayoutManager.LayoutParams) lParams).setFullSpan(isFullSpan); 236 | } 237 | } 238 | 239 | public OnGroupClickListener getOnGroupClickListener() { 240 | return onGroupClickListener; 241 | } 242 | 243 | public void setOnGroupClickListener(OnGroupClickListener listener) { 244 | onGroupClickListener = listener; 245 | } 246 | 247 | public OnChildClickListener getOnChildClickListener() { 248 | return onChildClickListener; 249 | } 250 | 251 | public void setOnChildClickListener(OnChildClickListener listener) { 252 | onChildClickListener = listener; 253 | } 254 | 255 | public OnGroupLongClickListener getOnGroupLongClickListener() { 256 | return onGroupLongClickListener; 257 | } 258 | 259 | public void setOnGroupLongClickListener(OnGroupLongClickListener listener) { 260 | onGroupLongClickListener = listener; 261 | } 262 | 263 | public OnChildLongClickListener getOnChildLongClickListener() { 264 | return onChildLongClickListener; 265 | } 266 | 267 | public void setOnChildLongClickListener(OnChildLongClickListener listener) { 268 | onChildLongClickListener = listener; 269 | } 270 | 271 | class GroupClickListener implements View.OnClickListener, View.OnLongClickListener { 272 | final RecyclerView mParent; 273 | final RecyclerView.ViewHolder mViewHolder; 274 | 275 | public GroupClickListener(RecyclerView parent, RecyclerView.ViewHolder viewHolder) { 276 | mParent = parent; 277 | mViewHolder = viewHolder; 278 | } 279 | 280 | @Override 281 | public void onClick(View v) { 282 | long id = mViewHolder.getItemId(); 283 | int position = mViewHolder.getLayoutPosition(); 284 | if (onGroupClickListener != null) { 285 | int[] positions = getRelativePositions(position); 286 | onGroupClickListener.onGroupClick(mParent, v, positions[0], id); 287 | } 288 | } 289 | 290 | @Override 291 | public boolean onLongClick(View v) { 292 | long id = mViewHolder.getItemId(); 293 | int position = mViewHolder.getLayoutPosition(); 294 | if (onGroupLongClickListener != null) { 295 | int[] positions = getRelativePositions(position); 296 | return onGroupLongClickListener.onGroupLongClick(mParent, v, positions[0], id); 297 | } 298 | return false; 299 | } 300 | } 301 | 302 | class ChildClickListener implements View.OnClickListener, View.OnLongClickListener { 303 | final RecyclerView mParent; 304 | final RecyclerView.ViewHolder mViewHolder; 305 | 306 | public ChildClickListener(RecyclerView parent, RecyclerView.ViewHolder viewHolder) { 307 | mParent = parent; 308 | mViewHolder = viewHolder; 309 | } 310 | 311 | @Override 312 | public void onClick(View v) { 313 | long id = mViewHolder.getItemId(); 314 | int position = mViewHolder.getLayoutPosition(); 315 | if (onChildClickListener != null) { 316 | int[] positions = getRelativePositions(position); 317 | onChildClickListener.onChildClick(mParent, v, positions[0], positions[1], id); 318 | } 319 | } 320 | 321 | @Override 322 | public boolean onLongClick(View v) { 323 | long id = mViewHolder.getItemId(); 324 | int position = mViewHolder.getLayoutPosition(); 325 | if (onChildLongClickListener != null) { 326 | int[] positions = getRelativePositions(position); 327 | return onChildLongClickListener.onChildLongClick(mParent, v, positions[0], positions[1], id); 328 | } 329 | return false; 330 | } 331 | } 332 | 333 | class DefaultOnGroupClickListener implements OnGroupClickListener { 334 | 335 | @Override 336 | public void onGroupClick(RecyclerView parent, View v, int groupPosition, long id) { 337 | if (isCollapsed(groupPosition)) { 338 | expand(groupPosition); 339 | } else { 340 | collapse(groupPosition); 341 | } 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ObjectAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.Filter; 7 | import android.widget.Filterable; 8 | 9 | import androidx.annotation.LayoutRes; 10 | import androidx.annotation.NonNull; 11 | 12 | import com.cncoderx.recyclerviewhelper.utils.Array; 13 | import com.cncoderx.recyclerviewhelper.utils.IArray; 14 | 15 | import java.util.Arrays; 16 | import java.util.Collection; 17 | import java.util.Comparator; 18 | 19 | /** 20 | * @author cncoderx 21 | */ 22 | public abstract class ObjectAdapter extends BaseAdapter 23 | implements IArray, IArray.Callback, Filterable { 24 | private @LayoutRes int mResource; 25 | private Array mArray = new Array<>(); 26 | private Array mOriginalArray; 27 | private ArrayFilter mFilter; 28 | private final Object mLock = new Object(); 29 | 30 | private boolean mNotifyOnChange = true; 31 | private int mPositionOffset = 0; 32 | 33 | public ObjectAdapter(@LayoutRes int resource) { 34 | mResource = resource; 35 | mArray.setCallback(this); 36 | } 37 | 38 | public ObjectAdapter(@LayoutRes int resource, @NonNull T... objects) { 39 | mResource = resource; 40 | mArray.addAll(Arrays.asList(objects)); 41 | mArray.setCallback(this); 42 | } 43 | 44 | public ObjectAdapter(@LayoutRes int resource, @NonNull Collection objects) { 45 | mResource = resource; 46 | mArray.addAll(objects); 47 | mArray.setCallback(this); 48 | } 49 | 50 | @Override 51 | protected View onCreateView(LayoutInflater inflater, ViewGroup parent, int viewType) { 52 | return inflater.inflate(getLayoutResource(viewType), parent, false); 53 | } 54 | 55 | @Override 56 | public void onBindViewHolder(BaseViewHolder holder, int position) { 57 | final T object = get(position); 58 | onBindViewHolder(holder, object, position); 59 | } 60 | 61 | public abstract void onBindViewHolder(BaseViewHolder holder, T object, int position); 62 | 63 | @LayoutRes 64 | protected int getLayoutResource(int viewType) { 65 | return mResource; 66 | } 67 | 68 | @Override 69 | public final int getItemCount() { 70 | return size(); 71 | } 72 | 73 | @Override 74 | public long getItemId(int position) { 75 | return position; 76 | } 77 | 78 | @Override 79 | public boolean isEmpty() { 80 | return mArray.isEmpty(); 81 | } 82 | 83 | @Override 84 | public int size() { 85 | return mArray.size(); 86 | } 87 | 88 | @Override 89 | public T get(int index) { 90 | return mArray.get(index); 91 | } 92 | 93 | @Override 94 | public int indexOf(@NonNull T object) { 95 | return mArray.indexOf(object); 96 | } 97 | 98 | @Override 99 | public void set(int index, @NonNull T object) { 100 | mArray.set(index, object); 101 | } 102 | 103 | @Override 104 | public void add(@NonNull T object) { 105 | mArray.add(object); 106 | } 107 | 108 | @Override 109 | public void add(int index, @NonNull T object) { 110 | mArray.add(index, object); 111 | } 112 | 113 | @Override 114 | public void addAll(@NonNull Collection objects) { 115 | mArray.addAll(objects); 116 | } 117 | 118 | @Override 119 | public void addAll(int index, @NonNull Collection objects) { 120 | mArray.addAll(index, objects); 121 | } 122 | 123 | @Override 124 | public void remove(int index) { 125 | mArray.remove(index); 126 | } 127 | 128 | @Override 129 | public void remove(@NonNull T object) { 130 | mArray.remove(object); 131 | } 132 | 133 | @Override 134 | public void removeRange(int fromIndex, int toIndex) { 135 | mArray.removeRange(fromIndex, toIndex); 136 | } 137 | 138 | @Override 139 | public void swap(int index, int index2) { 140 | mArray.swap(index, index2); 141 | } 142 | 143 | @Override 144 | public void sort(@NonNull Comparator comparator) { 145 | mArray.sort(comparator); 146 | } 147 | 148 | @Override 149 | public void clear() { 150 | mArray.clear(); 151 | } 152 | 153 | @Override 154 | public void onChanged(int index) { 155 | if (isNotifyOnChange()) { 156 | int position = getPosition(index); 157 | notifyItemChanged(position); 158 | } 159 | } 160 | 161 | @Override 162 | public void onAdded(int index) { 163 | if (isNotifyOnChange()) { 164 | int position = getPosition(index); 165 | notifyItemInserted(position); 166 | } 167 | } 168 | 169 | @Override 170 | public void onRemoved(int index) { 171 | if (isNotifyOnChange()) { 172 | int position = getPosition(index); 173 | int notifyCount = size() - index; 174 | notifyItemRemoved(position); 175 | notifyItemRangeChanged(position, notifyCount); 176 | } 177 | } 178 | 179 | @Override 180 | public void onSwapped(int index, int index2) { 181 | if (isNotifyOnChange()) { 182 | int position; 183 | int position2; 184 | if (index < index2) { 185 | position = getPosition(index); 186 | position2 = getPosition(index2); 187 | } else { 188 | position = getPosition(index2); 189 | position2 = getPosition(index); 190 | } 191 | notifyItemMoved(position, position2); 192 | notifyItemMoved(position2 - 1, position); 193 | } 194 | } 195 | 196 | @Override 197 | public void onChanged() { 198 | if (isNotifyOnChange()) { 199 | notifyDataSetChanged(); 200 | } 201 | } 202 | 203 | @Override 204 | public void onRangeAdded(int index, int size) { 205 | if (isNotifyOnChange()) { 206 | if (size() - size == 0) { 207 | notifyDataSetChanged(); 208 | } else { 209 | int position = getPosition(index); 210 | notifyItemRangeInserted(position, size); 211 | } 212 | } 213 | } 214 | 215 | @Override 216 | public void onRangeRemoved(int index, int size) { 217 | if (isNotifyOnChange()) { 218 | int position = getPosition(index); 219 | int notifyCount = size() - index; 220 | notifyItemRangeRemoved(position, size); 221 | notifyItemRangeChanged(position, notifyCount); 222 | } 223 | } 224 | 225 | private int getPosition(int index) { 226 | return index + mPositionOffset; 227 | } 228 | 229 | public boolean isNotifyOnChange() { 230 | return mNotifyOnChange; 231 | } 232 | 233 | public void setNotifyOnChange(boolean notifyOnChange) { 234 | mNotifyOnChange = notifyOnChange; 235 | } 236 | 237 | public int getPositionOffset() { 238 | return mPositionOffset; 239 | } 240 | 241 | public void setPositionOffset(int positionOffset) { 242 | mPositionOffset = positionOffset; 243 | } 244 | 245 | @Override 246 | public Filter getFilter() { 247 | if (mFilter == null) { 248 | mFilter = new ArrayFilter(); 249 | } 250 | return mFilter; 251 | } 252 | 253 | private class ArrayFilter extends Filter { 254 | 255 | @Override 256 | protected FilterResults performFiltering(CharSequence prefix) { 257 | final FilterResults results = new FilterResults(); 258 | 259 | if (mOriginalArray == null) { 260 | synchronized (mLock) { 261 | mOriginalArray = new Array<>(mArray); 262 | } 263 | } 264 | 265 | if (prefix == null || prefix.length() == 0) { 266 | final Array array; 267 | synchronized (mLock) { 268 | array = new Array<>(mOriginalArray); 269 | } 270 | results.values = array; 271 | results.count = array.size(); 272 | } else { 273 | final String prefixString = prefix.toString().toLowerCase(); 274 | 275 | final Array array; 276 | synchronized (mLock) { 277 | array = new Array<>(mOriginalArray); 278 | } 279 | 280 | final int count = array.size(); 281 | final Array newArray = new Array<>(); 282 | 283 | for (int i = 0; i < count; i++) { 284 | final T value = array.get(i); 285 | final String valueText = value.toString().toLowerCase(); 286 | 287 | // First match against the whole, non-splitted value 288 | if (valueText.startsWith(prefixString)) { 289 | newArray.add(value); 290 | } else { 291 | final String[] words = valueText.split(" "); 292 | for (String word : words) { 293 | if (word.startsWith(prefixString)) { 294 | newArray.add(value); 295 | break; 296 | } 297 | } 298 | } 299 | } 300 | 301 | results.values = newArray; 302 | results.count = newArray.size(); 303 | } 304 | 305 | return results; 306 | } 307 | 308 | @Override 309 | protected void publishResults(CharSequence constraint, FilterResults results) { 310 | mArray.setCallback(null); 311 | //noinspection unchecked 312 | mArray = (Array) results.values; 313 | mArray.setCallback(ObjectAdapter.this); 314 | notifyDataSetChanged(); 315 | } 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/ResourceCursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.database.Cursor; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * @author cncoderx 10 | */ 11 | public abstract class ResourceCursorAdapter extends CursorAdapter { 12 | private int mLayout; 13 | 14 | @Deprecated 15 | public ResourceCursorAdapter(int layout, Cursor c) { 16 | super(c); 17 | mLayout = layout; 18 | } 19 | 20 | public ResourceCursorAdapter(int layout, Cursor c, boolean autoRequery) { 21 | super(c, autoRequery); 22 | mLayout = layout; 23 | } 24 | 25 | public ResourceCursorAdapter(int layout, Cursor c, int flags) { 26 | super(c, flags); 27 | mLayout = layout; 28 | } 29 | 30 | @Override 31 | protected View onCreateView(LayoutInflater inflater, ViewGroup parent, int viewType) { 32 | return inflater.inflate(mLayout, parent, false); 33 | } 34 | 35 | public void setViewResource(int layout) { 36 | mLayout = layout; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/SimpleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.net.Uri; 4 | import androidx.annotation.IdRes; 5 | import androidx.annotation.LayoutRes; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.Checkable; 10 | import android.widget.Filter; 11 | import android.widget.Filterable; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * @author cncoderx 21 | */ 22 | public class SimpleAdapter extends BaseAdapter implements Filterable { 23 | private int[] mTo; 24 | private String[] mFrom; 25 | private ViewBinder mViewBinder; 26 | 27 | private List> mData; 28 | 29 | private int mResource; 30 | 31 | private SimpleFilter mFilter; 32 | private ArrayList> mUnfilteredData; 33 | 34 | public SimpleAdapter(List> data, 35 | @LayoutRes int resource, String[] from, @IdRes int[] to) { 36 | mData = data; 37 | mResource = resource; 38 | mFrom = from; 39 | mTo = to; 40 | } 41 | 42 | @Override 43 | protected View onCreateView(LayoutInflater inflater, ViewGroup parent, int viewType) { 44 | return inflater.inflate(mResource, parent, false); 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(BaseViewHolder holder, int position) { 49 | final Map dataSet = mData.get(position); 50 | if (dataSet == null) return; 51 | 52 | final ViewBinder binder = mViewBinder; 53 | final String[] from = mFrom; 54 | final int[] to = mTo; 55 | final int count = to.length; 56 | 57 | for (int i = 0; i < count; i++) { 58 | final View v = holder.getView(to[i]); 59 | if (v != null) { 60 | final Object data = dataSet.get(from[i]); 61 | String text = data == null ? "" : data.toString(); 62 | if (text == null) { 63 | text = ""; 64 | } 65 | 66 | boolean bound = false; 67 | if (binder != null) { 68 | bound = binder.setViewValue(v, data, text); 69 | } 70 | 71 | if (!bound) { 72 | if (v instanceof Checkable) { 73 | if (data instanceof Boolean) { 74 | ((Checkable) v).setChecked((Boolean) data); 75 | } else if (v instanceof TextView) { 76 | // Note: keep the instanceof TextView check at the bottom of these 77 | // ifs since a lot of views are TextViews (e.g. CheckBoxes). 78 | setViewText((TextView) v, text); 79 | } else { 80 | throw new IllegalStateException(v.getClass().getName() + 81 | " should be bound to a Boolean, not a " + 82 | (data == null ? "" : data.getClass())); 83 | } 84 | } else if (v instanceof TextView) { 85 | // Note: keep the instanceof TextView check at the bottom of these 86 | // ifs since a lot of views are TextViews (e.g. CheckBoxes). 87 | setViewText((TextView) v, text); 88 | } else if (v instanceof ImageView) { 89 | if (data instanceof Integer) { 90 | setViewImage((ImageView) v, (Integer) data); 91 | } else { 92 | setViewImage((ImageView) v, text); 93 | } 94 | } else { 95 | throw new IllegalStateException(v.getClass().getName() + " is not a " + 96 | " view that can be bounds by this SimpleAdapter"); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | @Override 104 | public int getItemCount() { 105 | return mData.size(); 106 | } 107 | 108 | public Object getItem(int position) { 109 | return mData.get(position); 110 | } 111 | 112 | @Override 113 | public long getItemId(int position) { 114 | return position; 115 | } 116 | 117 | public ViewBinder getViewBinder() { 118 | return mViewBinder; 119 | } 120 | 121 | public void setViewBinder(ViewBinder viewBinder) { 122 | mViewBinder = viewBinder; 123 | } 124 | 125 | public void setViewImage(ImageView v, int value) { 126 | v.setImageResource(value); 127 | } 128 | 129 | public void setViewImage(ImageView v, String value) { 130 | try { 131 | v.setImageResource(Integer.parseInt(value)); 132 | } catch (NumberFormatException nfe) { 133 | v.setImageURI(Uri.parse(value)); 134 | } 135 | } 136 | 137 | public void setViewText(TextView v, String text) { 138 | v.setText(text); 139 | } 140 | 141 | @Override 142 | public Filter getFilter() { 143 | if (mFilter == null) { 144 | mFilter = new SimpleFilter(); 145 | } 146 | return mFilter; 147 | } 148 | 149 | public static interface ViewBinder { 150 | boolean setViewValue(View view, Object data, String textRepresentation); 151 | } 152 | 153 | private class SimpleFilter extends Filter { 154 | 155 | @Override 156 | protected FilterResults performFiltering(CharSequence prefix) { 157 | FilterResults results = new FilterResults(); 158 | 159 | if (mUnfilteredData == null) { 160 | mUnfilteredData = new ArrayList>(mData); 161 | } 162 | 163 | if (prefix == null || prefix.length() == 0) { 164 | ArrayList> list = mUnfilteredData; 165 | results.values = list; 166 | results.count = list.size(); 167 | } else { 168 | String prefixString = prefix.toString().toLowerCase(); 169 | 170 | ArrayList> unfilteredValues = mUnfilteredData; 171 | int count = unfilteredValues.size(); 172 | 173 | ArrayList> newValues = new ArrayList>(count); 174 | 175 | for (int i = 0; i < count; i++) { 176 | Map h = unfilteredValues.get(i); 177 | if (h != null) { 178 | 179 | int len = mTo.length; 180 | 181 | for (int j = 0; j < len; j++) { 182 | String str = (String) h.get(mFrom[j]); 183 | 184 | String[] words = str.split(" "); 185 | int wordCount = words.length; 186 | 187 | for (int k = 0; k < wordCount; k++) { 188 | String word = words[k]; 189 | 190 | if (word.toLowerCase().startsWith(prefixString)) { 191 | newValues.add(h); 192 | break; 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | results.values = newValues; 200 | results.count = newValues.size(); 201 | } 202 | 203 | return results; 204 | } 205 | 206 | @Override 207 | protected void publishResults(CharSequence constraint, FilterResults results) { 208 | //noinspection unchecked 209 | mData = (List>) results.values; 210 | notifyDataSetChanged(); 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/SimpleCursorAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import android.database.Cursor; 4 | import android.net.Uri; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | public class SimpleCursorAdapter extends ResourceCursorAdapter { 10 | protected int[] mFrom; 11 | protected int[] mTo; 12 | 13 | private int mStringConversionColumn = -1; 14 | private CursorToStringConverter mCursorToStringConverter; 15 | private ViewBinder mViewBinder; 16 | 17 | String[] mOriginalFrom; 18 | 19 | @Deprecated 20 | public SimpleCursorAdapter(int layout, Cursor c, String[] from, int[] to) { 21 | super(layout, c); 22 | mTo = to; 23 | mOriginalFrom = from; 24 | findColumns(c, from); 25 | } 26 | 27 | public SimpleCursorAdapter(int layout, Cursor c, String[] from, 28 | int[] to, int flags) { 29 | super(layout, c, flags); 30 | mTo = to; 31 | mOriginalFrom = from; 32 | findColumns(c, from); 33 | } 34 | 35 | @Override 36 | public void onBindViewHolder(BaseViewHolder holder, Cursor cursor) { 37 | final ViewBinder binder = mViewBinder; 38 | final int count = mTo.length; 39 | final int[] from = mFrom; 40 | final int[] to = mTo; 41 | 42 | for (int i = 0; i < count; i++) { 43 | final View v = holder.getView(to[i]); 44 | if (v != null) { 45 | boolean bound = false; 46 | if (binder != null) { 47 | bound = binder.setViewValue(v, cursor, from[i]); 48 | } 49 | 50 | if (!bound) { 51 | String text = cursor.getString(from[i]); 52 | if (text == null) { 53 | text = ""; 54 | } 55 | 56 | if (v instanceof TextView) { 57 | setViewText((TextView) v, text); 58 | } else if (v instanceof ImageView) { 59 | setViewImage((ImageView) v, text); 60 | } else { 61 | throw new IllegalStateException(v.getClass().getName() + " is not a " + 62 | " view that can be bounds by this SimpleCursorAdapter"); 63 | } 64 | } 65 | } 66 | } 67 | } 68 | 69 | public ViewBinder getViewBinder() { 70 | return mViewBinder; 71 | } 72 | 73 | public void setViewBinder(ViewBinder viewBinder) { 74 | mViewBinder = viewBinder; 75 | } 76 | 77 | public void setViewImage(ImageView v, String value) { 78 | try { 79 | v.setImageResource(Integer.parseInt(value)); 80 | } catch (NumberFormatException nfe) { 81 | v.setImageURI(Uri.parse(value)); 82 | } 83 | } 84 | 85 | public void setViewText(TextView v, String text) { 86 | v.setText(text); 87 | } 88 | 89 | public int getStringConversionColumn() { 90 | return mStringConversionColumn; 91 | } 92 | 93 | public void setStringConversionColumn(int stringConversionColumn) { 94 | mStringConversionColumn = stringConversionColumn; 95 | } 96 | 97 | public CursorToStringConverter getCursorToStringConverter() { 98 | return mCursorToStringConverter; 99 | } 100 | 101 | public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) { 102 | mCursorToStringConverter = cursorToStringConverter; 103 | } 104 | 105 | @Override 106 | public CharSequence convertToString(Cursor cursor) { 107 | if (mCursorToStringConverter != null) { 108 | return mCursorToStringConverter.convertToString(cursor); 109 | } else if (mStringConversionColumn > -1) { 110 | return cursor.getString(mStringConversionColumn); 111 | } 112 | 113 | return super.convertToString(cursor); 114 | } 115 | 116 | private void findColumns(Cursor c, String[] from) { 117 | if (c != null) { 118 | int i; 119 | int count = from.length; 120 | if (mFrom == null || mFrom.length != count) { 121 | mFrom = new int[count]; 122 | } 123 | for (i = 0; i < count; i++) { 124 | mFrom[i] = c.getColumnIndexOrThrow(from[i]); 125 | } 126 | } else { 127 | mFrom = null; 128 | } 129 | } 130 | 131 | @Override 132 | public Cursor swapCursor(Cursor c) { 133 | // super.swapCursor() will notify observers before we have 134 | // a valid mapping, make sure we have a mapping before this 135 | // happens 136 | findColumns(c, mOriginalFrom); 137 | return super.swapCursor(c); 138 | } 139 | 140 | public void changeCursorAndColumns(Cursor c, String[] from, int[] to) { 141 | mOriginalFrom = from; 142 | mTo = to; 143 | // super.changeCursor() will notify observers before we have 144 | // a valid mapping, make sure we have a mapping before this 145 | // happens 146 | findColumns(c, mOriginalFrom); 147 | super.changeCursor(c); 148 | } 149 | 150 | public static interface ViewBinder { 151 | boolean setViewValue(View view, Cursor cursor, int columnIndex); 152 | } 153 | 154 | public static interface CursorToStringConverter { 155 | CharSequence convertToString(Cursor cursor); 156 | } 157 | } 158 | 159 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/adapter/SwipeAdapter.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.adapter; 2 | 3 | import androidx.annotation.LayoutRes; 4 | import androidx.annotation.NonNull; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | import android.view.ViewGroup; 7 | 8 | import com.cncoderx.recyclerviewhelper.R; 9 | import com.daimajia.swipe.SimpleSwipeListener; 10 | import com.daimajia.swipe.SwipeLayout; 11 | import com.daimajia.swipe.util.Attributes; 12 | 13 | import java.lang.ref.WeakReference; 14 | import java.util.ArrayList; 15 | import java.util.Collection; 16 | import java.util.Collections; 17 | import java.util.Comparator; 18 | import java.util.List; 19 | 20 | /** 21 | * @author cncoderx 22 | */ 23 | public abstract class SwipeAdapter extends ObjectAdapter { 24 | private Attributes.Mode mode = Attributes.Mode.Single; 25 | private List openedPositions = new ArrayList<>(); 26 | private SwipeLayout tempLayout; 27 | 28 | public SwipeAdapter(@LayoutRes int resource) { 29 | super(resource); 30 | } 31 | 32 | public SwipeAdapter(@LayoutRes int resource, @NonNull T[] objects) { 33 | super(resource, objects); 34 | openedPositions.addAll(obtainBoolCollection(objects.length)); 35 | } 36 | 37 | public SwipeAdapter(@LayoutRes int resource, @NonNull Collection objects) { 38 | super(resource, objects); 39 | openedPositions.addAll(obtainBoolCollection(objects.size())); 40 | } 41 | 42 | @Override 43 | public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 44 | BaseViewHolder holder = super.onCreateViewHolder(parent, viewType); 45 | SwipeLayout swipeLayout; 46 | if (holder.itemView instanceof SwipeLayout) { 47 | swipeLayout = (SwipeLayout) holder.itemView; 48 | } else { 49 | swipeLayout = (SwipeLayout) holder.itemView.findViewById(R.id.swipe_layout); 50 | } 51 | if (swipeLayout == null) { 52 | throw new RuntimeException("Failed to find swipe layout with ID " 53 | + holder.itemView.getResources().getResourceName(R.id.swipe_layout) 54 | + " in item layout"); 55 | } 56 | swipeLayout.addSwipeListener(new OnSwipeListener(holder)); 57 | swipeLayout.addOnLayoutListener(new OnLayoutListener(holder)); 58 | return holder; 59 | } 60 | 61 | private Collection obtainBoolCollection(int size) { 62 | ArrayList arrayList = new ArrayList<>(size); 63 | for (int i = 0; i < size; i++) { 64 | arrayList.add(Boolean.FALSE); 65 | } 66 | return arrayList; 67 | } 68 | 69 | @Override 70 | public void add(@NonNull T object) { 71 | super.add(object); 72 | openedPositions.add(Boolean.FALSE); 73 | } 74 | 75 | @Override 76 | public void add(int index, @NonNull T object) { 77 | super.add(index, object); 78 | openedPositions.add(index, Boolean.FALSE); 79 | } 80 | 81 | @Override 82 | public void addAll(@NonNull Collection objects) { 83 | super.addAll(objects); 84 | openedPositions.addAll(obtainBoolCollection(objects.size())); 85 | } 86 | 87 | @Override 88 | public void addAll(int index, @NonNull Collection objects) { 89 | super.addAll(index, objects); 90 | openedPositions.addAll(index, obtainBoolCollection(objects.size())); 91 | } 92 | 93 | @Override 94 | public void remove(int index) { 95 | super.remove(index); 96 | openedPositions.remove(index); 97 | } 98 | 99 | @Override 100 | public void removeRange(int fromIndex, int toIndex) { 101 | super.removeRange(fromIndex, toIndex); 102 | openedPositions.subList(fromIndex, toIndex).clear(); 103 | } 104 | 105 | @Override 106 | public void swap(int index, int index2) { 107 | super.swap(index, index2); 108 | Boolean b = openedPositions.get(index); 109 | Boolean b2 = openedPositions.get(index2); 110 | openedPositions.set(index, b2); 111 | openedPositions.set(index2, b); 112 | } 113 | 114 | @Override 115 | public void sort(@NonNull Comparator comparator) { 116 | super.sort(comparator); 117 | Collections.fill(openedPositions, Boolean.FALSE); 118 | } 119 | 120 | @Override 121 | public void clear() { 122 | super.clear(); 123 | openedPositions.clear(); 124 | } 125 | 126 | public Attributes.Mode getMode() { 127 | return mode; 128 | } 129 | 130 | public void setMode(Attributes.Mode mode) { 131 | this.mode = mode; 132 | } 133 | 134 | class OnLayoutListener implements SwipeLayout.OnLayout { 135 | WeakReference mViewHolderProvider; 136 | 137 | OnLayoutListener(RecyclerView.ViewHolder holder) { 138 | mViewHolderProvider = new WeakReference<>(holder); 139 | } 140 | 141 | @Override 142 | public void onLayout(SwipeLayout layout) { 143 | RecyclerView.ViewHolder holder = mViewHolderProvider.get(); 144 | if (holder != null) { 145 | int position = holder.getAdapterPosition(); 146 | if (openedPositions.get(position)) { 147 | layout.open(false, false); 148 | tempLayout = layout; 149 | } else { 150 | layout.close(false, false); 151 | } 152 | } 153 | } 154 | 155 | } 156 | 157 | class OnSwipeListener extends SimpleSwipeListener { 158 | WeakReference viewHolderRef; 159 | 160 | OnSwipeListener(RecyclerView.ViewHolder holder) { 161 | viewHolderRef = new WeakReference<>(holder); 162 | } 163 | 164 | @Override 165 | public void onClose(SwipeLayout layout) { 166 | RecyclerView.ViewHolder holder = viewHolderRef.get(); 167 | if (holder != null) { 168 | openedPositions.set(holder.getAdapterPosition(), Boolean.FALSE); 169 | } 170 | if (getMode() == Attributes.Mode.Single) { 171 | if (tempLayout == layout) { 172 | tempLayout = null; 173 | } 174 | } 175 | } 176 | 177 | @Override 178 | public void onOpen(SwipeLayout layout) { 179 | if (getMode() == Attributes.Mode.Single) { 180 | Collections.fill(openedPositions, Boolean.FALSE); 181 | if (tempLayout != null && tempLayout != layout) { 182 | tempLayout.close(); 183 | } 184 | tempLayout = layout; 185 | } 186 | RecyclerView.ViewHolder holder = viewHolderRef.get(); 187 | if (holder != null) { 188 | openedPositions.set(holder.getAdapterPosition(), Boolean.TRUE); 189 | } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/EndlessScrollListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.LinearLayoutManager; 4 | import androidx.recyclerview.widget.OrientationHelper; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | import androidx.recyclerview.widget.StaggeredGridLayoutManager; 7 | import android.view.View; 8 | 9 | import com.cncoderx.recyclerviewhelper.utils.ILoadingView; 10 | 11 | import java.util.Arrays; 12 | 13 | /** 14 | * @author cncoderx 15 | */ 16 | public class EndlessScrollListener extends RecyclerView.OnScrollListener { 17 | private int lastVisibleItemPosition; 18 | private int[] positions; 19 | private int oldSpanCount; 20 | private int orientation; 21 | 22 | private OnLoadMoreListener onLoadMoreListener; 23 | private ILoadingView mLoadingView; 24 | 25 | public EndlessScrollListener(OnLoadMoreListener onLoadMoreListener) { 26 | this.onLoadMoreListener = onLoadMoreListener; 27 | } 28 | 29 | public EndlessScrollListener(OnLoadMoreListener onLoadMoreListener, ILoadingView loadingView) { 30 | this.onLoadMoreListener = onLoadMoreListener; 31 | this.mLoadingView = loadingView; 32 | } 33 | 34 | @Override 35 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 36 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 37 | if (layoutManager instanceof LinearLayoutManager) { 38 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; 39 | lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition(); 40 | orientation = linearLayoutManager.getOrientation(); 41 | } else if (layoutManager instanceof StaggeredGridLayoutManager) { 42 | StaggeredGridLayoutManager staggeredLayoutManager = (StaggeredGridLayoutManager) layoutManager; 43 | int spanCount = staggeredLayoutManager.getSpanCount(); 44 | if (spanCount == oldSpanCount) { 45 | positions = staggeredLayoutManager.findLastVisibleItemPositions(positions); 46 | } else { 47 | positions = staggeredLayoutManager.findLastVisibleItemPositions(null); 48 | oldSpanCount = spanCount; 49 | } 50 | Arrays.sort(positions); 51 | lastVisibleItemPosition = positions[spanCount - 1]; 52 | orientation = staggeredLayoutManager.getOrientation(); 53 | } else { 54 | throw new RuntimeException( 55 | "Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager"); 56 | } 57 | } 58 | 59 | @Override 60 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 61 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); 62 | int itemCount = layoutManager.getItemCount(); 63 | if (newState == RecyclerView.SCROLL_STATE_IDLE 64 | && canScroll(recyclerView) 65 | && lastVisibleItemPosition >= itemCount - 1) { 66 | if (mLoadingView != null) { 67 | if (mLoadingView.getState() == ILoadingView.STATE_HIDDEN) { 68 | mLoadingView.show(); 69 | if (onLoadMoreListener != null) { 70 | onLoadMoreListener.load(recyclerView, mLoadingView); 71 | } 72 | } 73 | } else { 74 | if (onLoadMoreListener != null) 75 | onLoadMoreListener.load(recyclerView, null); 76 | } 77 | } 78 | } 79 | 80 | private boolean canScroll(View v) { 81 | if (orientation == OrientationHelper.VERTICAL) { 82 | return v.canScrollVertically(-1); 83 | } 84 | if (orientation == OrientationHelper.HORIZONTAL) { 85 | return v.canScrollHorizontally(-1); 86 | } 87 | return true; 88 | } 89 | } -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnChildClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnChildClickListener { 10 | void onChildClick(RecyclerView parent, View v, int groupPosition, 11 | int childPosition, long id); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnChildLongClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnChildLongClickListener { 10 | boolean onChildLongClick(RecyclerView parent, View v, int groupPosition, 11 | int childPosition, long id); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnGroupClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnGroupClickListener { 10 | void onGroupClick(RecyclerView parent, View v, int groupPosition, 11 | long id); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnGroupLongClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnGroupLongClickListener { 10 | boolean onGroupLongClick(RecyclerView parent, View v, int groupPosition, 11 | long id); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnItemClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnItemClickListener { 10 | void onItemClick(RecyclerView parent, View view, int position, long id); 11 | } 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnItemLongClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * @author cncoderx 8 | */ 9 | public interface OnItemLongClickListener { 10 | boolean onItemLongClick(RecyclerView parent, View view, int position, long id); 11 | } 12 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/listener/OnLoadMoreListener.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.listener; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | 5 | import com.cncoderx.recyclerviewhelper.utils.ILoadingView; 6 | 7 | /** 8 | * @author cncoderx 9 | */ 10 | public interface OnLoadMoreListener { 11 | void load(RecyclerView recyclerView, ILoadingView view); 12 | } 13 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/AdapterArray.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collection; 8 | import java.util.Comparator; 9 | 10 | /** 11 | * @author cncoderx 12 | */ 13 | public class AdapterArray extends Array implements IAdapterArray { 14 | private final RecyclerView.Adapter mAdapter; 15 | private boolean mNotifyOnChange = true; 16 | private int mPositionOffset = 0; 17 | 18 | public AdapterArray(@NonNull RecyclerView.Adapter adapter) { 19 | mAdapter = adapter; 20 | } 21 | 22 | public AdapterArray(@NonNull RecyclerView.Adapter adapter, T... objects) { 23 | mAdapter = adapter; 24 | addAll(Arrays.asList(objects)); 25 | } 26 | 27 | public AdapterArray(@NonNull RecyclerView.Adapter adapter, Collection objects) { 28 | mAdapter = adapter; 29 | addAll(objects); 30 | } 31 | 32 | public void set(int index, @NonNull T object) { 33 | super.set(index, object); 34 | if (isNotifyOnChange()) { 35 | int position = getPosition(index); 36 | mAdapter.notifyItemChanged(position); 37 | } 38 | } 39 | 40 | public void add(@NonNull T object) { 41 | super.add(object); 42 | if (isNotifyOnChange()) { 43 | int position = getPosition(size() - 1); 44 | mAdapter.notifyItemInserted(position); 45 | } 46 | } 47 | 48 | public void add(int index, @NonNull T object) { 49 | super.add(index, object); 50 | if (isNotifyOnChange()) { 51 | int position = getPosition(index); 52 | mAdapter.notifyItemInserted(position); 53 | } 54 | } 55 | 56 | public void addAll(@NonNull Collection objects) { 57 | super.addAll(objects); 58 | int size = objects.size(); 59 | int subSize = size() - size; 60 | if (isNotifyOnChange()) { 61 | if (subSize == 0) { 62 | mAdapter.notifyDataSetChanged(); 63 | } else { 64 | int position = getPosition(subSize); 65 | mAdapter.notifyItemRangeInserted(position, size); 66 | } 67 | } 68 | } 69 | 70 | public void addAll(int index, @NonNull Collection objects) { 71 | super.addAll(index, objects); 72 | int size = objects.size(); 73 | int subSize = size() - size; 74 | if (isNotifyOnChange()) { 75 | if (subSize == 0) { 76 | mAdapter.notifyDataSetChanged(); 77 | } else { 78 | int position = getPosition(index); 79 | mAdapter.notifyItemRangeInserted(position, size); 80 | } 81 | } 82 | } 83 | 84 | public void remove(int index) { 85 | super.remove(index); 86 | if (isNotifyOnChange()) { 87 | int position = getPosition(index); 88 | int notifyCount = size() - position; 89 | mAdapter.notifyItemRemoved(position); 90 | mAdapter.notifyItemRangeChanged(position, notifyCount); 91 | } 92 | } 93 | 94 | public void removeRange(int fromIndex, int toIndex) { 95 | super.removeRange(fromIndex, toIndex); 96 | if (isNotifyOnChange()) { 97 | int position = getPosition(fromIndex); 98 | int removeCount = toIndex - fromIndex; 99 | int notifyCount = size() - position; 100 | mAdapter.notifyItemRangeRemoved(position, removeCount); 101 | mAdapter.notifyItemRangeChanged(position, notifyCount); 102 | } 103 | } 104 | 105 | @Override 106 | public void sort(@NonNull Comparator comparator) { 107 | super.sort(comparator); 108 | if (isNotifyOnChange()) { 109 | mAdapter.notifyDataSetChanged(); 110 | } 111 | } 112 | 113 | public void clear() { 114 | super.clear(); 115 | if (isNotifyOnChange()) { 116 | mAdapter.notifyDataSetChanged(); 117 | } 118 | } 119 | 120 | private int getPosition(int index) { 121 | return index + mPositionOffset; 122 | } 123 | 124 | @Override 125 | public boolean isNotifyOnChange() { 126 | return mNotifyOnChange; 127 | } 128 | 129 | @Override 130 | public void setNotifyOnChange(boolean notify) { 131 | mNotifyOnChange = notify; 132 | } 133 | 134 | public int getPositionOffset() { 135 | return mPositionOffset; 136 | } 137 | 138 | public void setPositionOffset(int positionOffset) { 139 | mPositionOffset = positionOffset; 140 | } 141 | 142 | @Override 143 | public RecyclerView.Adapter getAdapter() { 144 | return mAdapter; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/Array.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | import java.util.Comparator; 9 | 10 | /** 11 | * @author cncoderx 12 | */ 13 | public class Array implements IArray { 14 | 15 | private final ArrayList mArray; 16 | 17 | private Callback mCallback; 18 | 19 | public Callback getCallback() { 20 | return mCallback; 21 | } 22 | 23 | public void setCallback(Callback callback) { 24 | mCallback = callback; 25 | } 26 | 27 | public Array() { 28 | this.mArray = new ArrayList<>(); 29 | } 30 | 31 | public Array(int capacity) { 32 | this.mArray = new ArrayList<>(capacity); 33 | } 34 | 35 | public Array(Array array) { 36 | this(array.mArray); 37 | } 38 | 39 | public Array(Collection c) { 40 | this.mArray = new ArrayList<>(c); 41 | } 42 | 43 | @Override 44 | public boolean isEmpty() { 45 | return mArray.isEmpty(); 46 | } 47 | 48 | @Override 49 | public int size() { 50 | return mArray.size(); 51 | } 52 | 53 | @Override 54 | public T get(int index) { 55 | return mArray.get(index); 56 | } 57 | 58 | @Override 59 | public int indexOf(@NonNull T object) { 60 | return mArray.indexOf(object); 61 | } 62 | 63 | @Override 64 | public void set(int index, @NonNull T object) { 65 | mArray.set(index, object); 66 | if (mCallback != null) { 67 | mCallback.onChanged(index); 68 | } 69 | } 70 | 71 | @Override 72 | public void add(@NonNull T object) { 73 | int index = mArray.size(); 74 | mArray.add(object); 75 | if (mCallback != null) { 76 | mCallback.onAdded(index); 77 | } 78 | } 79 | 80 | @Override 81 | public void add(int index, @NonNull T object) { 82 | mArray.add(index, object); 83 | if (mCallback != null) { 84 | mCallback.onAdded(index); 85 | } 86 | } 87 | 88 | @Override 89 | public void addAll(@NonNull Collection objects) { 90 | int index = mArray.size(); 91 | mArray.addAll(objects); 92 | if (mCallback != null) { 93 | int size = objects.size(); 94 | mCallback.onRangeAdded(index, size); 95 | } 96 | } 97 | 98 | @Override 99 | public void addAll(int index, @NonNull Collection objects) { 100 | mArray.addAll(index, objects); 101 | if (mCallback != null) { 102 | int size = objects.size(); 103 | mCallback.onRangeAdded(index, size); 104 | } 105 | } 106 | 107 | @Override 108 | public void remove(int index) { 109 | mArray.remove(index); 110 | if (mCallback != null) { 111 | mCallback.onRemoved(index); 112 | } 113 | } 114 | 115 | @Override 116 | public void remove(@NonNull T object) { 117 | int index = mArray.indexOf(object); 118 | if (index != -1) remove(index); 119 | } 120 | 121 | @Override 122 | public void removeRange(int fromIndex, int toIndex) { 123 | mArray.subList(fromIndex, toIndex).clear(); 124 | if (mCallback != null) { 125 | int size = toIndex - fromIndex; 126 | mCallback.onRangeRemoved(fromIndex, size); 127 | } 128 | } 129 | 130 | @Override 131 | public void swap(int index, int index2) { 132 | if (index == index2) 133 | return; 134 | T object = mArray.get(index); 135 | T object2 = mArray.get(index2); 136 | mArray.set(index, object2); 137 | mArray.set(index2, object); 138 | if (mCallback != null) { 139 | mCallback.onSwapped(index, index2); 140 | } 141 | } 142 | 143 | @Override 144 | public void sort(@NonNull Comparator comparator) { 145 | Collections.sort(mArray, comparator); 146 | if (mCallback != null) { 147 | mCallback.onChanged(); 148 | } 149 | } 150 | 151 | @Override 152 | public void clear() { 153 | mArray.clear(); 154 | if (mCallback != null) { 155 | mCallback.onChanged(); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.graphics.drawable.Drawable; 6 | import androidx.core.view.ViewCompat; 7 | import androidx.recyclerview.widget.LinearLayoutManager; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | /** 13 | * @author cncoderx 14 | */ 15 | @Deprecated 16 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 17 | private Drawable mDivider; 18 | private int mDividerHeight; 19 | 20 | public DividerItemDecoration(Drawable divider, int dividerHeight) { 21 | mDivider = divider; 22 | mDividerHeight = dividerHeight; 23 | } 24 | 25 | @Override 26 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 27 | if (mDivider == null) return; 28 | if (!(parent.getLayoutManager() instanceof LinearLayoutManager)) return; 29 | LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); 30 | int orientation = layoutManager.getOrientation(); 31 | if (orientation == LinearLayoutManager.VERTICAL) { 32 | final int left = parent.getPaddingLeft(); 33 | final int right = parent.getWidth() - parent.getPaddingRight(); 34 | final int childCount = parent.getChildCount(); 35 | for (int i = 1; i < childCount; i++) { 36 | final View child = parent.getChildAt(i); 37 | if (child.getVisibility() == View.GONE) continue; 38 | final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); 39 | final int bottom = child.getTop() - params.topMargin + Math.round(ViewCompat.getTranslationY(child)); 40 | final int top = bottom - mDividerHeight; 41 | mDivider.setBounds(left, top, right, bottom); 42 | mDivider.draw(c); 43 | } 44 | } else { 45 | final int top = parent.getPaddingTop(); 46 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 47 | final int childCount = parent.getChildCount(); 48 | for (int i = 1; i < childCount; i++) { 49 | final View child = parent.getChildAt(i); 50 | if (child.getVisibility() == View.GONE) continue; 51 | final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); 52 | final int right = child.getLeft() - params.leftMargin + Math.round(ViewCompat.getTranslationX(child)); 53 | final int left = right - mDividerHeight; 54 | mDivider.setBounds(left, top, right, bottom); 55 | mDivider.draw(c); 56 | } 57 | } 58 | } 59 | 60 | @Override 61 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 62 | final int adapterPosition = parent.getChildAdapterPosition(view); 63 | final int layoutPosition = parent.getChildLayoutPosition(view); 64 | if (!(parent.getLayoutManager() instanceof LinearLayoutManager)) return; 65 | LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); 66 | if (adapterPosition > 0 || adapterPosition == -1 && layoutPosition != 0) { 67 | int orientation = layoutManager.getOrientation(); 68 | if (orientation == LinearLayoutManager.VERTICAL) { 69 | outRect.top = mDividerHeight; 70 | } else { 71 | outRect.left = mDividerHeight; 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/IAdapterArray.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import androidx.recyclerview.widget.RecyclerView; 4 | 5 | /** 6 | * @author cncoderx 7 | */ 8 | public interface IAdapterArray { 9 | boolean isNotifyOnChange(); 10 | void setNotifyOnChange(boolean notify); 11 | int getPositionOffset(); 12 | void setPositionOffset(int offset); 13 | RecyclerView.Adapter getAdapter(); 14 | } 15 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/IArray.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import androidx.annotation.IntRange; 4 | import androidx.annotation.NonNull; 5 | 6 | import java.util.Collection; 7 | import java.util.Comparator; 8 | 9 | /** 10 | * @author cncoderx 11 | */ 12 | 13 | public interface IArray { 14 | boolean isEmpty(); 15 | int size(); 16 | T get(@IntRange(from = 0) int index); 17 | int indexOf(@NonNull T object); 18 | void set(@IntRange(from = 0) int index, @NonNull T object); 19 | void add(@NonNull T object); 20 | void add(@IntRange(from = 0) int index, @NonNull T object); 21 | void addAll(@NonNull Collection objects); 22 | void addAll(@IntRange(from = 0) int index, @NonNull Collection objects); 23 | void remove(@IntRange(from = 0) int index); 24 | void remove(@NonNull T object); 25 | void removeRange(@IntRange(from = 0) int fromIndex, @IntRange(from = 0) int toIndex); 26 | void swap(@IntRange(from = 0) int index, @IntRange(from = 0) int index2); 27 | void sort(@NonNull Comparator comparator); 28 | void clear(); 29 | 30 | public static interface Callback { 31 | void onChanged(int index); 32 | void onAdded(int index); 33 | void onRemoved(int index); 34 | void onSwapped(int index, int index2); 35 | 36 | void onChanged(); 37 | void onRangeAdded(int index, int size); 38 | void onRangeRemoved(int index, int size); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/ILoadingView.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * @author cncoderx 7 | */ 8 | public interface ILoadingView { 9 | // public static final int STATE_DEFAULT = 0; 10 | public static final int STATE_HIDDEN = 0; 11 | public static final int STATE_SHOW = 1; 12 | public static final int STATE_ERROR = 2; 13 | public static final int STATE_END = 3; 14 | public static final int STATE_GONE = 4; 15 | 16 | void show(); 17 | void hidden(); 18 | void error(); 19 | void end(); 20 | void gone(); 21 | int getState(); 22 | View getView(); 23 | } 24 | -------------------------------------------------------------------------------- /library/src/main/java/com/cncoderx/recyclerviewhelper/utils/SpacingItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper.utils; 2 | 3 | import android.graphics.Rect; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | import android.view.View; 6 | 7 | /** 8 | * @author cncoderx 9 | */ 10 | @Deprecated 11 | public class SpacingItemDecoration extends RecyclerView.ItemDecoration { 12 | private int mHalfSpace; 13 | private boolean hasPadding; 14 | 15 | public SpacingItemDecoration(int space) { 16 | mHalfSpace = space / 2; 17 | } 18 | 19 | @Override 20 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 21 | if (!hasPadding) { 22 | hasPadding = true; 23 | parent.setPadding(mHalfSpace, mHalfSpace, mHalfSpace, mHalfSpace); 24 | } 25 | outRect.set(mHalfSpace, mHalfSpace, mHalfSpace, mHalfSpace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /library/src/main/res/layout/layout_loading_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 20 | 21 | 28 | 29 | 30 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | 59 | 60 | -------------------------------------------------------------------------------- /library/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 加载中… 4 | 加载完成 5 | 加载失败 6 | 没有更多内容 7 | -------------------------------------------------------------------------------- /library/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 45dp 4 | -------------------------------------------------------------------------------- /library/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Library 3 | Loading… 4 | Loaded 5 | Load failed 6 | Nothing more 7 | 8 | -------------------------------------------------------------------------------- /library/src/test/java/com/cncoderx/recyclerviewhelper/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cncoderx.recyclerviewhelper; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':library' 2 | --------------------------------------------------------------------------------