# ByRecyclerView
English | [简体中文](README.md)
**ByRecyclerView is an Android RecyclerView library** for building list screens with pull-to-refresh, automatic or pull-up load more, headers, footers, empty states, and a simplified adapter. It extends the Android View-based RecyclerView; it is not a native Jetpack Compose component.
## Status
**Actively maintained.** Latest release: [1.4.2](https://github.com/youlookwhat/ByRecyclerView/releases/tag/1.4.2), available via JitPack. [](https://jitpack.io/#youlookwhat/ByRecyclerView) Please report problems in [Issues](https://github.com/youlookwhat/ByRecyclerView/issues).
## Integrating with an AI coding assistant
The [AI integration guide](AGENTS.md) describes the APIs and common pitfalls. It is not automatically loaded into other projects, so ask the assistant to read it explicitly. Copy and adapt this prompt:
```text
Use https://github.com/youlookwhat/ByRecyclerView to add pull-to-refresh and automatic load more to this Android View-based list. Read the repository's README and AGENTS.md first, adapt the integration to this project's Gradle configuration and data source, handle empty, failure, retry and end-of-list states, and build and verify it. Report anything you could not verify.
```
Adjust the request to your app and preferred loading mode. ByRecyclerView is not a native Compose list.
## Features
- Pull-to-refresh, with customizable refresh and load-more views; can also be used with SwipeRefreshLayout.
- Pull-up or automatic load more, with a configurable preload distance.
- Header, footer, and state views; `setPageData` handles first-page empty states and subsequent-page updates.
- Simplified adapters, item and child click/long-click listeners, and payload updates.
- Linear, grid, and staggered-grid item decorations, sticky headers, and skeleton screens.
- DataBinding support and a separate [ViewBinding example](https://github.com/youlookwhat/android-learning/tree/master/ByRv-viewbinding/app/src/main/java/me/jingbin/byrv/viewbinding).
## Installation
For projects using central repository management, add JitPack to `settings.gradle`:
```groovy
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
```
Or in `settings.gradle.kts`:
```kotlin
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
```
For older projects that use `allprojects.repositories` in the root `build.gradle`, add JitPack there instead.
Add these dependencies to the app module:
```groovy
dependencies {
implementation 'com.github.youlookwhat:ByRecyclerView:1.4.2'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'com.google.android.material:material:1.10.0'
}
```
Kotlin DSL:
```kotlin
dependencies {
implementation("com.github.youlookwhat:ByRecyclerView:1.4.2")
implementation("androidx.recyclerview:recyclerview:1.3.0")
implementation("com.google.android.material:material:1.10.0")
}
```
The library declares RecyclerView and Material as `compileOnly`, so the app must provide them. If your app already includes them, use versions compatible with your project. The library module declares `minSdk` 14; the effective minimum also depends on the dependencies selected by your app.
## Quick start
Add the view to an Activity layout:
```xml
```
The following Java example uses local data to demonstrate refresh and the end-of-list state; replace it with your own data source. `android.R.layout.simple_list_item_1` supplies the item layout. Add these imports to your Activity:
```java
import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.ArrayList;
import java.util.Arrays;
import me.jingbin.library.ByRecyclerView;
import me.jingbin.library.adapter.BaseByViewHolder;
import me.jingbin.library.adapter.BaseRecyclerAdapter;
```
Then use this code after `setContentView(...)`:
```java
ByRecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
BaseRecyclerAdapter adapter =
new BaseRecyclerAdapter(android.R.layout.simple_list_item_1) {
@Override
protected void bindView(BaseByViewHolder holder, String item, int position) {
holder.setText(android.R.id.text1, item);
}
};
recyclerView.setAdapter(adapter);
TextView emptyView = new TextView(this);
emptyView.setText("No items");
adapter.setPageEmptyView(emptyView);
recyclerView.setOnRefreshListener(new ByRecyclerView.OnRefreshListener() {
@Override
public void onRefresh() {
adapter.setPageData(true, new ArrayList<>(Arrays.asList("First", "Second")));
}
});
recyclerView.setOnLoadMoreListener(true, 1, new ByRecyclerView.OnLoadMoreListener() {
@Override
public void onLoadMore() {
adapter.setPageData(false, new ArrayList()); // No more pages
}
});
adapter.setPageData(true, new ArrayList<>(Arrays.asList("First", "Second")));
```
The equivalent setup in Kotlin. Add these imports to your Activity:
```kotlin
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import me.jingbin.library.ByRecyclerView
import me.jingbin.library.adapter.BaseByViewHolder
import me.jingbin.library.adapter.BaseRecyclerAdapter
```
Then use this code after `setContentView(...)`:
```kotlin
val recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
val adapter = object : BaseRecyclerAdapter(android.R.layout.simple_list_item_1) {
override fun bindView(holder: BaseByViewHolder, item: String, position: Int) {
holder.setText(android.R.id.text1, item)
}
}
recyclerView.adapter = adapter
adapter.setPageEmptyView(TextView(this).apply { text = "No items" })
recyclerView.setOnRefreshListener {
adapter.setPageData(true, arrayListOf("First", "Second"))
}
recyclerView.setOnLoadMoreListener(true, 1) {
adapter.setPageData(false, arrayListOf())
}
adapter.setPageData(true, arrayListOf("First", "Second"))
```
`setPageData` requires the adapter to be attached to a `ByRecyclerView` first. A nonempty first page replaces the data; an empty first page displays the configured empty view and disables load more. A nonempty later page is appended and completes loading; an empty later page marks the end. Use a mutable list, since later pages are appended to it. This helper is not intended for showing a state view above existing list items.
For real requests, update the UI on the main thread. Do not treat a failed request as an empty successful page: stop a failed refresh with `recyclerView.setRefreshing(false)`, or call `recyclerView.loadMoreFail()` for a failed load-more request, and show an error to the user. Advance your page cursor only after success, and manage concurrent requests in your app. To manage the load-more state yourself, use `adapter.addData(...)` followed by `loadMoreComplete()`, or `loadMoreEnd()` when there are no more pages.
`setOnLoadMoreListener(true, 1, ...)` enables automatic loading near the end. The overload without the boolean uses pull-up-and-release loading. `setLoadMoreEnabled(false)` disables load more entirely.
## More examples
- [Chinese README](README.md): item decorations, header/footer views, clicks, sticky headers, and skeleton screens.
- [Demo app](app/src/main/java/me/jingbin/byrecyclerview/) and [Wiki](https://github.com/youlookwhat/ByRecyclerView/wiki).
- [Release notes](https://github.com/youlookwhat/ByRecyclerView/releases).
## License
[Apache License 2.0](LICENSE).