Skip to content

Commit 8b78ac4

Browse files
authored
Merge pull request #6 from manneohlund/rc-2.2.0
Rc 2.2.0
2 parents cdfee5a + 3319cc7 commit 8b78ac4

24 files changed

+464
-53
lines changed

Diff for: README.md

+33-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ allprojects {
2323
#### Step 2. Add the dependency
2424
```groovy
2525
dependencies {
26-
implementation 'com.github.manneohlund:smart-recycler-adapter:2.1.0'
26+
implementation 'com.github.manneohlund:smart-recycler-adapter:2.2.0'
2727
}
2828
```
2929

@@ -172,7 +172,38 @@ SmartRecyclerAdapter
172172
(view, actionId, position) -> openMovieInfo())
173173
.into(recyclerView);
174174
```
175-
175+
176+
### SmartEndlessScrollRecyclerAdapter
177+
178+
A popular feature in apps is to have endless scrolling with pagination, in other words load more items when user has scrolled to bottom.
179+
With SmartEndlessScrollRecyclerAdapter you can achieve this.
180+
181+
#### 1. Create adapter
182+
```java
183+
SmartEndlessScrollRecyclerAdapter endlessScrollAdapter = SmartEndlessScrollRecyclerAdapter
184+
.items(items)
185+
.map(MovieModel.class, MovieViewHolder.class)
186+
.into(recyclerView);
187+
```
188+
189+
#### 2. Set OnLoadMoreListener to your SmartEndlessScrollRecyclerAdapter
190+
191+
Called when scrolled to the last item and loading view is visible.
192+
193+
```java
194+
endlessScrollAdapter.setOnLoadMoreListener(() -> {
195+
endlessScrollAdapter.addItems(moreItems);
196+
});
197+
```
198+
199+
#### More SmartEndlessScrollRecyclerAdapter features
200+
201+
Enable/Disable endless scrolling and thus removing the loading view.
202+
`endlessScrollAdapter.setEndlessScrollEnabled(false);`
203+
204+
You can also set your custom loading/loadmore view.
205+
`endlessScrollAdapter.setCustomLoadMoreLayoutResource(R.layout.your_custom_loadmore_view);`
206+
176207
### Adapter creation with ViewTypeResolver
177208

178209
If you want to bind one data type with different view holders depending on some attribute you can set a ViewTypeResolver.

Diff for: build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ buildscript {
2222
allprojects {
2323
// Smart Adapter global version code and name
2424
ext {
25-
VERSION_CODE = 7
26-
VERSION_NAME = '2.1.0'
25+
VERSION_CODE = 8
26+
VERSION_NAME = '2.2.0'
2727
TARGET_SDK_VERSION = 28
2828
MIN_SDK_VERSION = 14
2929
}

Diff for: sample/src/main/java/com/example/smartrecycleradapter/DemoActivity.java

+39-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import android.content.Intent;
99
import android.os.Bundle;
10+
import android.os.Handler;
1011
import android.support.v4.app.ActivityCompat;
1112
import android.support.v7.app.AppCompatActivity;
1213
import android.support.v7.widget.RecyclerView;
@@ -43,13 +44,14 @@
4344
import java.util.List;
4445
import java.util.Locale;
4546

47+
import smartadapter.SmartEndlessScrollRecyclerAdapter;
4648
import smartadapter.SmartRecyclerAdapter;
4749

4850
public class DemoActivity extends AppCompatActivity {
4951

5052
RecyclerView recyclerView;
51-
SmartRecyclerAdapter mainSmartMovieAdapter;
52-
SmartRecyclerAdapter comingSoonSmartMovieAdapter;
53+
SmartEndlessScrollRecyclerAdapter mainSmartMovieAdapter;
54+
SmartEndlessScrollRecyclerAdapter comingSoonSmartMovieAdapter;
5355
SmartRecyclerAdapter myWatchListSmartMovieAdapter;
5456
SmartRecyclerAdapter actionMoviesSmartMovieAdapter;
5557
SmartRecyclerAdapter adventuresMoviesSmartMovieAdapter;
@@ -84,7 +86,7 @@ private void initSmartRecyclerAdapter() {
8486
items.add(new RecentlyPlayedMoviesModel("Recently played"));
8587
items.add(new CopyrightModel(String.format("SmartRecyclerAdapter v%s\n\nDeveloped by Manne Öhlund", BuildConfig.VERSION_NAME)));
8688

87-
mainSmartMovieAdapter = SmartRecyclerAdapter
89+
mainSmartMovieAdapter = SmartEndlessScrollRecyclerAdapter
8890
.items(items)
8991
.map(MoviePosterModel.class, PosterViewHolder.class)
9092
.map(MovieBannerModel.class, BannerViewHolder.class)
@@ -184,10 +186,25 @@ private void initSmartRecyclerAdapter() {
184186
.map(RecentlyPlayedMoviesViewHolder.class, recentlyPlayedMoviesSmartMovieAdapter)
185187

186188
.into(recyclerView);
189+
190+
// Endless pagination
191+
mainSmartMovieAdapter.setOnLoadMoreListener(() -> {
192+
Toast.makeText(getApplicationContext(), "LoadMore", Toast.LENGTH_SHORT).show();
193+
194+
int indexBeforeCopyright = 2;
195+
new Handler().postDelayed(() -> {
196+
mainSmartMovieAdapter.addItem(
197+
mainSmartMovieAdapter.getItemCount() - indexBeforeCopyright,
198+
new MovieBannerModel("More items loaded", MovieDataItems.INSTANCE.getRandomBanner())
199+
);
200+
},
201+
800);
202+
});
187203
}
188204

205+
int moreItemsLoadedCount = 0;
189206
private void initNestedSmartRecyclerAdapters() {
190-
comingSoonSmartMovieAdapter = SmartRecyclerAdapter.items(MovieDataItems.INSTANCE.getComingSoonItems())
207+
comingSoonSmartMovieAdapter = SmartEndlessScrollRecyclerAdapter.items(MovieDataItems.INSTANCE.getComingSoonItems())
191208
.map(MovieModel.class, LargeThumbViewHolder.class)
192209
.addViewEventListener(
193210
LargeThumbViewHolder.class,
@@ -203,6 +220,24 @@ private void initNestedSmartRecyclerAdapters() {
203220
})
204221
.create();
205222

223+
// Set custom load more view
224+
comingSoonSmartMovieAdapter.setCustomLoadMoreLayoutResource(R.layout.custom_loadmore_view);
225+
226+
// Pagination ends after 3 loads
227+
comingSoonSmartMovieAdapter.setOnLoadMoreListener(() -> {
228+
Toast.makeText(getApplicationContext(), "LoadMore", Toast.LENGTH_SHORT).show();
229+
230+
new Handler().postDelayed(() -> {
231+
comingSoonSmartMovieAdapter.addItems(
232+
comingSoonSmartMovieAdapter.getItemCount()-1,
233+
MovieDataItems.INSTANCE.getLoadMoreItems()
234+
);
235+
if (moreItemsLoadedCount++ == 2)
236+
comingSoonSmartMovieAdapter.setEndlessScrollEnabled(false);
237+
},
238+
1000);
239+
});
240+
206241
myWatchListSmartMovieAdapter = SmartRecyclerAdapter.items(MovieDataItems.INSTANCE.getMyWatchListItems())
207242
.map(MovieModel.class, ThumbViewHolder.class)
208243
.addViewEventListener(

Diff for: sample/src/main/java/com/example/smartrecycleradapter/MovieCategoryDetailsActivity.kt

+43-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.example.smartrecycleradapter
22

33
import android.os.Bundle
4+
import android.os.Handler
45
import android.support.v7.app.AppCompatActivity
56
import android.support.v7.widget.GridLayoutManager
67
import android.widget.Toast
@@ -10,8 +11,8 @@ import com.example.smartrecycleradapter.models.MovieModel
1011
import com.example.smartrecycleradapter.viewholder.HeaderViewHolder
1112
import com.example.smartrecycleradapter.viewholder.ThumbViewHolder
1213
import kotlinx.android.synthetic.main.activity_movie_category_details.*
14+
import smartadapter.SmartEndlessScrollRecyclerAdapter
1315
import smartadapter.SmartRecyclerAdapter
14-
import java.util.Arrays.asList
1516

1617
enum class MovieType(val title: String) {
1718
COMING_SOON("Coming soon"),
@@ -24,14 +25,15 @@ enum class MovieType(val title: String) {
2425

2526
class MovieCategoryDetailsActivity : AppCompatActivity() {
2627

27-
private lateinit var movieType: MovieType;
28+
private lateinit var movieType: MovieType
29+
private var endlessScrollCount = 0
2830

2931
override fun onCreate(savedInstanceState: Bundle?) {
3032
super.onCreate(savedInstanceState)
3133
setContentView(R.layout.activity_movie_category_details)
3234

3335
intent?.getIntExtra("MovieType", MovieType.ANIMATED.ordinal)?.let {
34-
movieType = MovieType.values()[it];
36+
movieType = MovieType.values()[it]
3537
}
3638

3739
initSmartRecyclerAdapter()
@@ -45,11 +47,10 @@ class MovieCategoryDetailsActivity : AppCompatActivity() {
4547
MovieType.ADVENTURE -> MovieDataItems.nestedAdventureItems
4648
MovieType.ANIMATED -> MovieDataItems.nestedAnimatedItems
4749
MovieType.SCI_FI -> MovieDataItems.nestedSciFiItems
48-
else -> asList()
4950
}
5051

5152
val adapterItems: ArrayList<Any> = ArrayList<Any>()
52-
adapterItems.add(movieType.title);
53+
adapterItems.add(movieType.title)
5354
adapterItems.addAll(movieItems)
5455

5556
val gridAutoLayoutManager = GridAutoLayoutManager(this, 100)
@@ -59,13 +60,43 @@ class MovieCategoryDetailsActivity : AppCompatActivity() {
5960
}
6061
}
6162

62-
SmartRecyclerAdapter.items(adapterItems)
63-
.map(String::class.java, HeaderViewHolder::class.java)
64-
.map(MovieModel::class.java, ThumbViewHolder::class.java)
65-
.setLayoutManager(gridAutoLayoutManager)
66-
.addViewEventListener(ThumbViewHolder::class.java, R.id.action_on_click) { view, actionId, position ->
67-
Toast.makeText(this, "Movie $position", Toast.LENGTH_SHORT).show()
63+
when (movieType) {
64+
MovieType.COMING_SOON, MovieType.MY_WATCH_LIST -> {
65+
SmartRecyclerAdapter.items(adapterItems)
66+
.map(String::class.java, HeaderViewHolder::class.java)
67+
.map(MovieModel::class.java, ThumbViewHolder::class.java)
68+
.setLayoutManager(gridAutoLayoutManager)
69+
.addViewEventListener(ThumbViewHolder::class.java, R.id.action_on_click) { view, actionId, position ->
70+
Toast.makeText(this, "Movie $position", Toast.LENGTH_SHORT).show()
71+
}
72+
.into(recyclerView)
73+
}
74+
MovieType.ACTION, MovieType.ADVENTURE,MovieType.ANIMATED, MovieType.SCI_FI -> {
75+
val endlessScrollAdapter: SmartEndlessScrollRecyclerAdapter = SmartEndlessScrollRecyclerAdapter.items(adapterItems)
76+
.map(String::class.java, HeaderViewHolder::class.java)
77+
.map(MovieModel::class.java, ThumbViewHolder::class.java)
78+
.setLayoutManager(gridAutoLayoutManager)
79+
.addViewEventListener(ThumbViewHolder::class.java, R.id.action_on_click) { view, actionId, position ->
80+
Toast.makeText(this, "Movie $position", Toast.LENGTH_SHORT).show()
81+
}
82+
.into(recyclerView)
83+
84+
endlessScrollAdapter.setOnLoadMoreListener {
85+
if (!endlessScrollAdapter.isLoading) {
86+
endlessScrollAdapter.setIsLoading(true)
87+
Toast.makeText(applicationContext, "LoadMore", Toast.LENGTH_SHORT).show()
88+
89+
Handler().postDelayed({
90+
endlessScrollAdapter.addItems(movieItems)
91+
if (endlessScrollCount++ == 3) {
92+
endlessScrollAdapter.setEndlessScrollEnabled(false);
93+
}
94+
endlessScrollAdapter.setIsLoading(false)
95+
},
96+
3000)
97+
}
6898
}
69-
.into(recyclerView)
99+
}
100+
}
70101
}
71102
}

Diff for: sample/src/main/java/com/example/smartrecycleradapter/data/MovieDataItems.kt

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object MovieDataItems {
1717
const val THUMBS_BASE_URL = "https://raw.githubusercontent.com/manneohlund/smart-recycler-adapter-resources/master/thumbs/"
1818

1919
// Coming soon
20-
val comingSoonItems: List<Any> = asList(
20+
val comingSoonItems: List<Any> = mutableListOf(
2121
MovieModel("Fist man", "first_man"),
2222
MovieModel("Terminator dark fate", "terminator_dark_fate"),
2323
MovieModel("Murder Mystery", "murder_mystery"),
@@ -40,6 +40,23 @@ object MovieDataItems {
4040
MovieModel("Abominable", "abominable")
4141
)
4242

43+
// Load more items
44+
val loadMoreItems: List<Any> = asList(
45+
MovieModel("Terminator dark fate", "terminator_dark_fate"),
46+
MovieModel("Joker", "joker"),
47+
MovieModel("Fist man", "first_man"),
48+
MovieModel("The Lion king", "lion_king"),
49+
MovieModel("John Wick 3", "john_wick_3"),
50+
MovieModel("Grinch", "grinch"),
51+
MovieModel("Wonder Woman", "woderwoman"),
52+
MovieModel("Hellboy", "hellboy"),
53+
MovieModel("Predator", "predator"),
54+
MovieModel("It 2", "it_2"),
55+
MovieModel("Once upon a time in Hollywood", "once_hollywood"),
56+
MovieModel("Age of uprising", "age_of_uprising"),
57+
MovieModel("Murder Mystery", "murder_mystery")
58+
)
59+
4360
// My watchlist
4461
val myWatchListItems: List<Any> = mutableListOf(
4562
MovieModel("Joker", "joker"),

Diff for: sample/src/main/res/layout/custom_loadmore_view.xml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:id="@+id/progressBar"
4+
style="@style/Base.Widget.AppCompat.ProgressBar"
5+
android:layout_width="160dp"
6+
android:layout_height="240dp"
7+
android:layout_gravity="center"
8+
android:padding="60dp" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package smartadapter;
2+
3+
/*
4+
* Created by Manne Öhlund on 2019-07-29.
5+
* Copyright (c) All rights reserved.
6+
*/
7+
8+
import android.support.annotation.LayoutRes;
9+
import android.support.annotation.NonNull;
10+
11+
import smartadapter.listener.OnLoadMoreListener;
12+
13+
/**
14+
* Defines the extension methods for {@link SmartEndlessScrollRecyclerAdapter}.
15+
*/
16+
public interface ISmartEndlessScrollRecyclerAdapter {
17+
18+
/**
19+
* Used to determine if loading view should show or not.
20+
* If {@link #isEndlessScrollEnabled()} returns true this returns 1.
21+
* @return offset loading view count
22+
*/
23+
int getEndlessScrollOffset();
24+
25+
/**
26+
* Checks if endless scrolling is enabled.
27+
* @return endless scrolling enabled
28+
*/
29+
boolean isEndlessScrollEnabled();
30+
31+
/**
32+
* Setter for enabling endless scrolling by letting the {@link SmartEndlessScrollRecyclerAdapter} render a loading view.
33+
* @param enabled if true enables endless scrolling.
34+
*/
35+
void setEndlessScrollEnabled(boolean enabled);
36+
37+
/**
38+
* Checks if the {@link SmartEndlessScrollRecyclerAdapter} is in loading state.
39+
* Good to use when async loading takes time and user scrolls back and forth.
40+
* @return loading state
41+
*/
42+
boolean isLoading();
43+
44+
/**
45+
* Setting the loading state to {@link SmartEndlessScrollRecyclerAdapter}.
46+
* @param loading state for loading more items
47+
*/
48+
void setIsLoading(boolean loading);
49+
50+
/**
51+
* Setter for {@link OnLoadMoreListener} callback for listening on when the {@link SmartEndlessScrollRecyclerAdapter}
52+
* is showing the {@link smartadapter.viewholder.LoadMoreViewHolder}.
53+
* @param onLoadMoreListener load more callback
54+
*/
55+
void setOnLoadMoreListener(@NonNull OnLoadMoreListener onLoadMoreListener);
56+
57+
/**
58+
* Enables customization of the layout for the {@link smartadapter.viewholder.LoadMoreViewHolder}.
59+
* @param loadMoreLayoutResource layout resource
60+
*/
61+
void setCustomLoadMoreLayoutResource(@LayoutRes int loadMoreLayoutResource);
62+
}

Diff for: smartadapter/src/main/java/smartadapter/ISmartRecyclerAdapter.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import java.util.HashMap;
1212
import java.util.List;
1313

14-
import smartadapter.internal.Mapper;
14+
import smartadapter.internal.mapper.ViewHolderMapper;
1515
import smartadapter.listener.ViewEventListener;
1616
import smartadapter.viewholder.SmartViewHolder;
1717
import smartadapter.widget.ViewTypeResolver;
@@ -230,9 +230,9 @@ public interface ISmartRecyclerAdapter {
230230

231231
/**
232232
* Returns the data item view holder mapper.
233-
* @return Mapper
233+
* @return ViewHolderMapper
234234
*/
235-
Mapper getMapper();
235+
ViewHolderMapper getMapper();
236236

237237
/**
238238
* Returns {@link ViewTypeResolver}.

0 commit comments

Comments
 (0)