See other recyclerview library (https://github.com/utsmannn/painless-paging-library)
Make easy and faster RecyclerView without adapter, design for kotlin.
Support standard adapter and paged adapter RecyclerView base on Android Paging Library
For standard adapter
implementation "com.utsman.recycling:recycling:${latest}"
For paged adapter
implementation "com.utsman.recycling-paged:recycling:${latest}"
For standard adapter
implementation "com.utsman.recycling-android:recycling:${latest}"
For paged adapter
implementation "com.utsman.recycling-paged-android:recycling:${latest}"
For standard use .setupAdapter<>
recyclerView.setupAdapter<Item>(R.layout.item_view) { adapter, context, list ->
...
}
For paging use .setupAdapterPaged<>
recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
...
}
Setup parameter | Desc |
---|---|
bind { } |
recycling your holder |
adapter |
get adapter |
context |
get context |
list |
get current list |
setLayoutManager(layout_manager) |
recycling layout manager |
setDivider(divider) |
add divider |
submitList(list) |
submit your list |
submitItem(item) |
add item in list (only for standard adapter) |
submitNetwork(networkState) |
submit network state |
fixGridSpan(column_size) |
fix grid span for grid layout when network state enabled |
onPagingListener(layoutManager) |
paging helper (only for standard adapter) |
addLoader(layout) { } |
add loader |
In lamba of recycling, use bind
to instead viewholder
recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
// recycling your holder
bind { itemView, position, item ->
// bind view
itemView.img_view.load(item?.url)
itemView.setOnClickListener {
toast("Click on $position")
}
}
}
Bind parameter | Desc |
---|---|
itemView |
itemView |
item |
item |
position |
item position |
Default layout manager is LinearLayoutManager
, you can set layout manager with
recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
// recycling your layout manager
setLayoutManager(GridLayoutManager(context))
}
You can set list / submit list inside lamba with submitList(list)
recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
...
submitList(yourList)
}
This library support for network loader, use paged recycling is recommended
loader state | error state |
---|---|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress_circular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="30dp"
tools:ignore="UnusedAttribute"
android:indeterminateTint="@color/colorPrimary"
android:indeterminateTintMode="src_atop" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Error"
android:textColor="@android:color/holo_red_light"
android:id="@+id/error_text_view"
android:layout_margin="12dp"
tools:ignore="HardcodedText" />
</LinearLayout>
For create loader, use addLoader(layout)
bind your id in layout loader
addLoader(R.layout.item_loader) {
idLoader = R.id.progress_circular
idTextError = R.id.error_text_view
}
Add network state in viewmodel or etc for user to see data process
// define network state with mutable livedata
val networkState: MutableLiveData<NetworkState> = MutableLiveData()
// for error state
networkState.postValue(NetworkState.error("error network: ${t.message}"))
// for loading state
networkState.postValue(NetworkState.LOADING)
// for loaded state
networkState.postValue(NetworkState.LOADED)
// and submit in your recycling
submitNetworkState(networkState)
Use fixGridSpan(column_size)
recyclerView.setupAdapterPaged<Item>(R.layout.item_view) { adapter, context, list ->
...
val layoutManager = GridLayoutManager(context, 2)
setLayoutManager(layoutManager)
fixGridSpan(2)
}
Use onPagingListener(layoutManager)
for paging recycler
recyclerView.setupAdapter<Item>(R.layout.item_view) { adapter, context, list ->
...
onPagingListener(layoutManager) { page, itemCount ->
// recycling data with page + 1
}
}
Just list of string
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listData = listOf("satu", "dua", "tiga", "empat")
main_recycler_view.setupAdapter<String>(R.layout.simple_item_view) { adapter, context, list ->
bind { itemView, position, item ->
itemView.name_item.text = item
}
submitList(listData)
}
}
}
For this sample code, I using Pexel Api for get photos and viewmodel pattern
// View Model
class SampleViewModel : ViewModel() {
private val instance = RetrofitInstance.create()
private val networkState: MutableLiveData<NetworkState> = MutableLiveData()
// get list
fun getCuratedPhoto(perPage: Int, page: Int): LiveData<List<Pexel>?> {
val newList: MutableLiveData<List<Pexel>?> = MutableLiveData()
// network state is loading
networkState.postValue(NetworkState.LOADING)
// call api
instance.getCuratedPhoto(perPage, page)
.enqueue(object : Callback<Responses> {
override fun onFailure(call: Call<Responses>, t: Throwable) {
// network state error with error message
networkState.postValue(NetworkState.error("error network: ${t.message}"))
}
override fun onResponse(call: Call<Responses>, response: Response<Responses>) {
val listResponse = response.body()?.photos
newList.postValue(listResponse)
// network state loaded
networkState.postValue(NetworkState.LOADED)
}
})
return newList
}
// get network state
fun getNetworkState(): LiveData<NetworkState> = networkState
}
// Activity
class MainActivity : AppCompatActivity() {
private val viewModel by lazy {
ViewModelProviders.of(this)[PexelViewModel::class.java]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// setup recycling
main_recycler_view.setupAdapter<Pexel>(R.layout.item_view) { adapter, context, list ->
// bind is viewholder function
bind { itemView, position, item ->
itemView.img_view.load(item?.src?.small)
itemView.setOnClickListener {
Toast.makeText(context, "wee ${adapter.itemCount} - ${list.size} - $position", Toast.LENGTH_SHORT).show()
}
}
// add loader state
addLoader(R.layout.item_loader) {
idLoader = R.id.progress_circular
idTextError = R.id.error_text_view
}
// using grid layout manager
val layoutManager = GridLayoutManager(this@MainActivity, 2)
setLayoutManager(layoutManager)
// for grid layout manager, loader by default is ugly, to fix use fixGridSpan
fixGridSpan(2)
// call function setupData with page 1
setupData(this, 1)
// use paging listener for endless recycler view and loaded data
onPagingListener(layoutManager) { page, itemCount ->
// call function setup data with page +1
setupData(this@setupAdapter, page+1)
}
}
}
// function for setup data
private fun setupData(recycling: Recycling<Pexel>, page: Int) {
viewModel.getCuratedPhoto(20, page).observe(this, Observer {
// submit list from viewmodel into recycling
recycling.submitList(it)
})
viewModel.getNetworkState().observe(this, Observer {
// submit network state from viewmodel into recycling
recycling.submitNetworkState(it)
})
}
}
Copyright 2019 Muhammad Utsman
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.