BRV RecyclerView Framework

repository·master·Indexed 25 days ago

https://github.com/liangjingkanji/brv

A high-efficiency RecyclerView framework for Android designed to reduce boilerplate code. BRV provides extensive support for multi-type layouts, grouping, sticky headers, and data binding. Key features include DiffUtil-based updates, automatic pagination, built-in item animations (Alpha, Scale, Slide), and a comprehensive selection system for single and multi-select modes. It also includes a DefaultDecoration for customizable dividers and integrated click event handling with built-in debouncing.

Tokens
21.8K
Snippets
70
Records
122
Agent score
83%

What's inside BRV

  1. Overview of BRV features

    master

    BRV is a powerful tool for rapidly building RecyclerView lists in Android. Key features include:

    • List Construction: Fast creation of multi-type lists (one-to-one/one-to-many), header/footer layouts, and dividers/intervals.
    • Interactions: Click (with debounce) and long-press events, drag-and-drop reordering, and swipe-to-delete.
    • Grouping & Layout: Grouping (expand/collapse, recursive hierarchy, drag, etc.), sticky headers, and support for FlexboxLayoutManager for wrapping lists.
    • Data Management: DiffUtil-based data updates, automatic pagination, preloading, and selection modes (multi-select, single-select, select all, etc.).
    • Refresh & Loading: Pull-to-refresh, load-more, and up-fetch (implemented via SmartRefreshLayout), plus automatic pagination.
    • UI/UX: List animations, skeleton screen animations, and empty state handling (via StateLayout).
    • Integrations: Supports DataBinding, ViewBinding, and can be used with Net for automated network requests.
  2. Explore Net features for BRV automation

    master

    Net is a third-party network request framework designed to work seamlessly with BRV to provide automated features, including:

    • Automatic Pull-to-Refresh: Automates the refresh logic.
    • Automatic Pagination: Automates loading more data as the user scrolls.
    • Automatic Empty/Error States: Automatically handles the display of default/empty pages.
  3. Add horizontal dividers to a linear list

    master

    To add horizontal dividers, create a drawable resource to define the divider's appearance (specifically its height) and use the linear().divider() method.

    Warning: The divider implementation uses addItemDecoration. Calling the divider setup multiple times will stack multiple dividers.

    <!-- Example drawable: divider_horizontal.xml -->
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@color/dividerDecoration" />
        <size android:height="5dp" />
    </shape>
    rv.linear().divider(R.drawable.divider_horizontal).setup {
        addType<DividerModel>(R.layout.item_divider)
    }.models = getData()
  4. Handle one-to-one click events

    master

    For a simpler syntax where one specific ID maps to one specific callback, you can call the listener methods directly on the ID within the setup block.

    rv.linear().setup {
        addType<SimpleModel>(R.layout.item_simple)
    
        R.id.tv_simple.onClick {
            toast("点击Text")
        }
        R.id.item.onLongClick {
            toast("点击Item")
        }
    }.models = getData()
  5. Start drag via click to avoid gesture conflicts

    master

    To prevent conflicts between list scrolling and drag-and-drop gestures, it is recommended to trigger the drag via a specific view (like a button) within the item. Use itemTouchHelper?.startDrag(this) inside an OnTouchListener when the MotionEvent.ACTION_DOWN event occurs.

    rv.linear().setup {
        addType<DragModel>(R.layout.item_drag)
        onCreate {
            findView<View>(R.id.btnDrag).setOnTouchListener { _, event ->
                if (event.action == MotionEvent.ACTION_DOWN) { // Start dragging when finger is pressed
                    itemTouchHelper?.startDrag(this)
                }
                true
            }
        }
    }.models = getData()
  6. Initialize SmartRefreshLayout for PageRefreshLayout

    master

    Since PageRefreshLayout extends SmartRefreshLayout, you should initialize the default refresh header and footer creators in your Application class to ensure consistent behavior across the app.

    SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout -> MaterialHeader(this) }
    SmartRefreshLayout.setDefaultRefreshFooterCreator { context, layout -> ClassicsFooter(this) }
  7. Implement dividers for all four sides (Full Wrap)

    master

    To wrap the list items with dividers on all four sides, the recommended approach is to use a GridLayoutManager with a spanCount of 1 and set the orientation to DividerOrientation.GRID with includeVisible = true.

    rv.grid().divider {
        setDrawable(R.drawable.divider_horizontal)
        orientation = DividerOrientation.GRID
        includeVisible = true
    }.setup {
        addType<DividerModel>(R.layout.item_divider_vertical)
    }.models = getData()
  8. Quick Start with BRV

    master

    To quickly build a RecyclerView list, use the setup method on a layout manager (e.g., linear()) and register your data models with their corresponding layout resources using addType<T>(layoutId). Finally, assign your data to the models property.

    rv.linear().setup {
        addType<SimpleModel>(R.layout.item_simple)
    }.models = getData()
  9. Install BRV via JitPack

    master

    To use BRV in your Android project, you must first add the JitPack repository to your settings.gradle file, and then add the BRV dependency to your module's build.gradle file.

    // settings.gradle
    dependencyResolutionManagement {
        repositories {
            // ...
            maven { url 'https://jitpack.io' }
        }
    }
    
    // build.gradle (Module level)
    dependencies {
        implementation 'com.github.liangjingkanji:BRV:1.6.1'
    }
  10. Refresh specific items in a RecyclerView

    master

    There are two primary ways to refresh a specific item's data:

    1. Manual Notification: Use the notifyXX() methods on the bindingAdapter (e.g., notifyItemChanged(position)).
    2. DataBinding: If using DataBinding with two-way binding, changes to the data object will automatically update the view without manual index management. This is the most efficient method as it minimizes the update scope.
  11. Implement Many-to-Many type mapping in BRV

    master

    To map different data models to different item layouts (Many-to-Many), call addType<T>(layoutId) multiple times within the setup block. Each unique class type T will be associated with its specific layout.

    rv.linear().setup {
        addType<Model>(R.layout.item_1)
        addType<Store>(R.layout.item_2)
    }.models = data
  12. Configure PageRefreshLayout for CoordinatorLayout

    master

    When using a CoordinatorLayout to prevent empty states from covering header/footer layouts, use PageRefreshLayout to ensure the pull-to-refresh animation starts from the top of the page.

    In your XML layout, configure the following attributes:

    1. app:page_rv: Specify the ID of the nested RecyclerView.
    2. app:page_state: Specify the ID of the nested empty state layout (e.g., StateLayout).
    <com.drake.brv.PageRefreshLayout
        android:id="@+id/page"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:page_rv="@id/rv"
        app:page_state="@id/state">
    
        <androidx.coordinatorlayout.widget.CoordinatorLayout>
    
            <com.google.android.material.appbar.AppBarLayout>
                <!-- ... HEADER -->
            </com.google.android.material.appbar.AppBarLayout>
    
            <com.drake.statelayout.StateLayout
                android:id="@+id/state"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
    
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rv"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
    
            </com.drake.statelayout.StateLayout>
    
        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    
    </com.drake.brv.PageRefreshLayout>