Sometimes when you’re developing a project, you’ll come across a complex page that requires multiple lists or sliding layouts, or even webViews, to form a complete page. To achieve such a complex page, in the past, we may nest multiple recyclerViews, WebViews and ScrollViews in a large ScrollView by nesting layout. But not only does this nesting approach seriously affect layout performance, but it can also be a headache to handle the collision of sliding events, which can seriously affect the user experience. ConsecutiveScrollerLayout is designed to solve this difficult problem slide layout, It can nest multiple sliding layouts (RecyclerView, WebView, ScrollView, etc.) and ordinary controls (TextView, ImageView, LinearLayou, custom View, etc.) at the same time, it treats all the sub-views as a whole, Unified process layout by ConsecutiveScrollerLayout sliding, allows multiple sliding layout as a whole continuous sliding, its effect is like a ScrollView. And it supports the nesting of all views, with good versatility. The user doesn’t have to worry about how it slides, doesn’t have to worry about sliding conflicts, and doesn’t have to worry about it affecting the performance of the child View.
The following is an introduction to the use of ConsecutiveScrollerLayout and a written notice.
Project address: ConsecutiveScroller
ConsecutiveScroller design train of thought and the analysis of source: Android sustainable slide layout: ConsecutiveScrollerLayout
rendering
Introduction of depend on
Add the following code in Project build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io'}}}Copy the code
Add the following code to build.gradle in Module
implementation 'com. Making. Donkingliang: ConsecutiveScroller: 2.6.2'
Copy the code
Note: If you plan to use this library, be sure to read the documentation below carefully. It can make you understand ConsecutiveScrollerLayout can realize the function, and avoid unnecessary mistakes.
The basic use
ConsecutiveScrollerLayout use is very simple, need the layout of the sliding as ConsecutiveScrollerLayout immediate child of the View.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@android:color/holo_red_dark"
android:gravity="center"
android:orientation="vertical">
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.core.widget.NestedScrollView>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/temp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
</ScrollView>
<! - can be nested ConsecutiveScrollerLayout -- -- >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/design_default_color_primary">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text=""
android:textColor="@android:color/black"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView3"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
On the margin
ConsecutiveScrollerLayout support left and right margin, but does not support the fluctuation margin, spacing between the View can be set through the Space.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<! -- Use Space to set upper and lower margins -->
<Space
android:layout_width="0dp"
android:layout_height="20dp" />
<! - ConsecutiveScrollerLayout support left and right margin, but does not support fluctuation margin -- -- >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@android:color/holo_red_dark"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LinearLayout"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>
<! -- Use Space to set upper and lower margins -->
<Space
android:layout_width="0dp"
android:layout_height="20dp" />
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
Layout alignment
ConsecutiveScrollerLayout layout is similar to the vertical LinearLayout, but it’s not gravity and child view layout_gravity attribute. ConsecutiveScrollerLayout child view for it to provide the layout_align properties, father is used to set the view and the layout of the alignment. Layout_align has three values: LEFT, RIGHT, and CENTER.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 1"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true"
app:layout_align="LEFT"/>// Alignment</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
Nested fragments
If you want to put a nested fragments in ConsecutiveScrollerLayout. Usually we need a layout container to hold our Fragment, or write the Fragment directly into the activity’s layout. If the Fragment is a vertical sliding, then load container needs to be ConsecutiveScrollerLayout fragments, and fragments of root layout is also need to be vertical sliding. We recommend ConsecutiveScrollerLayout or other vertical sliding control (such as: RecyclerView, NestedScrollView) as the root layout of fragments. If your Fragment doesn’t slide vertically, you can ignore this restriction.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<! -- Fragment container -->
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<! MyFragment's root layout is a vertical sliding control -->
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.donkingliang.consecutivescrollerdemo.MyFragment"/>
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
Layout to suck the top
In the past, we might have written two identical layouts, one hidden at the top and one nested under a ScrollView, listening to the ScrollView slide to show and hide the top layout. This approach is cumbersome and inelegant to implement. ConsecutiveScrollerLayout internal implementation the adsorption at the top of the View function, as long as set a property, you can achieve top absorption function. And support to set up a number of sub-view top, behind the View to top when the front of the top View out of the screen.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<! App :layout_isSticky="true" -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 1"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="vertical"
app:layout_isSticky="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Top view-2 I'm a LinearLayout"
android:textColor="@android:color/black"
android:textSize="18sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 3"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.core.widget.NestedScrollView>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="10dp"
android:text="吸顶View - 4"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
Resident roof absorption
If you don’t want the top view to be pushed out of the screen by the top view, and multiple top views are arranged on the top, you can set the permanent top mode: app:isPermanent=”true”.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:isPermanent="true"// Keep the ceilingandroid:scrollbars="vertical">
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
Other methods for top suction function
// Set the distance from the top to the top, and hover the top when it is a certain distance from the top
scrollerLayout.setStickyOffset(50);
// Monitor top change (normal mode)
scrollerLayout.setOnStickyChangeListener(OnStickyChangeListener);
// Monitor top change (permanent mode)
scrollerLayout.setOnPermanentStickyChangeListener(OnPermanentStickyChangeListener);
// Get the current top view(normal mode)
scrollerLayout.getCurrentStickyView();
// Get the current top view(permanent mode)
scrollerLayout.getCurrentStickyViews();
Copy the code
Local sliding
ConsecutiveScrollerLayout all child View will be regarded as a whole, unified handling page slide events by it, so it will default to intercept slide child View slide events, distributed processing by yourself. And will track the user’s finger sliding events, calculate adjustment ConsecutiveScrollerLayout sliding shift. If you want a child View to handle its own slide events, you can tell the parent View not to block its slide events by setting the layout_issize property. This allows the parent View to slide within its own height. Rather than as part of the ConsecutiveScrollerLayout to deal with.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<! App: layout_isavg ="false" so that the parent layout does not block sliding events -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_isConsecutive="false">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="The red area below is a RecyclerView, which slides independently within its own boundaries."
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_isSticky="true" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:layout_marginBottom="30dp"
android:background="@android:color/holo_red_dark"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="Down here is a NestedScrollView, and it slides in its own scope."
android:textColor="@android:color/black"
android:textSize="18sp" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="250dp"
app:layout_isConsecutive="false">
</androidx.core.widget.NestedScrollView>
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
In this example NestedScrollView hope in their height sliding their own content, rather than follow ConsecutiveScrollerLayout sliding, as long as layout_isConsecutive = “false” to set it up. The LinearLayout is not a sliding layout, but it has a sliding RecyclerView nested underneath it, so it also needs to set layout_issize =”false”.
ConsecutiveScrollerLayout support NestedScrolling mechanism, if you view has realized the partial sliding NestedScrollingChild interface (such as: RecyclerView, NestedScrollView, etc.), it will slide after the completion of the sliding event to the parent layout. If you don’t want your child view or its child view to slide nested with the parent layout, you can set app layout_isNestedScroll=”false” for the child view. It can view and ConsecutiveScrollerLayout nested sliding is prohibited
Slide a child view of a child view
ConsecutiveScrollerLayout by default will only deal with its immediate child view slide, but sometimes need to slide layout may not be ConsecutiveScrollerLayout child view directly, but the son view nested view at a lower level. Such as ConsecutiveScrollerLayout nested FrameLayout FrameLayout nested ScrollView, we hope ConsecutiveScrollerLayout can normal processing ScrollView sliding. To support this requirement, ConsecutiveScroller provided an interface: IConsecutiveScroller. Child view IConsecutiveScroller interface is implemented, and by the method of implementing an interface tell ConsecutiveScrollerLayout need slide view at a lower level, sliding ConsecutiveScrollerLayout can correctly handle it. IConsecutiveScroller needs to implement two methods:
/** * returns the current subview that needs to be slid. Only one view can slide at a time. * /
View getCurrentScrollerView(a);
/** * returns all child views that can slide. Since ConsecutiveScrollerLayout allows its child view contains more than one slide of view, it returns a list view. * /
List<View> getScrolledViews(a);
Copy the code
In the previous example, we could implement this:
public class MyFrameLayout extends FrameLayout implements IConsecutiveScroller {
@Override
public View getCurrentScrollerView(a) {
// Returns the ScrollView to slide
return getChildAt(0);
}
@Override
public List<View> getScrolledViews(a) {
// Returns the ScrollView to slide
List<View> views = new ArrayList<>();
views.add(getChildAt(0));
returnviews; }}Copy the code
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<com.donkingliang.consecutivescrollerdemo.widget.MyFrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</ScrollView>
</com.donkingliang.consecutivescrollerdemo.widget.MyFrameLayout>
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
So ConsecutiveScrollerLayout can correctly handle ScrollView sliding. This is a simple example, in a real world requirement, we generally don’t need to do this.
Note:
GetCurrentScrollerView () and getScrolledViews() must correctly return the views to be slid, which may be nested in multiple layers, not necessarily direct child views. So users should implement the two methods according to their own actual scenarios.
2. The sliding control should be the same height as the nested child view, that is, the sliding control should be match_parent, and its child view and ppAdding should not be set margin or ppAdding. Width has no such limitation.
ViewPager support
If your ViewPager hosts sub-layouts (or fragments) that don’t slide vertically, use plain ViewPager. If you can slide vertically, then your ViewPager needs to implement the IConsecutiveScroller interface and return the view object that you want to slide. The framework provided a custom control that implemented the IConsecutiveScroller interface: ConsecutiveViewPager. Using this control, then your ConsecutiveViewPager child view(or the root layout of the Fragment) is a vertically sliding view, as in: RecyclerView, NestedScrollView, ConsecutiveScrollerLayout can. So your ViewPager can correctly with ConsecutiveScrollerLayout sliding.
<?xml version="1.0" encoding="utf-8"? >
<com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/scrollerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorPrimary"
app:tabIndicatorHeight="3dp"
app:tabMode="scrollable"
app:tabSelectedTextColor="@color/colorPrimary" />
<com.donkingliang.consecutivescroller.ConsecutiveViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.donkingliang.consecutivescroller.ConsecutiveScrollerLayout>
Copy the code
The top of a layout is overlaid on top of the following layout. Sometimes we want the top of a TabLayout to float at the top, but we don’t want it to overwrite the content blocking the ViewPager. ConsecutiveViewPager provides setAdjustHeight to adjust its layout height so that it is not covered by a TabLayout. Note: only ConsecutiveScrollerLayout is ConsecutiveScrollerLayout lowest department can do that.
// Ensure that the height of the tabLayout can be obtained
tabLayout.post(new Runnable() {
@Override
public void run(a) { viewPager.setAdjustHeight(tabLayout.getHeight()); }});Copy the code
Other Matters needing attention
1. Sliding layout of WebView during loading may lead to disconnection between WebView and other views in display. The following method can avoid this problem to some extent.
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress); scrollerLayout.checkLayoutChange(); }});Copy the code
2, SmartRefreshLayout and SwipeRefreshLayout refresh controls can be nested ConsecutiveScrollerLayout drop-down refresh functions, But ConsecutiveScrollerLayout nested inside them to refresh the view, because the son ConsecutiveScrollerLayout sliding content such as part of the view. Unless you set SmartRefreshLayout or SwipeRefreshLayout to app: layout_isrow =”false”.
3, inherit the AbsListView layout (ListView, GridView, etc.), sliding may be out of sync with the user’s finger sliding, RecyclerView is recommended instead.
4. ConsecutiveScroller’s minSdkVersion is 19, and if your project supports less than 19, you can set:
<uses-sdk tools:overrideLibrary="com.donkingliang.consecutivescroller"/>
Copy the code
But don’t in the minSdkVersion is less than 19 projects using AbsListView subclass, because ConsecutiveScrollerLayout use is only for more than 19 AbsListView API.
5, use ConsecutiveScrollerLayout setOnVerticalScrollChangeListener slide () method to monitor the layout of the event. View the setOnScrollChangeListener provided () method has been invalid.
6, through getOwnScrollY () method to obtain ConsecutiveScrollerLayout vertical sliding distance, the View of getScrollY () method to get not ConsecutiveScrollerLayout integral sliding distance.