Probably the most powerful RecyclerView framework
GitHub | Using document | Alternate access
This framework does not affect the use of RecyclerView any function components on the basis of development. The project will also be maintained at all times
Welcome to contribute code/questions
- Elegant function design
- Detailed usage documentation
- Simple sample code
- High cohesion and low coupling
- Refresh the screen without blinking
- Two-way DataBinding (DataBinding)
function
- g
- A single data model one-to-many
- Multiple data model
- Add head layout and foot layout
- Click (Anti-jitter) or hold the event
- Grouping (Unfold fold/recursive hierarchy/unfold top/single unfold mode)
- hover
- Split line/uniform spacing (support official full
LayoutManager
) - Switch mode
- Selection mode (multiple/single/All/Cancel all/Reverse selection)
- Drag and drop location
- Lateral spreads to delete
- Drop-down refresh | tensile load, extension SmartRefreshLayout that is compatible with all of its functions
- Pull the index (UpFetch) | Preload index (Preload)
- The default page
- Automatic page loading
- Extend scalable layout (FlexboxLayoutManager)
- Extended Automated Network Request (Net), which implements automated concurrent network requests based on coroutines
The installation
Add the repository to build. Gradle in the project root directory
allprojects {
repositories {
// ...
maven { url 'https://jitpack.io'}}}Copy the code
Add dependencies to build.gradle in module
android {
/ /... Turn DataBinding on even if you're not using it
buildFeatures.dataBinding = true
}
dependencies {
/ /...
implementation 'com. Making. Liangjingkanji: BRV: 1.3.24'
}
Copy the code
License
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.
Copy the code
preview
Home page
The function interface
Initialize the
class MyApplication : Application() {
override fun onCreate(a) {
super.onCreate()
BindingAdapter.modelId = BR.m // It is recommended to initialize or use it in Application}}Copy the code
g
Different data models
rv.linear().setup {
addType<Model>(R.layout.item_1)
addType<Store>(R.layout.item_2)
}.models = data
Copy the code
One-to-many data model
It is common in development to come across a list with a field for each itemType
addType<Model>{
// Use age as a judgment to return different layouts
when (age) {
23 -> {
R.layout.item_1
}
else -> {
R.layout.item_2
}
}
}
Copy the code
The divider
Fast secant line implementation
fun RecyclerView.divider(
@DrawableRes drawable: Int.@RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL,
block: ((Rect.View.RecyclerView.RecyclerView.State) - >Boolean)? = null
)
Copy the code
Listen for an event
Listening events need to be added to the view you want to listen on
fun addClickable(@IdRes vararg id: Int)
// Filter repeated clicks within 500 milliseconds
fun addFastClickable(@IdRes vararg id: Int)
// The function does not filter repeated click events
fun addLongClickable(@IdRes vararg id: Int)
// Long press event
Copy the code
Event callback
onClick{
}
// Click the event
onLongClick{
}
// Long click events
onBind {
false
}
Copy the code
OnBind belongs to the onBindViewHolder event listener.
Use this function if you need to set data or bind events yourself. The return value determines whether to use the Databinding binding layout that is the internal default of the frame. false indicates no binding.
A simpler example
rv.linear().setup {
addType<Model>{
R.layout.item_1
}
onClick(R.id.item, R.id.user_portrait){
}
onLongClick(R.id.item){
}
}.models = data
Copy the code
Head layout/foot layout
The head and foot layouts count as one item in the RV, so they should be considered when calculating positions.
Operation head layout
fun addHeader(view: View)
fun removeHeader(view: View)
fun clearHeader(a)
fun isHeader(@IntRange(from = 0) position: Int): Boolean
Copy the code
Operator pin layout
fun addFooter(view: View)
fun removeFooter(view: View)
fun clearFooter(a)
fun isFooter(@IntRange(from = 0) position: Int): Boolean
Copy the code
To get the data
val headerCount: Int
val footerCount: Int
Copy the code
Switch mode
Switching mode provides a callback function to iterate over all items, and you can refresh each item in turn within this callback.
Often used to toggle selection modes.
fun toggle(a)
// Switch mode
fun getToggleMode(a): Boolean
// The range is currently switching mode
fun setToggleMode(toggleMode: Boolean)
// Set toggle mode, if set to the current mode will not trigger the callback
Copy the code
The callback function
onToggle { type, position, toggleMode -> // Type position toggle Boolean values
// Here we can refresh the item into select mode
}
// The switch is complete
onToggleEnd {
// For example, switch the toolbar to Select mode
}
Copy the code
Select the schema
fun allChecked(a)
/ / all
fun allChecked(isAllChecked: Boolean)
// Select all or cancel all
fun clearChecked(a)
// Deselect all
fun reverseChecked(a)
/ / the choice
fun setChecked(@IntRange(from = 0) position: Int, checked: Boolean)
// Sets the selection status of an item
fun toggleChecked(@IntRange(from = 0) position: Int)
// Toggle the selection state of an item
fun <M> getCheckedModels(a): List<M>
fun setCheckableType(@LayoutRes vararg checkableItemType: Int)
// Sets which types are allowed to enter the selection state
val checkedCount: Int
Copy the code
Drag/side slip
Only support drag and drop movement and side – slide deletion
Steps:
- open
ItemTouchHelper
support - Data model inheritance
ItemModel
- Custom extension
The BindingAdapter provides a field to enable ItemTouchHelper support
var touchEnable = false // It is disabled by default
Copy the code
The data model then requires inheriting the ItemModel, rewriting the function as needed.
Example:
data class Model(val name: String) : ItemModel() {
override fun getDrag(a): Int {
return UP or DOWN
}
override fun getSwipe(a): Int {
return RIGHT or LEFT
}
}
Copy the code
RIGHT or LEFT is a constant that controls the direction of drag and sideslip (sideslip does not support UP/DOWN).
Dragging and dropping items automatically changes the position of the data model in the data set.
Extend the functionality
If you want to extend ItemTouchHelper, you can assign to the BindingAdapter variable ItemTouchHelper
rv.linear().setup {
addType<Model>(R.layout.item)
touchEnable = true
itemTouchHelper = ItemTouchHelper(object : DefaultItemTouchCallback(this) {
// We can rewrite the function here
})
}.models = data
Copy the code
Swipe can control the view that slides to move by attaching the tag to the view.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="80dp"
android:orientation="horizontal"
android:tag="swipe"/>
Copy the code
The default page
StateLayout internal dependence, the library support any Activity | fragments | View to carry on the functions of the default page.
The main features
- Global configuration
- Singleton configuration
- Life cycle (can load animations or process events)
- Supports activity/fragment/ View replacement
- Support code or XML implementation
- ShowLoading displays an incorrect layout in the absence of a network, while loading is displayed in the presence of a network
This library is already dependent and does not need to be dependent again. See GitHub for instructions.
PageRefreshLayout
This layout extends SmartRefreshLayout(highly recommended by the library) to support all of its features. This framework has the perfect default page functionality
SmartRefreshLayout ‘com.scwang.smart:refresh-layout-kernel:2.0.0-alpha-1’ has already been introduced into this library.
Request headers that are required can be subcontracted to their open source address.
Optional configuration refreshes the head layout and foot layout
implementation 'com. Scwang. Smart: refresh - footer - classics: 2.0.0 - alpha - 1' // Classic loading
implementation 'com. Scwang. Smart: refresh header - material: 2.0.0 - alpha - 1' // Google refresh header
// The above two types are already built in
implementation 'com. Scwang. Smart: refresh header - classics: 2.0.0 - alpha - 1' // Classic refresh header
implementation 'com. Scwang. Smart: refresh header - radar: 2.0.0 - alpha - 1' // The radar refresh header
implementation 'com. Scwang. Smart: refresh header - falsify: 2.0.0 - alpha - 1' // Virtual refresh header
implementation 'com. Scwang. Smart: refresh - the header - two - level: 2.0.0 - alpha - 1' // Level 2 refresh header
implementation 'com. Scwang. Smart: refresh - footer - ball: 2.0.0 - alpha - 1' // Ball pulse loading
implementation 'com. Scwang. Smartrefresh: SmartRefreshHorizontal: 1.0.0 andx - 1' / / level
Copy the code
Refresh layout requirements must be initialized first, recommended in Application
SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout -> ClassicsHeader(this) }
SmartRefreshLayout.setDefaultRefreshFooterCreator { context, layout -> ClassicsFooter(this) }
Copy the code
Add features on top of that
- The default page
- Automatic page loading
- Support for KT feature
- Code to replace
Create a way
Val page = rv.page() // 2. Layout of the package<com.drake.brv.PageRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/page"
app:stateEnabled="true"
android:layout_height="match_parent"
tools:context="com.drake.brv.sample.fragment.RefreshFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.drake.brv.PageRefreshLayout>
Copy the code
Listening state
// Drop refresh
page.onRefresh {
// Asynchronous operations such as network requests can be performed here
}
// Pull up load
page.onLoadMore {
// Asynchronous operations such as network requests can be performed here
}
Copy the code
If onLoadMore is not called, the pull-up load also calls back the onRefresh function, because the pull-down refresh and the pull-up load may both go through the same network request.
The default page
Trigger the refresh state (both callback function onRefresh)
autoRefesh
This is the triggered drop-down refreshshowLoading
This triggers the loading of the default page, after setting loadingLayout(or reading the global default page configuration).refresh
The silent refresh does not trigger any animation
The second method is usually used to load data when first entering the page (product managers may require this), and all three methods result in index=startIndex resetting.
Default page state control
showEmpty()
showError()
showContent
showLoading()
Copy the code
Configure the global default page
This code is common to StateLayout
/ * * * recommended for global configuration default page in the Application, also, of course, each page can specify a default page alone. Specific see https://github.com/liangjingkanji/StateLayout * / *
StateConfig.apply {
emptyLayout = R.layout.layout_empty
errorLayout = R.layout.layout_error
loadingLayout = R.layout.layout_loading
onLoading {
// This lifecycle takes the view object created by LoadingLayout, which can be animated or clicked.}}Copy the code
The singleton default page can be configured in two ways
- XML
<com.drake.brv.PageRefreshLayout
.
app:error_layout="@layout/layout_error"
app:empty_layout="@layout/layout_empty"
app:loading_layout="@layout/layout_loading">
Copy the code
- code
page.apply {
loadingLayout = R.layout.layout_loading
emptyLayout = R.layout.layout_empty
errorLayout = R.layout.layout_error
}
Copy the code
The default page will be used by default if you have set the global default page but don’t want to use it at the moment. Can use properties | function: stateEnabled
If you want to use a default page that does not cover the head layout, you can use CoordinatorLayout for head layout. Note that using NestedScrollView causes a large memory consumption after the RV loads the item at one time.
The refresh data
As mentioned earlier, PageRefreshLayout supports automatic pagination loading
// Set the index of the first page to be paged. Default =1. Triggering a refresh resets the index. If you need to change it, set it once in Application
// PageRefreshLayout.startIndex = 1
pageLayout.onRefresh {
// Both the pull-down refresh and the pull-up load will execute the network request unless onLoadMore is set otherwise
get("/path") {
param("key"."value")
param("page", pageLayout.index) // Frame supplied properties are used here
}.page(this) {
// This callback function argument returns a Boolean type to determine the existence of the next page, determining the status of the pull-up load. And whether it is currently refreshing or loading more entries
addData(data){ adapter.itemCount < data.count }}}}Copy the code
The web request here uses my other open source project, Net, which supports the extension brv. GitHub: Net.
extension
LayoutManager
The framework also provides extension functions to quickly create layout managers, as shown in the example above
rv.linear().setup {
}
Copy the code
function
fun RecyclerView.linear(
@RecyclerView.Orientation orientation: Int = VERTICAL,
reverseLayout: Boolean = false
)
fun RecyclerView.grid(
spanCount: Int.@RecyclerView.Orientation orientation: Int = VERTICAL,
reverseLayout: Boolean = false
)
fun RecyclerView.staggered(
spanCount: Int.@RecyclerView.Orientation orientation: Int = VERTICAL
)
Copy the code
dividers
The framework provides quick setup of separator extension functions
fun RecyclerView.divider(
@DrawableRes drawable: Int.// delimiter Drawable
@RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL, // Direction of LayoutManager
block: ((Rect.View.RecyclerView.RecyclerView.State) - >Boolean)? = null // The getItemOffset callback is used to set the interval
)
Copy the code
The sample
rv.linear().divider(R.drawable.divider_horizontal_padding_15dp).setup {
}
Copy the code
dialog
Use extension functions to quickly create lists for dialogs
Dialog(context).setAdapter(bindingAdapter)
Copy the code