├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── list │ │ └── rados │ │ └── recyclerviewlibrary │ │ └── MainActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── item.xml │ ├── item_custom.xml │ └── item_second.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── fast-list ├── .gitignore ├── build.gradle ├── deploy.gradle ├── keystore.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── list │ │ └── rados │ │ └── fast_list │ │ └── BaseList.kt │ └── res │ └── values │ └── strings.xml ├── gradle.properties ├── logo.png └── 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 | .externalNativeBuild 10 | .idea/ 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Radoslav Yankov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://raw.githubusercontent.com/dev-labs-bg/fast-list/master/logo.png) 2 | 3 | 4 | Create dynamic, fast and easy recycler view lists (including ViewPager2). **No adapters, no view holders**. 5 | 6 | [![Download](https://img.shields.io/badge/version-1.4-6db33f?style=flat-square)](https://jitpack.io/#dev-labs-bg/fast-list) [![Twitter URL](https://img.shields.io/badge/twitter-%40devlabsbg-1DA1F2.svg?style=flat-square&logo=twitter)](http://twitter.com/devlabsbg) 7 | 8 | 9 | ## Usage 10 | 11 | FastList supports 2 types of lists- single layout lists and dynamic lists. 12 | 13 | - Here's how to create a simple single layout list: 14 | 15 | ```kotlin 16 | val list = listOf(Item("fast", 1), Item("recycler", 2), Item("view", 1)) 17 | 18 | recycler_view.bind(list, R.layout.item) { it : Item, position: Int -> 19 | item_text.text = it.value 20 | } 21 | ``` 22 | That's it (for ViewPager2, just replace recycler_view with the ViewPager2 instance)! The first parameter is the list you want to show, the second is the ID of the layout and the third one is a function for binding each element. It uses Kotlin Extensions, so you can directly address the XML views and set them up. 23 | 24 | 25 | - The second type is dynamic lists with multiple layouts: 26 | 27 | ```kotlin 28 | val list = listOf(Item("fast", 1), Item("recycler", 2), Item("view", 1)) 29 | 30 | recycler_view.bind(list) 31 | .map(layout = R.layout.item, predicate = { it: Item, _ -> it.type == 1}) { item: Item, p: Int -> 32 | item_text.text = it.value 33 | } 34 | .map(layout = R.layout.item_second, predicate = { it: Item, _ -> it.type == 2}) { item: Item, p: Int -> 35 | item_second_text.text = it.value 36 | } 37 | .layoutManager(LinearLayoutManager(this)) 38 | ``` 39 | The map function accepts 3 parameters. The first is the ID of the layout for the type. The second is the predicate function by which you want to sort your items. The last one is the "view holder" binding function for each element. It uses Kotlin Extensions, so you can directly address the XML views and set them up. 40 | 41 | If you need control over your view's creation, you can pass a factory that allows you to create your own view: 42 | ```kotlin 43 | val list = listOf(Item("fast", 1), Item("recycler", 2), Item("view", 1)) 44 | 45 | recycler_view.bind(list) 46 | .map(layoutFactory = LocalFactory(this), predicate = { it: Item, _ -> it.type == 1}) { item: Item, p: Int -> 47 | item_text.text = it.value 48 | } 49 | .map(layout = R.layout.item_second, predicate = { it: Item, _ -> it.type == 2}) { item: Item, p: Int -> 50 | item_second_text.text = it.value 51 | } 52 | .layoutManager(LinearLayoutManager(this)) 53 | ... 54 | class LocalFactory(val activity: AppCompatActivity) : LayoutFactory { 55 | override fun createView(parent: ViewGroup, type: Int): View { 56 | val view = LayoutInflater.from(activity).inflate(R.layout.item, 57 | parent, false) 58 | //Manipulate view as needed 59 | return view 60 | } 61 | } 62 | ``` 63 | 64 | 65 | 66 | You can also update a list in a shown recycler view with this DiffUtils update function: 67 | ```kotlin 68 | ... 69 | val list2 = listOf(Item("fast", 1)) 70 | 71 | recycler_view.update(list2) 72 | ``` 73 | 74 | ## Download 75 | 76 | ### Manually 77 | 78 | The recommended way to download is to copy the [the library class](https://github.com/dev-labs-bg/fast-list/blob/master/fast-list/src/main/java/com/list/rados/fast_list/BaseList.kt) and use it in your application. 79 | 80 | **Important**: For the manual download you need Kotlin extensions to be enabled. To turn them on, simply place "apply plugin: 'kotlin-android-extensions'" inside of your app build.gradle 81 | 82 | ### Gradle 83 | 84 | ```gradle 85 | dependencies { 86 | implementation 'bg.devlabs.fastlist:fast-list:$latest_version' 87 | } 88 | ``` 89 | 90 | ## Getting help 91 | 92 | Dev Labs [@devlabsbg](https://twitter.com/devlabsbg) 93 | 94 | Radoslav Yankov [@rado__yankov](https://twitter.com/rado__yankov/) 95 | 96 | Under [MIT License](https://github.com/dev-labs-bg/fast-list/blob/master/LICENSE). 97 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | apply plugin: 'kotlin-android-extensions' 5 | 6 | androidExtensions { 7 | experimental = true 8 | } 9 | 10 | android { 11 | compileSdkVersion 29 12 | defaultConfig { 13 | applicationId "bg.devlabs.fastlist" 14 | minSdkVersion 19 15 | targetSdkVersion 29 16 | versionCode 1 17 | versionName "1.0" 18 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 19 | } 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(dir: 'libs', include: ['*.jar']) 30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 31 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 32 | implementation 'androidx.appcompat:appcompat:1.1.0' 33 | implementation "androidx.recyclerview:recyclerview:1.1.0" 34 | 35 | implementation 'androidx.core:core-ktx:1.2.0' 36 | 37 | implementation project(path: ':fast-list') 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/list/rados/recyclerviewlibrary/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.list.rados.recyclerviewlibrary 2 | 3 | import android.os.Bundle 4 | import android.os.Handler 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.Toast 9 | import androidx.appcompat.app.AppCompatActivity 10 | import androidx.core.view.children 11 | import androidx.recyclerview.widget.LinearLayoutManager 12 | import com.list.rados.fast_list.LayoutFactory 13 | import com.list.rados.fast_list.bind 14 | import com.list.rados.fast_list.update 15 | import kotlinx.android.synthetic.main.activity_main.* 16 | import kotlinx.android.synthetic.main.item.view.* 17 | import kotlinx.android.synthetic.main.item_custom.view.* 18 | import kotlinx.android.synthetic.main.item_second.view.* 19 | 20 | class MainActivity : AppCompatActivity() { 21 | 22 | data class Item(val value: String, val type: Int) 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | setContentView(R.layout.activity_main) 27 | 28 | val list = listOf(Item("first", 2), Item("second", 2), Item("third", 1), Item("fourth", 1), Item("fifth", 1)) 29 | val list2 = listOf(Item("first", 2), Item("third", 1), Item("fifth", 1), Item("sixth", 3)) 30 | 31 | recycler_view.bind(list, R.layout.item) { item: Item, position: Int -> 32 | item_text.text = item.value 33 | container.setOnClickListener { 34 | toast(item.value) 35 | } 36 | } 37 | 38 | recycler_view.bind(list) 39 | .map(layout = R.layout.item, predicate = { it: Item, _ -> it.type == 1 }) { item: Item, position: Int -> 40 | item_text.text = item.value 41 | container.setOnClickListener { 42 | toast(item.value) 43 | } 44 | } 45 | .map(layout = R.layout.item_second, predicate = { it: Item, _ -> it.type == 2 }) { item: Item, position: Int -> 46 | item_second_text.text = item.value 47 | container_second.setOnClickListener { 48 | toast(item.value) 49 | } 50 | } 51 | .map(layoutFactory = LocalFactory(this), predicate = { it: Item, _ -> it.type == 3 }) { item: Item, position: Int -> 52 | item_custom_text.text = item.value 53 | container_custom.setOnClickListener { 54 | toast(item.value) 55 | } 56 | } 57 | .layoutManager(LinearLayoutManager(this)) 58 | 59 | delay(2000) { 60 | recycler_view.update(list2) 61 | } 62 | 63 | } 64 | 65 | private fun toast(value: String) { 66 | Toast.makeText(this, value, Toast.LENGTH_SHORT).show() 67 | } 68 | } 69 | 70 | class LocalFactory(val activity: AppCompatActivity) : LayoutFactory { 71 | override fun createView(parent: ViewGroup, type: Int): View { 72 | return LayoutInflater.from(activity).inflate(R.layout.item_custom, 73 | parent, false) 74 | } 75 | } 76 | 77 | fun delay(delay: Long, func: () -> Unit) { 78 | val handler = Handler() 79 | handler.postDelayed({ 80 | try { 81 | func() 82 | } catch (e: Exception) { 83 | println(e.toString()) 84 | } 85 | }, delay) 86 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_second.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FastList 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.72' 5 | ext.dokka_version = '0.9.16' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:4.1.0-alpha02' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | 14 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0' 15 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' 16 | classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${dokka_version}" 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | jcenter() 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /fast-list/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /fast-list/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'com.jfrog.bintray' 5 | apply plugin: 'org.jetbrains.dokka-android' 6 | apply plugin: 'maven-publish' 7 | 8 | androidExtensions { 9 | experimental = true 10 | } 11 | 12 | android { 13 | compileSdkVersion 29 14 | 15 | defaultConfig { 16 | minSdkVersion 19 17 | targetSdkVersion 29 18 | versionCode 4 19 | versionName "1.4" 20 | 21 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 22 | 23 | } 24 | 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | } 30 | } 31 | 32 | } 33 | 34 | dokka { 35 | outputFormat = 'html' 36 | outputDirectory = "$buildDir/javadoc" 37 | } 38 | 39 | dependencies { 40 | implementation fileTree(dir: 'libs', include: ['*.jar']) 41 | 42 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 43 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 44 | implementation 'androidx.viewpager2:viewpager2:1.0.0' 45 | testImplementation 'junit:junit:4.12' 46 | compileOnly 'androidx.core:core-ktx:1.2.0' 47 | 48 | } 49 | 50 | apply from: 'deploy.gradle' -------------------------------------------------------------------------------- /fast-list/deploy.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | apply from: 'keystore.gradle'//the file, containing the bintray API key 4 | ext { 5 | // This configuration will result in: 6 | // compile '::' 7 | groupId = 'bg.devlabs.fastlist' // package name of the project 8 | artifactId = "fast-list" // module name of the library 9 | libVersion = "1.4" 10 | } 11 | version = libVersion 12 | group = groupId 13 | //take a look at https://github.com/bintray/gradle-bintray-plugin#buildgradle 14 | bintray { 15 | user = 'radoslav' // Your bintray User 16 | key = bintray_key // Defined in keystore.gradle file 17 | configurations = ['archives'] 18 | publish = true //[Default: false] Whether version should be auto published after an upload 19 | override = false //[Default: false] Whether to override version artifacts already published 20 | // Package configuration. The plugin will use the repo and name properties to check if the 21 | // package already exists. In that case, there's no need to configure the other package 22 | // properties (like userOrg, desc, etc). 23 | pkg { 24 | repo = "maven" //bintray repo 25 | name = "fast-list" //bintray package 26 | version { 27 | name = libVersion 28 | } 29 | } 30 | } 31 | install { 32 | repositories.mavenInstaller { 33 | pom.project { 34 | packaging 'aar' 35 | groupId groupId 36 | artifactId artifactId 37 | version libVersion 38 | name artifactId // pom.project.name must be same as bintray.pkg.name 39 | } 40 | } 41 | } 42 | 43 | //just copy paste the lines below 44 | if (project.hasProperty("kotlin")) { //Kotlin libraries 45 | task sourcesJar(type: Jar) { 46 | classifier = 'sources' 47 | from android.sourceSets.main.java.srcDirs 48 | } 49 | 50 | task javadoc(type: Javadoc, dependsOn: dokka) { 51 | 52 | } 53 | } else if (project.hasProperty("android")) { 54 | task sourcesJar(type: Jar) { 55 | classifier = 'sources' 56 | from android.sourceSets.main.java.srcDirs 57 | } 58 | 59 | task javadoc(type: Javadoc) { 60 | source = android.sourceSets.main.java.srcDirs 61 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 62 | } 63 | } else { // Java libraries 64 | task sourcesJar(type: Jar, dependsOn: classes) { 65 | classifier = 'sources' 66 | from sourceSets.main.allSource 67 | } 68 | } 69 | 70 | task javadocJar(type: Jar, dependsOn: javadoc) { 71 | classifier = 'javadoc' 72 | from javadoc.destinationDir 73 | // options.encoding = 'UTF-8' 74 | } 75 | 76 | artifacts { 77 | archives javadocJar 78 | archives sourcesJar 79 | } -------------------------------------------------------------------------------- /fast-list/keystore.gradle: -------------------------------------------------------------------------------- 1 | ext{ 2 | bintray_key = '-' 3 | } -------------------------------------------------------------------------------- /fast-list/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /fast-list/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /fast-list/src/main/java/com/list/rados/fast_list/BaseList.kt: -------------------------------------------------------------------------------- 1 | package com.list.rados.fast_list 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.annotation.LayoutRes 7 | import androidx.recyclerview.widget.DiffUtil 8 | import androidx.recyclerview.widget.LinearLayoutManager 9 | import androidx.recyclerview.widget.RecyclerView 10 | import androidx.viewpager2.widget.ViewPager2 11 | import kotlinx.android.extensions.LayoutContainer 12 | 13 | /** 14 | * Created by Radoslav Yankov on 29.06.2018 15 | * radoslavyankov@gmail.com 16 | */ 17 | 18 | typealias BindingClosure = (View.(item: T, position: Int) -> Unit) 19 | 20 | /** 21 | * Dynamic list bind function. It should be followed by one or multiple .map calls. 22 | * @param items - Generic list of the items to be displayed in the list 23 | */ 24 | fun RecyclerView.bind(items: List): FastListAdapter { 25 | layoutManager = LinearLayoutManager(context) 26 | return FastListAdapter(items.toMutableList(), this) 27 | } 28 | 29 | /** 30 | * ViewPager2 update 31 | * Dynamic list bind function. It should be followed by one or multiple .map calls. 32 | * @param items - Generic list of the items to be displayed in the list 33 | */ 34 | fun ViewPager2.bind(items: List): FastListAdapter { 35 | return FastListAdapter(items.toMutableList(), vpList = this) 36 | } 37 | 38 | /** 39 | * Simple list bind function. 40 | * @param items - Generic list of the items to be displayed in the list 41 | * @param singleLayout - The layout that will be used in the list 42 | * @param singleBind - The "binding" function between the item and the layout. This is the standard "bind" function in traditional ViewHolder classes. It uses Kotlin Extensions 43 | * so you can just use the XML names of the views inside your layout to address them. 44 | */ 45 | fun RecyclerView.bind(items: List, @LayoutRes singleLayout: Int = 0, singleBind: BindingClosure): FastListAdapter { 46 | layoutManager = LinearLayoutManager(context) 47 | return FastListAdapter(items.toMutableList(), this 48 | ).map(singleLayout, { item: T, position: Int -> true }, singleBind) 49 | } 50 | 51 | /** 52 | * ViewPager2 update 53 | * Simple list bind function. 54 | * @param items - Generic list of the items to be displayed in the list 55 | * @param singleLayout - The layout that will be used in the list 56 | * @param singleBind - The "binding" function between the item and the layout. This is the standard "bind" function in traditional ViewHolder classes. It uses Kotlin Extensions 57 | * so you can just use the XML names of the views inside your layout to address them. 58 | */ 59 | fun ViewPager2.bind(items: List, @LayoutRes singleLayout: Int = 0, singleBind: BindingClosure): FastListAdapter { 60 | return FastListAdapter(items.toMutableList(), vpList = this 61 | ).map(singleLayout, { item: T, position: Int -> true }, singleBind) 62 | } 63 | 64 | /** 65 | * Updates the list using DiffUtils. 66 | * @param newItems the new list which is to replace the old one. 67 | * 68 | * NOTICE: The comparator currently checks if items are literally the same. You can change that if you want, 69 | * by changing the lambda in the function 70 | */ 71 | fun RecyclerView.update(newItems: List) { 72 | (adapter as? FastListAdapter)?.update(newItems) { o, n, _ -> o == n } 73 | } 74 | 75 | /** 76 | * ViewPager2 update 77 | * Updates the list using DiffUtils. 78 | * @param newItems the new list which is to replace the old one. 79 | * 80 | * NOTICE: The comparator currently checks if items are literally the same. You can change that if you want, 81 | * by changing the lambda in the function 82 | */ 83 | fun ViewPager2.update(newItems: List) { 84 | (adapter as? FastListAdapter)?.update(newItems) { o, n, _ -> o == n } 85 | } 86 | 87 | open class FastListAdapter(private var items: MutableList, private var list: RecyclerView? = null, private var vpList: ViewPager2? = null) 88 | : RecyclerView.Adapter>() { 89 | 90 | init { 91 | if (vpList != null && list != null) 92 | throw IllegalArgumentException("You can only use either the Recycler(list) or the Pager(vpList)") 93 | if (vpList == null && list == null) 94 | throw IllegalArgumentException("You have to use either the Recycler(list) or the Pager(vpList)") 95 | 96 | } 97 | 98 | private inner class BindMap(val layout: Int, var type: Int = 0, val bind: BindingClosure, val predicate: (item: T, position: Int) -> Boolean) { 99 | constructor(lf: LayoutFactory, type: Int = 0, bind: BindingClosure, predicate: (item: T, position: Int) -> Boolean) : this(0, type, bind, predicate) { 100 | layoutFactory = lf 101 | } 102 | 103 | var layoutFactory: LayoutFactory? = null 104 | } 105 | 106 | private var bindMap = mutableListOf() 107 | private var typeCounter = 0 108 | 109 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FastListViewHolder { 110 | return bindMap.first { it.type == viewType }.let { 111 | it.layoutFactory?.let { 112 | return FastListViewHolder(it.createView(parent, viewType), viewType) 113 | } ?: run { 114 | return FastListViewHolder(LayoutInflater.from(parent.context).inflate(it.layout, 115 | parent, false), viewType) 116 | } 117 | } 118 | } 119 | 120 | override fun onBindViewHolder(holder: FastListViewHolder, position: Int) { 121 | val item = items.get(position) 122 | holder.bind(item, position, bindMap.first { it.type == holder.holderType }.bind) 123 | } 124 | 125 | override fun getItemCount() = items.size 126 | 127 | override fun getItemViewType(position: Int) = try { 128 | bindMap.first { it.predicate(items[position], position) }.type 129 | } catch (e: Exception) { 130 | 0 131 | } 132 | 133 | /** 134 | * The function used for mapping types to layouts 135 | * @param layout - The ID of the XML layout of the given type 136 | * @param predicate - Function used to sort the items. For example, a Type field inside your items class with different values for different types. 137 | * @param bind - The "binding" function between the item and the layout. This is the standard "bind" function in traditional ViewHolder classes. It uses Kotlin Extensions 138 | * so you can just use the XML names of the views inside your layout to address them. 139 | */ 140 | fun map(@LayoutRes layout: Int, predicate: (item: T, position: Int) -> Boolean, bind: BindingClosure): FastListAdapter { 141 | bindMap.add(BindMap(layout, typeCounter++, bind, predicate)) 142 | list?.adapter = this 143 | vpList?.adapter = this 144 | return this 145 | } 146 | 147 | /** 148 | * The function used for mapping types to layouts 149 | * @param layoutFactory - factory that creates the view for this adapter 150 | * @param predicate - Function used to sort the items. For example, a Type field inside your items class with different values for different types. 151 | * @param bind - The "binding" function between the item and the layout. This is the standard "bind" function in traditional ViewHolder classes. It uses Kotlin Extensions 152 | * so you can just use the XML names of the views inside your layout to address them. 153 | */ 154 | fun map(layoutFactory: LayoutFactory, predicate: (item: T, position: Int) -> Boolean, bind: BindingClosure): FastListAdapter { 155 | bindMap.add(BindMap(layoutFactory, typeCounter++, bind, predicate)) 156 | list?.adapter = this 157 | vpList?.adapter = this 158 | return this 159 | } 160 | 161 | /** 162 | * Sets up a layout manager for the recycler view. 163 | */ 164 | fun layoutManager(manager: RecyclerView.LayoutManager): FastListAdapter { 165 | vpList?.let { throw UnsupportedOperationException("layoumanager not needed for ViewPager2") } 166 | list!!.layoutManager = manager 167 | return this 168 | } 169 | 170 | fun update(newList: List, compare: (T, T, Boolean) -> Boolean) { 171 | val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() { 172 | 173 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { 174 | return compare(items[oldItemPosition], newList[newItemPosition], false) 175 | } 176 | 177 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { 178 | return compare(items[oldItemPosition], newList[newItemPosition], true) 179 | } 180 | 181 | override fun getOldListSize() = items.size 182 | 183 | override fun getNewListSize() = newList.size 184 | }) 185 | if (newList is MutableList) 186 | items = newList 187 | else 188 | items = newList.toMutableList() 189 | diff.dispatchUpdatesTo(this) 190 | } 191 | 192 | } 193 | 194 | interface LayoutFactory { 195 | fun createView(parent: ViewGroup, type: Int): View 196 | } 197 | 198 | class FastListViewHolder(override val containerView: View, val holderType: Int) : RecyclerView.ViewHolder(containerView), LayoutContainer { 199 | fun bind(entry: T, position: Int, func: BindingClosure) { 200 | containerView.apply { 201 | func(entry, position) 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /fast-list/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | FastList 3 | 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.useAndroidX=true -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dev-labs-bg/fast-list/14766800fff24cdd2797bf63580e7fb61cda5294/logo.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':fast-list' 2 | --------------------------------------------------------------------------------