当前位置:网站首页>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;
}
}
边栏推荐
- 使用华为性能管理服务,按需配置采样率
- 将线程绑定在某个具体的CPU逻辑内核上运行
- Introduction to MySQL basics day4 power node [Lao Du] class notes
- Alcohol tester scheme: what principle does the alcohol tester measure alcohol solubility based on?
- Influencing factors of echo cancellation for smart speakers
- Maxiouassigner of mmdet line by line interpretation
- 文件上传 upload 组件 on-success 事件,添加自定义参数
- Treatment process record of Union Medical College Hospital (Dongdan hospital area)
- Detailed explanation of pytoch's scatter function
- TiDB 6.0:让 TSO 更高效丨TiDB Book Rush
猜你喜欢

Rew acoustic test (II): offline test

2021-04-29

Interpretation of orientedrcnn papers

C#访问MongoDB并执行CRUD操作

Flink Sql -- toAppendStream doesn‘t support consuming update and delete changes which

Detectron2 source code reading 3-- encapsulating dataset with mapper

A troubleshooting of CPU bottom falling

Redis design and Implementation (VI) | cluster (sharding)

Codeworks 5 questions per day (1700 for each) - the third day

基于Svelte3.x桌面端UI组件库Svelte UI
随机推荐
Vite project require syntax compatibility problem solving require is not defined
Flink Sql -- toAppendStream doesn‘t support consuming update and delete changes which
Opencv learning notes -day10 logical operation of image pixels (usage of rectangle function and rect function and bit related operation in openCV)
2021-05-06
将线程绑定在某个具体的CPU逻辑内核上运行
C#访问SQL Server数据库两种方式的比较(SqlDataReader vs SqlDataAdapter)
[untitled]
Esp32 (6): Bluetooth and WiFi functions for function development
Axure制作菜单栏效果
Introduction to MySQL basics day4 power node [Lao Du] class notes
codeforces每日5题(均1700)-第三天
Interference source current spectrum test of current probe
Axure make menu bar effect
Mmdet line by line code interpretation of positive and negative sample sampler
Introduction to the runner of mmcv
mysql基础入门 day4 动力节点[老杜]课堂笔记
关于Lombok的@Data注解
[data analysis and display]
icon资源
C accesses mongodb and performs CRUD operations