GithubHelp home page GithubHelp logo

stephenvinouze / advancedrecyclerview Goto Github PK

View Code? Open in Web Editor NEW
201.0 5.0 36.0 40.77 MB

An easy, empowering Kotlin library for RecyclerView

License: Apache License 2.0

Java 42.37% Kotlin 51.90% Ruby 5.72%
android java kotlin recyclerview

advancedrecyclerview's Introduction

AdvancedRecyclerView

Release Build Status API Android Arsenal GitHub license

Before the appearance of RecyclerView, ListView and GridView were the common layout used to display lists of items. Even though RecyclerView has optimized how to render list of items without having to worry how you want to display them (either list or grid) it comes with a price when implementing such behaviors.

This library comes with two focuses:

  • Make your RecyclerView basic implementation dead simple.
  • Intagrating useful features that could be found in either ListView and GridView (such as choice mode) and even more (sections, pagination, gestures).
Single choice Multiple choice Sections
Single choice Multiple choice Sections

Migrate to v2

If you are already using the v1 of this library and considering migrating to the v2, here are a few things worth mentioning

  • You need to declare all modules that you require as they are not transitive anymore.
  • Several methods were renamed for clarification
  • Packages were renamed to apply latest Android Studio guidelines. Some classes were also rearranged in the process.
  • A Kotlin sample was added and callback systems were changed in favor of lambdas to match with Kotlin language.
  • In order to not disadvantage Java users I kept the previous methods. Both Java and kotlin samples are available in this repository.
  • For Java users, Java 8 is now required for this library because of lambdas.

Basic usage

The core module contains the basic logic to easily manipulate a RecyclerView. It allows you to define your adapter in a blink of the eye, with a already built-in ViewHolder pattern so that you just need to define how your items will be laid out in your list.

Create your model :

data class Sample(val id: Int, val rate: Int, val name: String)

Create your view :

class SampleItemView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) {

    init {
        LayoutInflater.from(context).inflate(R.layout.view_sample_item, this, true)
    }

    fun bind(sample: Sample) {
        // Update your subviews with the Sample data 
    }

}

Then define your own adapter that extends from RecyclerAdapter and template it with your model that will be used to populate your list :

class SampleAdapter : RecyclerAdapter<Sample>() {

    override fun onCreateItemView(parent: ViewGroup, viewType: Int): View = SampleItemView(parent.context)

    override fun onBindItemView(view: View, position: Int) {
        when (view) {
            is SampleItemView -> view.bind(items[position])
        }
    }

}

Finally in your Activity/Fragment, add your Sample items to your SampleAdapter and bind your adapter to your RecyclerView:

val adapter = SampleAdapter(this)
adapter.items = mutableListOf()
recyclerView.adapter = adapter

Your RecyclerView is ready to be displayed. You just have to implement your bind() method within your view to configure it (or use the databinding pattern if you prefer).

Click events

Listening to click events are often required and usually requires to transit such an event from your adapter to your Activity/Fragment to maintain a clean architecture. This library provides to optional lambdas for click and long click events that can be called directly from your adapter :

adapter.onClick = { view, position ->
    val sample = items[position]
    // Do whatever you want
}
adapter.onLongClick = { view, position ->
    val sample = items[position]
    // Do whatever you want
}

Choice mode

A useful feature that can be found in either ListView and GridView is ChoiceMode. Although this does not come natively with RecyclerView, this library provides such a mechanism.

Choice mode can be either NONE (default), SINGLE or MULTIPLE. If a choice mode other than NONE is declared for your adapter, your selected items will be internally stored at each view click. You can also manually select an item :

adapter.toggleItemView(position)

You can obviously retrieve which items are selected :

adapter.selectedItemViewCount // Returns the selected item view count
adapter.getSelectedItemViews() // Returns a list of selected item views
adapter.isItemViewToggled(position) // Returns true if item is selected

If you need to remove all selected items :

adapter.clearSelectedItemViews()

Advanced usage

In most cases the core module should handle most of the heavy work. This section presents more advanced concepts that can help you while using RecyclerView in your applications.

Section

You may encounter lists that need to be regrouped within sections to present a clear sorting or your items. This can be easily done natively by overriding getItemViewType() and manipulate yourself each viewType in your adapter callbacks. The section module intends to lift this work for you as well as to provide a clear implementation by separating section building callbacks from main items in your list.

Create a section item view to render your sections. Let's call it SampleSectionItemView.

Extends your adapter class from RecyclerSectionAdapter (which itself extends from RecyclerAdapter) and provides two more abstract methods to shape your views that will be displayed as sections :

class SampleSectionAdapter : RecyclerSectionAdapter<Int, Sample>({ it.rate }) {

    override fun onCreateItemView(parent: ViewGroup, viewType: Int): View = SampleItemView(parent.context)

    override fun onBindItemView(view: View, position: Int) {
        when (view) {
            is SampleItemView -> view.bind(items[position])
        }
    }

    // Override these two new methods to render your sections
       
    override fun onCreateSectionItemView(parent: ViewGroup, viewType: Int): View =
            SampleSectionItemView(parent.context)

    override fun onBindSectionItemView(sectionView: View, sectionPosition: Int) {
        sectionAt(sectionPosition)?.let {
            when (sectionView) {
                is SampleSectionItemView -> sectionView.bind(it)
            }
        }
    }

}

Note the Int generic type in the class declaration that indicates the type that will contains the section. In our case, we want to sort them by rate. The building of the sections will be automatically taken care of by a lambda that you must provide in your constructor (){ sample -> sample.rate }).

Wraps things up the way you were doing with your RecyclerAdapter :

val sectionAdapter = SampleSectionAdapter(this)
sectionAdapter.items = mutableListOf()
recyclerView.adapter = sectionAdapter

Setting items to your adapter will take care of the section building and relayout your list. You may want to sort your items before setting them in your adapter to obtain consistent sections.

Pagination

Pagination is a common pattern especially when interacting with an API to lazy load your items into your list. The pagination module provides an extension to the RecyclerView class to easily activate pagination and notify what to do when pagination is triggered. You should also notify your users that your content is being loaded into your list by providing a loader at the bottom of your list.

Extend your adapter from RecyclerPaginationAdapter and implement the loader creator callback :

class SamplePaginationAdapter : RecyclerPaginationAdapter<Sample>() {

    override fun onCreateItemView(parent: ViewGroup, viewType: Int): View = SampleItemView(parent.context)

    override fun onBindItemView(view: View, position: Int) {
        when (view) {
            is SampleItemView -> view.bind(items[position], isItemViewToggled(position))
        }
    }

    override fun onCreateLoaderView(parent: ViewGroup, viewType: Int): View =
            LayoutInflater.from(parent.context).inflate(R.layout.view_progress, parent, false)

}

Activate pagination on your RecyclerView and populate your list with the appendItems() extension method :

val paginationAdapter = SamplePaginationAdapter(this)
recyclerView.adapter = paginationAdapter
recyclerView.enablePagination(
    isLoading = {
        paginationAdapter.isLoading
    },
    hasAllItems = {
        // return true if you have loaded all your items to stop the pagination to try loading more
    },
    onLoad = {
        // Fetch and/or load your items within your list
        paginationAdapter.isLoading = true
        // Fetch items from API. Indicate loading done once fetch is finished
        paginationAdapter.isLoading = false
        // Append items into your list
        paginationAdapter.appendItems(items)
    }
)

โš ๏ธ Note that RecyclerPaginationAdapter extends from RecyclerAdapter as pagination for sectioned content is not (and won't be) supported.

Gesture

The RecyclerView component allows you to interact with your items by draging them with the ItemTouchHelper class. The gesture module abstracts this behavior to let you easily swipe-to-delete and/or move your items from your RecyclerView. Items are manipulated for you for both move on swipe-to-delete gestures.

You can enable gestures by using the RecyclerView extension method :

recyclerView.enableGestures(
    dragDirections = ItemTouchHelper.UP or ItemTouchHelper.DOWN,
    swipeDirections = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT,
    onMove = { fromPosition, toPosition ->
        // Do whatever you want
        true
    },
    onSwipe = { position, direction ->
        // Do whatever you want
    }
)

Note that all lambdas are optionals so that you may enable/configure your desired gestures. Also, the gesture module includes the section module so that all your gestures also works while using your list with sections. The only limitation is that you cannot move an item from one section to another.

Gradle Dependency

The gradle dependency is available via JitPack. Add this in your root build.gradle file:

allprojects {
    repositories {
	    maven { url "https://jitpack.io" }
    }
}

Then add the dependencies that you need in your project.

def advancedrecyclerview_version = "{latest_version}"

dependencies {
    implementation "com.github.StephenVinouze.AdvancedRecyclerView:core:${advancedrecyclerview_version}"
  
    // If you need to display lists with sections
    implementation "com.github.StephenVinouze.AdvancedRecyclerView:section:${advancedrecyclerview_version}"
   
    // If you need to paginate your lists
    implementation "com.github.StephenVinouze.AdvancedRecyclerView:pagination:${advancedrecyclerview_version}"
  
    // If you need to handle gestures within your lists
    implementation "com.github.StephenVinouze.AdvancedRecyclerView:gesture:${advancedrecyclerview_version}"
}

Pull requests

I welcome and encourage all pull requests. I might not be able to respond as fast as I would want to but I endeavor to be as responsive as possible.

All PR must:

  1. Be written in Kotlin
  2. Maintain code style
  3. Indicate whether it is a enhancement, bug fix or anything else
  4. Provide a clear description of what your PR brings
  5. Enjoy coding in Kotlin :)

advancedrecyclerview's People

Contributors

aardouin avatar stephenvinouze avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

advancedrecyclerview's Issues

Item long click not supported?

Hi Stephen, thanks for a great library!
I want to activate multichoice mode upon long click (like ListView did), however
the method "onItemLongClick" in ClickCallback is not overridable (doesn't have "open" qualifier) and is fixed to simply return false.
Is this by design or just an oversight?
Thanks!

Section and Pagination?

Will be supported section and pagination in one recycler view?
Currently when we use adapter.setItems(list, page) we end up with items only from last page

Incompatibility

Hi, your component aren't compatible with
com.mcxiaoke.koi:core
com.mcxiaoke.koi:async
please can you check this.

I need to pass Model Object instead of Primitive Data Type

Hi, I'm implementing the sections list. And wondering if I could pass the Model Object too to the Section View. I saw your demo project and you are simply passing the Int, Sample (Custom Model Object). What if I also need to pass the custom model object too in RecyclerSectionAdapter parameters.
Currently it is like this class SampleSectionAdapter : RecyclerSectionAdapter<Int, Sample>({ it.rate }) {
And I want like this class OrdersAdapter: RecyclerSectionAdapter<Order, Order>({ it }) {

When I try to pass model object then I get the error. pease see attached image.
Screen Shot 2020-02-02 at 9 08 57 AM

Could you please help me in this regard to resolve this issue.

Thanks,
Hassan

Single selection is disappears in View Pager when coming back from 3rd tab to 1st tab

Hi,

I'm new to Android and implemented this library in my application. I've a View Pager with 3 tabs. It can be more tabs, but I've 3 as of now. And in all 3 tabs I've implemented AdvanceRecyclerView of single selection mode. The issue I'm experiencing is that when I select any item in the 1st tab and go to 2nd tab, select the item again, and go to the 3rd tab and again select the item, finally when I come back to 1st tab, the selection disappears for both 1st and 3rd tab, but selection in 2nd tab remains there. This is very strange behavior.

Can you look into this issue?

Thanks
Hassan

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.