current position:Home>Custom Behavior of Android CoordinatorLayout
Custom Behavior of Android CoordinatorLayout
2023-01-25 11:57:03【Someone from Yungu Li】
协调布局CoordinatorLayout
CoordinatorLayout简介
- CoordinatorLayoutThe Chinese translation is coordinated layout,It coordinates interactions between sub-layouts,When touched changes the childViewSometimes it will affect the layout and produce a linkage effect,The root cause lies inBehavior类
- CoordinatorLayoutI don't control myselfView,All control is thereBehavior这个类
- 系统里Behavior有FloatingActionButton.Behavior和AppBarLayout.Behavior等等;Our usual user linkages are defined by the systemBehavior来实现
- 系统里面BehavoirSome implement complex control functions.But it is limited after all,We can implement our own in a custom wayBehavior
自定义Behavior有两种方式
1、一个View监听另一个View的状态变化
See the running effect as shown in the figure below:
实现方式如下:
1.继承CoordinatorLayout.Behavior类
/** * 第一种自定义Behavior方式 */
public class DependencyBehavior extends CoordinatorLayout.Behavior<Button>
2.重写Behavior两个参数的构造方法
/** * This constructor must be overloaded,因为在CoordinatorLayoutHere use reflection to obtain * Behavior的时候就是拿的这个构造 */
public DependencyBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
width = context.getResources().getDisplayMetrics().widthPixels;
}
3.重写layoutDependsOn和onDependentViewChanged方法
/** * 确定依赖关系 * * @param parent * @param child to perform an actionView * @param dependency child要依赖的View,,,也就是Child要监听的View * @return Determine dependencies logically */
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, Button child, View dependency) {
Log.e("Behavior", "----child: " + child.toString());
Log.e("Behavior", "----dependency: " + dependency.toString());
return dependency instanceof DragTextView;
}
/** * 状态(大小、位置、Show or not etc)This method is executed when a change occurs * 在这里我们定义child要执行的具体动作 * * @param parent * @param child * @param dependency * @return */
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, Button child, View dependency) {
int top = dependency.getTop();
int left = dependency.getLeft();
int x = width - left - child.getWidth();
int y = top;
setPosition(child, x, y);
return true;
}
4.在xml文件中引用app:layout_behavior
<?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"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="88dp"
android:layout_height="88dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="child"
android:textAllCaps="false"
android:textColor="@android:color/white"
app:layout_behavior="com.coordinator.behavior.first.DependencyBehavior" />
<com.coordinator.behavior.first.DragTextView
android:layout_width="88dp"
android:layout_height="88dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="dependency"
android:textAllCaps="false"
android:textColor="@android:color/white" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2、View监听CoordinatorLayout里的滑动状态
这个要求CoordinatorLayoutThere must be sliding controls inside,At least it has to be doneNestedScrollingChild接口,比如RecyclerView,NestScrollView等滑动控件;
看运行效果:
1.继承CoordinatorLayout.Behaviorclass or systemBehavior类
/** * The second type of customizationBehavior方式 */
public class ScrollBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
2.重写Behavior两个参数的构造方法
/** * This constructor must be overloaded,因为在CoordinatorLayoutHere use reflection to obtain * Behavior的时候就是拿的这个构造 */
public ScrollBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
3.rewrite at leastonStartNestedScroll和onNestedScroll方法,Of course there are others that can be rewritten as well
/** * 当子View调用NestedScrollingChild的方法startNestedScroll时,会调用该方法. * Be sure to return according to your needstrue,This method determines whether the current control can receive its interiorView(Not a direct childView)滑动时的参数 * * @param coordinatorLayout * @param child This is dependent on other scrollingView的另一个View,这里是FloatingActionButton * @param directTargetChild directly trigger nested scrollingview的对象 * @param target 触发嵌套滚动的view (在这里如果不涉及多层嵌套的话,target和directTargetChild是相同的) * @param nestedScrollAxes Direction flag for nested swipe * @return Determine which direction we care about sliding based on the return value(x轴 / y轴),这里我们关心的是y轴方向 */
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingActionButton child,
View directTargetChild,
View target,
int nestedScrollAxes) {
Log.e("123", "directTargetChild: " + directTargetChild);
Log.e("123", "target: " + target);//在这里directTargetChild和target都是NestedScrollView
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
/** * 当子View调用dispatchNestedPreScroll时会调用该方法 * This method is passed in internallyView移动的dx,dy,If you need to consume certaindx,dy,will pass the last parameterconsumed * 进行指定.For example I want to consume half of itdy,就可以写consumed[1]=dy/2 * dxIndicates this scrollingxThe total distance resulting from the direction * * @param coordinatorLayout * @param child 此处是FloatingActionButton * @param target 同上 * @param dxConsumed target已经消费的x方向的距离 * @param dyConsumed target已经消费的x方向的距离 * @param dxUnconsumed x方向剩下的滑动距离 * @param dyUnconsumed y方向剩下的滑动距离 */
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout,
FloatingActionButton child,
View target,
int dxConsumed,
int dyConsumed,
int dxUnconsumed,
int dyUnconsumed) {
//Log.e("234", "===============dxConsumed: " + dxConsumed);
Log.e("234", "===============dyConsumed: " + dyConsumed);
//Log.e("234","===============dxUnconsumed: "+dxUnconsumed);
Log.e("234", "===============dyUnconsumed: " + dyUnconsumed);
if (((dyConsumed > 0 && dyUnconsumed == 0)
|| (dyConsumed == 0 && dyUnconsumed > 0))
) {
//上滑隐藏
child.animate()
.scaleY(0).scaleX(0)
.setDuration(200)
.start();
} else if (((dyConsumed < 0 && dyUnconsumed == 0)
|| (dyConsumed == 0 && dyUnconsumed < 0))
) {
//下滑显示
child.animate()
.scaleY(1).scaleX(1)
.setDuration(200)
.start();
}
}
4.在xml文件中引用app:layout_behavior
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:src="@android:drawable/ic_dialog_email"
app:backgroundTint="@color/colorAccent"
app:elevation="8dp"
app:fabSize="mini"
app:layout_behavior="com.coordinator.behavior.second.ScrollBehavior"
app:pressedTranslationZ="16dp"
app:rippleColor="@color/colorPrimary" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
CoordinatorLayout交互原理
1.子View如何拿到Behavior?
比如下面的xmlHow to get it in the fileBehavior的呢?
CoordinatorLayoutThere is a process to add childrenView,Let's start with where to start,
这里的LayoutParam肯定是CoordinatorLayout.LayoutParam生成的吧;
这里明显Behavior就是在LayoutParamsIt can be analyzed in it,就是解析的app:layout_behavior属性;
2.BehaviorHow did you get the incident?
The above is just a special case of code,In fact, in the event delivery,你会发现,所有出现Behavior的地方Behaviorwill take over!I don't want to analyze a little bit in the clouds here,It's so easy to miss the forest for the trees.你就从
dispatchTouchEvent,
onInterception,
onTouchEvent,
These events are analyzed in the code,You can see the code snippet;
Behavior b = lp.getBehavior()
你懂得,Just transfer all event handling to it;
Implement a coordinated layout yourself
运行效果如下图:
1.Implement your own coordinate layoutBehaviorCoordinatorLayout
public class BehaviorCoordinatorLayout extends RelativeLayout implements NestedScrollingParent,
ViewTreeObserver.OnGlobalLayoutListener {
public BehaviorCoordinatorLayout(Context context, AttributeSet attrs) {
super(context, attrs);
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View v = getChildAt(i);
LP lp = (LP) v.getLayoutParams();
BeHavior mBehavior = lp.mBehavior;
if (mBehavior != null) {
mBehavior.onNestedScroll(this, v, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
}
}
@Override
public void onGlobalLayout() {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View v = getChildAt(i);
LP lp = (LP) v.getLayoutParams();
BeHavior mBehavior = lp.mBehavior;
if (mBehavior != null) {
mBehavior.onLayoutChild(this, v, 0);
}
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LP(getContext(), attrs);
}
2.实现自己的LayoutParams
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LP(getContext(), attrs);
}
public static class LP extends RelativeLayout.LayoutParams {
BeHavior mBehavior;
public LP(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.BehaviorCoordinatorLayout_Layout);
if (ta.hasValue(R.styleable.BehaviorCoordinatorLayout_Layout_custom_layout_behavior)) {
String clStr = ta.getString(R.styleable.BehaviorCoordinatorLayout_Layout_custom_layout_behavior);
Log.e("tag", clStr);
mBehavior = parseBehavior(c, attrs, clStr);
Log.e("tag", (mBehavior == null) + " ");
}
ta.recycle();
}
public BeHavior parseBehavior(Context context, AttributeSet attrs, String name) {
try {
Class<?> clazz = Class.forName(name, false, context.getClassLoader());
Constructor c = clazz.getConstructor(Context.class, AttributeSet.class);
c.setAccessible(true);
return (BeHavior) c.newInstance(context, attrs);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
3.实现自己的Behavior类
public class BeHavior<V extends View> {
public BeHavior(Context context, AttributeSet attrs) {
}
public boolean onLayoutChild(BehaviorCoordinatorLayout parent, V child,
int layoutDirection) {
return false;
}
public void onNestedScroll(BehaviorCoordinatorLayout coordinatorLayout, V child,
View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed) {
}
}
4.实现自己的Behavior子类
ublic class ImageViewBehavior extends BeHavior<ImageView> {
public ImageViewBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
int maxHeight = 400;
int originHeight = 0;
@Override
public boolean onLayoutChild(BehaviorCoordinatorLayout parent, ImageView child, int layoutDirection) {
if (originHeight == 0) {
originHeight = child.getHeight();
}
return super.onLayoutChild(parent, child, layoutDirection);
}
@Override
public void onNestedScroll(BehaviorCoordinatorLayout coordinatorLayout, ImageView child,
View scrollview, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
if (scrollview.getScrollY() > 0) {
BehaviorCoordinatorLayout.LP lp = (BehaviorCoordinatorLayout.LP) child.getLayoutParams();
lp.height = lp.height - Math.abs(dyConsumed);
if (lp.height <= originHeight) {
lp.height = originHeight;
}
child.setLayoutParams(lp);
} else if (scrollview.getScrollY() == 0) {
BehaviorCoordinatorLayout.LP lp = (BehaviorCoordinatorLayout.LP) child.getLayoutParams();
lp.height = lp.height + Math.abs(dyUnconsumed);
if (lp.height >= maxHeight) {
lp.height = maxHeight;
}
child.setLayoutParams(lp);
}
}
}
public class ToolbarBehavior extends BeHavior<Toolbar> {
public ToolbarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
int maxHeight = 400;
@Override
public void onNestedScroll(BehaviorCoordinatorLayout coordinatorLayout, Toolbar child, View scrollView,
int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
if (scrollView.getScrollY() <= maxHeight) {
child.setAlpha(scrollView.getScrollY() * 1.0f / maxHeight);
} else if (scrollView.getScrollY() == 0) {
child.setAlpha(0);
}
}
}
5.xml布局中引用
<?xml version="1.0" encoding="utf-8"?>
<com.coordinator.behavior.custom.BehaviorCoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="50dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:contentDescription="@string/app_name"
android:src="@mipmap/london"
app:custom_layout_behavior="com.coordinator.behavior.custom.ImageViewBehavior" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/img">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text" />
</androidx.core.widget.NestedScrollView>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorPrimary"
app:custom_layout_behavior="com.coordinator.behavior.custom.ToolbarBehavior" />
</com.coordinator.behavior.custom.BehaviorCoordinatorLayout>
copyright notice
author[Someone from Yungu Li],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2023/025/202301251120395901.html
The sidebar is recommended
- The front end of actual combat: copy write millet's official website on the first day
- 1. Linux application programming and network programming---file IO notes in Linux system
- [Front-end notes - CSS] 10. Cascading and inheritance + selector
- 8. Linux application programming and network programming---Linux network programming notes
- [Java|golang] 1828. Count the number of points in a circle
- [Front-end notes——CSS] 11. Box model + background and border
- C + + large Numbers together, according to a combined
- 3. Linux application programming and network programming --- get system information notes
- The use and principle of Kafka message queue
- 5. Linux application programming and network programming---signal notes in Linux
guess what you like
6 · Linux application programming and system programming - senior IO notes
Java collection common interview questions (4)
072-JAVA project training: Imitation QQ instant messaging software series lecture 7 (explaining the realization of the chat interface and functions)
Coordination center performance comparison: how zookeeper solves the load balancing problem
070-JAVA project training: imitation QQ instant messaging software series lecture five (explain user registration function)
Ubuntu installation and configuration (brief)
073-JAVA project training: imitation QQ instant messaging software series lecture eight (explain query and add friend function)
SQL injection classification and error injection EXP
All basic commands in linux fail, showing that the command cannot be found
4. Linux application programming and network programming---Linux process full solution notes (difference between process and program)
Random recommended
- Linux system - basic IO
- Hanlp's understanding of user-defined dictionaries (java version)
- Brief description and configuration of Maven
- 071-JAVA project training: imitation QQ instant messaging software series lecture six (explaining the function of QQ main interface)
- 【Maximum LeetCode】January Algorithm Training (12) Linked List
- 【Max LeetCode】January Algorithm Training (13) Doubly Linked List
- [Big Data Management] Java implements Bloom filter
- [Maximum LeetCode] Algorithm training in January (14) stack
- [Machine Learning] Adaboost Integrated Algorithm
- [Big Data Management] Java implements cuckoo filter (CF)
- Chaozhou Xiangqiao: "Charming Ancient City, Cultural Sharing" Spring Festival Intangible Cultural Heritage Market Opens
- [Big data management] Java realizes the dictionary tree TireTree
- [Max LeetCode] January Algorithm Training (11) Matrix
- New Express (Web framework based on HTTP module encapsulation NodeJS)
- JavaScript error-prone questions (stack processing, call function, prototype chain questions)
- Space "travel", lion and crane dance, intangible cultural heritage experience...During the Spring Festival, Zhuhai Jinwan is so fun!
- Wine 8.0 official release: better support for running Windows applications on Linux and other systems
- Zhongke Sugon: Sugon's new computer "participates in" "The Wandering Earth 2"
- Linux actual combat notes finishing (1.24)
- Winter Vacation JavaScript Tutorial Chapter 1 Variable Promotion
- Automatically execute the specified sql when the springBoot project starts
- Winter vacation javascript cram school Chapter 2 let & const temporary dead zone
- Microsoft CEO Nadella: We firmly believe that the wave of artificial intelligence is unstoppable
- [Bi She] Style Migration Based on CycleGAN [3] Code Migration to Server (Linux) and Environment Construction
- Axiba HTML
- Explore the vachar, test, longtext storage limits of the database mysql
- Web front-end development technology: Web front-end development technology
- Python data structure implements various sorting algorithms (including algorithm introduction and stability, complexity summary)
- Web front-end development technology: Vue routing
- 【 MySQL 】 the seventh part of the process control function
- Web front-end development technology: Vuex state management
- Important concepts and installation of Linux + vim common operations
- [MySQL] Part 9 MySQL Information Functions
- [MySQL] Part VIII Encryption and Decryption Functions
- PAT 1014 Sherlock Holmes' appointment (C++ implementation)
- Android gradle custom plug-in implementation
- Python numpy ValueError: setting an array element with a sequence.
- On Spring notes (annotation-based development)
- Ubuntu18.04 install Hadoop
- Android proguard code obfuscation and decompilation tool