当前位置:网站首页>Using appbarlayout to realize secondary ceiling function
Using appbarlayout to realize secondary ceiling function
2022-06-30 09:00:00 【Byte station】
I open source a convenience RecyclerView Ceiling mounted Android library , Welcome to https://github.com/lizijin/StickyHeaderForRecyclerView, If you use this library , Please give us your valuable comments .
It currently supports the following functions :
- Support single type ceiling function
- Support multi type ceiling function
- Support to open and close the ceiling function
- Support ceiling function at specified position
- Support to set the ceiling offset
- Support customization RecyclerView On Item Ceiling boundary customization
- Can fit seamlessly AppBarLayout
Come to the point , Recently, we need to achieve a secondary ceiling effect ,UE The effect picture given is as follows

The analysis is as follows :
See the ceiling effect , First think of using CoordinatorLayout and AppBarLayout To achieve . The interface is mainly divided into 2 Parts of :
- Sliding area at the bottom , It can be used ScrollView perhaps RecyclerView Realization .
- The ceiling area at the top uses AppBarLayout Realization .
Let's split the ceiling area at the top , It can be divided into the following 4 Parts of :
- Brand area , When it goes down ,RecyclerView Show the first Item When , The area just started to slide down .

- Category picture area , When it goes down , The area will slide down , When the area reaches the top, it will always suck the top , until RecyclerView first Item When it appears , Just sliding down .

- Category title area , When you slide up , This area will first follow up and slide up , When the area reaches the top, it will always suck the top

- Sort and filter areas , When it goes down , No matter what RecyclerView Where is the current position , The area will first follow down and out


In this paper , I put the slide up area 3 Imbibition , Slide down the area 2 Ceiling has a definition called Secondary ceiling , There will be a contradiction in the function of secondary ceiling , We want the region to 3 Sucking on the top while sliding up , So it's bound to cause regional 4 Unable to act as AppBarLayout Part of ( be familiar with AppBarLayout Of scroll The students should be able to understand , If you can't understand , In the second half of this article, we will explain ), So the region 4 It can only be done as RecyclerView The head of , As the head , Only when RecyclerView Down to the top , Area 4 To follow down and slide out , Can't satisfy the upper area 4 The requirements of .
When analyzing such a contradictory point . My first reaction was , Use AppBarLayout Unable to meet existing requirements , I have to rewrite one myself Behavior To achieve this function , And the Behavior You have to meet the following 3 Conditions :
- Behavior It needs to deal with sliding events , When sliding in the ceiling area ,RecyclerView Need linkage
- Behavior Need to deal with RecylerView And the nested sliding between the ceiling area , stay RecyclerView When the area is sliding , The ceiling area needs linkage
- Up slide zone 3 We need to suck the top , When you slide down, the area 4 We need to suck the top
Just think of meeting these three conditions to achieve the effect , Can't wait to try , But calm down for a few seconds and you'll find , But dealing with sliding Events , We need to consider not only the handling of various event types , The processing of nested sliding , as well as CoordiatorLayout Complex event distribution logic , also Fling And so on , All of a sudden, it's a huge amount of work , It's really necessary to write one by hand Behavior Do you ? Don't Google Dad's AppBarLayout It's really that shallow , Can only achieve a single ceiling function ? In handwriting Behavior It seemed necessary before , have a look AppBarLayout The internal implementation principle , The so-called know yourself and know the other can win a hundred battles , It's also known as knowing it , Know why . If AppBarLayout It can't realize the function of secondary ceiling , We need to know why , If we can achieve the function of secondary ceiling , So what should we do ?
After three days and three nights , Keep on being right AppBarLayout In depth study of source code and continuous Demo verification , Finally found , original Google Dad is very thoughtful , The function of secondary ceiling , I've already thought about it for us , Just waiting for us to discover . Finally, without having to write a custom line Behavior、 Without writing nested sliding logic , Have succeeded in carrying out an assignment , Completed the development of secondary ceiling effect . The renderings are as follows :

The code is as follows
Layout file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".coordinatorlayout.CollapsingToolbarLayoutActivity">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/long_hate_song"></TextView>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pic1"
android:contentDescription=" Ceiling area one "
android:gravity="center"
android:scaleType="fitXY"
app:layout_scrollFlags="scroll" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pic2"
android:contentDescription=" Ceiling area two "
android:gravity="center"
app:layout_scrollFlags="enterAlways|scroll"></ImageView>
<com.peter.viewgrouptutorial.coordinatorlayout.FloatLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_scrollFlags="enterAlways|scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/text.view3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pic3"
android:contentDescription=" Ceiling area three "
android:gravity="center"
android:text="HEAD3"
app:layout_pin="true" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pic4"
android:contentDescription=" Ceiling area four "
android:gravity="center"
app:layout_pin="false" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pic5"
android:contentDescription=" Ceiling area four "
app:layout_pin="false" />
</com.peter.viewgrouptutorial.coordinatorlayout.FloatLinearLayout>
>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Customize FloatLinearLayout
public class FloatLinearLayout extends LinearLayout {
int currentOffset;
private AppBarLayout.OnOffsetChangedListener onOffsetChangedListener;
public FloatLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setChildrenDrawingOrderEnabled(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (((LayoutParams) child.getLayoutParams()).pin) {
setMinimumHeight(child.getMeasuredHeight());
break;
}
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Add an OnOffsetChangedListener if possible
final ViewParent parent = getParent();
if (parent instanceof AppBarLayout) {
// Copy over from the ABL whether we should fit system windows
ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View) parent));
if (onOffsetChangedListener == null) {
onOffsetChangedListener = new FloatLinearLayout.OffsetUpdateListener();
}
((AppBarLayout) parent).addOnOffsetChangedListener(onOffsetChangedListener);
// We're attached, so lets request an inset dispatch
ViewCompat.requestApplyInsets(this);
}
}
@Override
protected void onDetachedFromWindow() {
// Remove our OnOffsetChangedListener if possible and it exists
final ViewParent parent = getParent();
if (onOffsetChangedListener != null && parent instanceof AppBarLayout) {
((AppBarLayout) parent).removeOnOffsetChangedListener(onOffsetChangedListener);
}
super.onDetachedFromWindow();
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
return childCount - i - 1;
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
public static class LayoutParams extends LinearLayout.LayoutParams {
boolean pin = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FloatLinearLayout_Layout);
pin =
a.getBoolean(
R.styleable.FloatLinearLayout_Layout_layout_pin, false);
a.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(int width, int height, float weight) {
super(width, height, weight);
}
public LayoutParams(ViewGroup.LayoutParams p) {
super(p);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
public LayoutParams(LinearLayout.LayoutParams source) {
super(source);
}
}
private class OffsetUpdateListener implements com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener {
OffsetUpdateListener() {
}
@Override
public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
currentOffset = verticalOffset;
for (int i = 0, z = getChildCount(); i < z; i++) {
final View child = getChildAt(i);
final FloatLinearLayout.LayoutParams lp = (FloatLinearLayout.LayoutParams) child.getLayoutParams();
final ViewOffsetHelper offsetHelper = getViewOffsetHelper(child);
if (lp.pin) {
int offset = -currentOffset - getTop();
offsetHelper.setTopAndBottomOffset(MathUtils.clamp(offset, 0, offset));
}
}
}
}
@NonNull
static ViewOffsetHelper getViewOffsetHelper(@NonNull View view) {
ViewOffsetHelper offsetHelper = (ViewOffsetHelper) view.getTag(com.google.android.material.R.id.view_offset_helper);
if (offsetHelper == null) {
offsetHelper = new ViewOffsetHelper(view);
view.setTag(com.google.android.material.R.id.view_offset_helper, offsetHelper);
}
return offsetHelper;
}
}
边栏推荐
- 国债逆回购绝对安全吗 网上怎么开户
- [untitled]
- 启动jar包报错UnsupportedClassVersionError,如何修复
- Based on svelte3 X desktop UI component library svelte UI
- 将线程绑定在某个具体的CPU逻辑内核上运行
- Flink Sql -- toAppendStream doesn‘t support consuming update and delete changes which
- Esp32 things (x): other functions
- 基于Svelte3.x桌面端UI组件库Svelte UI
- C#访问SQL Server数据库两种方式的比较(SqlDataReader vs SqlDataAdapter)
- Occasionally, Flink data is overstocked, resulting in checkpoint failure
猜你喜欢

vim 从嫌弃到依赖(21)——跨文件搜索

Redis design and Implementation (I) | data structure & object

Axure make menu bar effect

Advanced technology management -- how managers design and build echelons

Rew acoustic test (VI): signal and measurement

Use Huawei performance management service to configure the sampling rate on demand
![[kotlin collaboration process] complete the advanced kotlin collaboration process](/img/43/9c4b337caf406537e317dea2ed5f17.png)
[kotlin collaboration process] complete the advanced kotlin collaboration process

Esp32 (4): overview of the overall code architecture

Set, map and modularity

Interference source current spectrum test of current probe
随机推荐
Interference source current spectrum test of current probe
El input limit can only input numbers
Alcohol tester scheme: what principle does the alcohol tester measure alcohol solubility based on?
mysql基础入门 day3 动力节点[老杜]课堂笔记
Opencv learning notes-day9 opencv's own color table operation (colormap coloraptypes enumeration data types and applycolormap() pseudo color function)
Opencv learning notes -day2 (implemented by the color space conversion function cvtcolar(), and imwrite image saving function imwrite())
Raspberry pie 4B no screen installation system and networking using VNC wireless projection function
Qt通过Url下载文件
快应用中实现自定义抽屉组件
Redis design and Implementation (I) | data structure & object
Opencv learning notes-day5 (arithmetic operation of image pixels, add() addition function, subtract() subtraction function, divide() division function, multiply() multiplication function
Torchvision loads the weight of RESNET except the full connection layer
100 lines of code and a voice conversation assistant
Redis design and Implementation (V) | sentinel sentry
Esp32 (7): I2S and I2C drivers for function development
基于Svelte3.x桌面端UI组件库Svelte UI
C#訪問SQL Server數據庫兩種方式的比較(SqlDataReader vs SqlDataAdapter)
2021-02-18
Unity simple shader
vite項目require語法兼容問題解决require is not defined