![](yasha.png)
# Yasha
A DSL library for rendering RecyclerView and ViewPager and Compose List.
> *Read this in other languages: [中文](README.zh.md), [English](README.md), [Changelog](CHANGELOG.md)*
## Feature introduction:
✅ Support RecyclerView
✅ Support ViewPager
✅ Support MultiType
✅ Support Header and Footer
✅ Support automatic paging loading
✅ Support DiffUtil
✅ Support loading status display
✅ Support automatic clean up resources
✅ Support Compose
![](yasha_usage.png)
## Prepare
1. Add jitpack to build.gradle
```gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
```
2. Add Dependencies
```gradle
dependencies {
implementation 'com.github.ssseasonnn:Yasha:1.2.0'
// or
implementation 'com.github.ssseasonnn.Yasha:yasha:1.2.0' //only for recyclerview
implementation 'com.github.ssseasonnn.Yasha:yasha-compose:1.2.0' //only for compose
}
```
## Basic usage
### 1. Render RecyclerView
```kotlin
//Create data class
class RecyclerViewItem(val i: Int, val text: String = "") : YashaItem
//Create DataSource
val dataSource = YashaDataSource()
//Render RecyclerView
recyclerView.linear(dataSource) {
renderBindingItem {
onBind {
itemBinding.tvNormalContent.text = "position: $position, data: $data"
}
}
}
```
### 2. Render ViewPager
```kotlin
//Create data class
class ViewPagerItem(val i: Int, val text: String = "") : YashaItem
//Create DataSource
val dataSource = YashaDataSource()
//Render ViewPager
viewPager.vertical(dataSource) {
renderBindingItem {
onBind {
itemBinding.tvNormalContent.text = "position: $position, data: $data"
}
}
}
```
## Other configurations
### 1. Render Type
Yasha supports multiple types of RecyclerView, such as list, Grid, Stagger, Pager and custom list types
```kotlin
//Render List
recyclerView.linear(dataSource) {
//Set the direction to vertical list or horizontal list
orientation(RecyclerView.VERTICAL)
renderBindingItem {}
}
//Render Grid
recyclerView.grid(dataSource) {
//Set the number of columns
spanCount(2)
renderBindingItem {
//Set the number of columns corresponding to this item
gridSpanSize(2)
onBind {}
}
}
//Render waterfall flow
recyclerView.stagger(dataSource) {
//Set the number of columns
spanCount(2)
renderBindingItem {
staggerFullSpan(true)
onBind {}
}
}
//Render Page
recyclerView.pager(dataSource) {
//Register page change callback
onPageChanged { position, yashaItem, view ->
Toast.makeText(this, "This is page $position", Toast.LENGTH_SHORT).show()
}
}
//Render custom layout
recyclerView.custom(customLayoutManager, dataSource) {}
```
### 2. DataSource paging load
```kotlin
class CustomDataSource(coroutineScope: CoroutineScope) : YashaDataSource(coroutineScope) {
var page = 0
// Called when initializing the load
override suspend fun loadInitial(): List? {
page = 0
val items = mutableListOf()
for (i in 0 until 10) {
items.add(NormalItem(i))
}
// Return null to trigger loading failure
// Return to the empty list to trigger no more
// Return init data
return items
}
// Called on paging load
override suspend fun loadAfter(): List? {
page++
if (page % 5 == 0) {
// Return null to trigger loading failure
return null
}
val items = mutableListOf()
for (i in 0 until 10) {
items.add(NormalItem(i))
}
// Return to the empty list to trigger no more
return items
}
}
```
### 3. Render MultiType
```kotlin
//Define data type A
class AItem(val i: Int) : YashaItem
//Define data type B
class BItem(val i: Int) : YashaItem
//Render Items
recyclerView.linear(dataSource) {
//Render Type A
renderBindingItem {
onBind {
//render
...
}
}
//Render Type B
renderBindingItem {
onBind {
//render
...
}
}
}
```
### 4. Header and Footer
DataSource supports the following methods for adding headers and footers:
```kotlin
//Headers
fun addHeader(t: T, position: Int = -1, delay: Boolean = false)
fun addHeaders(list: List, position: Int = -1, delay: Boolean = false)
fun removeHeader(t: T, delay: Boolean = false)
fun setHeader(old: T, new: T, delay: Boolean = false)
fun getHeader(position: Int): T
fun clearHeader(delay: Boolean = false)
//Footers
fun addFooter(t: T, position: Int = -1, delay: Boolean = false)
fun addFooters(list: List, position: Int = -1, delay: Boolean = false)
fun removeFooter(t: T, delay: Boolean = false)
fun setFooter(old: T, new: T, delay: Boolean = false)
fun getFooter(position: Int): T
fun clearFooter(delay: Boolean = false)
```
### 5. Partial refresh
By rewriting the Diff method of the data class, you can complete efficient local refresh:
```kotlin
//Override Diff method when defining data type
class NormalItem(val i: Int, val text: String = "") : YashaItem {
override fun areItemsTheSame(other: Differ): Boolean {
if (other !is NormalItem) return false
return other.i == i
}
override fun areContentsTheSame(other: Differ): Boolean {
if (other !is NormalItem) return false
return other.text == text
}
//Set up payload
override fun getChangePayload(other: Differ): Any? {
if (other !is NormalItem) return null
return other.text
}
}
//Use dataSource to update the new Item data
val oldItem = NormalItem(1, "1")
val newItem = NormalItem(2, "2")
dataSource.setItem(oldItem, newItem)
// Register onBindPayload at render time
recyclerView.linear(dataSource) {
renderBindingItem {
onBind {
itemBinding.tvNormalContent.text = "position: $position, data: $data"
}
//Partial refresh use
onBindPayload {
//Take out payload for partial refresh
val payload = it[0]
if (payload != null) {
itemBinding.tvNormalContent.text = payload.toString()
}
}
}
}
```
### 6. Custom Load Status
```kotlin
//Use default load state
val dataSource = YashaDataSource(enableDefaultState = true)
//Custom LoadStateItem
class CustomStateItem(val state: Int) : YashaItem
class CustomDataSource : YashaDataSource(enableDefaultState = false) {
override fun onStateChanged(newState: Int) {
setState(CustomStateItem(newState))
}
}
//Render Custom State
recyclerView.linear(dataSource) {
...
renderBindingItem {
onBind {
when (data.state) {
FetchingState.FETCHING -> {
//loading...
}
FetchingState.FETCHING_ERROR -> {
//loading failed
}
FetchingState.DONE_FETCHING -> {
//loading complete
}
else -> {
//other
}
}
}
}
}
```
### 7. Proguard
Only when using reflection to create ViewBinding, you need to add the following guard rules:
```pro
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
public static ** inflate(...);
}
```
## License
> ```
> Copyright 2021 Season.Zlc
>
> 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.
> ```