什么是 CoordinatorLayout
官方文檔是這么描述的
CoordinatorLayout is a super-powered FrameLayout
CoordinatorLayout is intended for two primary use cases:
- As a top-level application decor or chrome layout
- As a container for a specific interaction with one or more child views
翻譯一下
CoordinatorLayout 是一個加強版的 FrameLayout
主要用途有兩個:
- 用作應用的頂層布局管理器给猾,也就是作為用戶界面中所有UI控件的容器
- 用作相互之間具有特定交互行為的UI控件的容器
Coordinator 是協(xié)調者的意思,協(xié)調者布局责循,其實就是協(xié)調各個子 View 的一個容器蓉媳。
很多 Material Design 的效果都離不開 CoordinatorLayout冒冬。
比如 https://material.io/guidelines/components/snackbars-toasts.html#snackbars-toasts-usage 中的 Don’t block the floating action button 部分舱沧。
比如 https://material.io/guidelines/patterns/scrolling-techniques.html#scrolling-techniques-app-bar-scrollable-regions 中的各種滑動時隱藏畫面頂部內容的效果溉愁。
本篇文章先介紹一下 CoordinatorLayout 的基本使用屋摇,之后的文章再講怎么實現(xiàn)各種 Material Design 效果揩魂。
CoordinatorLayout 的簡單使用
參考這篇博文中的例子,效果如下
例子中有一個 Button炮温,有一個 TextView火脉,拖動 Button,TextView 也跟著一起移動柒啤,這就是交互行為倦挂。
其實這是一個觀察者模式,Button 是被觀察者担巩,TextView 是觀察者方援,TextView 觀察 Button 的移動,一旦移動了涛癌,TextView 也跟著移動犯戏。
看看代碼是怎么實現(xiàn)的
首先添加 design library
compile 'com.android.support:design:25.4.0'
布局文件如下
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="被觀察者" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="觀察者"
app:layout_behavior=".FollowBehavior" />
</android.support.design.widget.CoordinatorLayout>
把 Button 和 TextView 放到一個 CoordinatorLayout 中窥浪,并且設置 TextView 的 app:layout_behavior 屬性。
再來看看 FollowBehavior 類
public class FollowBehavior extends CoordinatorLayout.Behavior {
public FollowBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof Button;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
child.setX(dependency.getX() + 150);
child.setY(dependency.getY() + 150);
return true;
}
}
繼承自 CoordinatorLayout.Behavior笛丙。
layoutDependsOn 是用來確定 dependent view 的漾脂,CoordinatorLayout 下面的所有子 View 都會去判斷。例子中把 Button 作為本次交互的對象胚鸯。
onDependentViewChanged 當 dependent view 發(fā)生變化時骨稿,這個方法會被調用,從而完成交互行為姜钳。例子中設置始終跟隨 Button 移動坦冠。
控制 Button 移動的代碼如下
public class MainActivity extends AppCompatActivity {
float downEventX, downEventY;
float downButtonX, downButtonY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downEventX = event.getRawX();
downEventY = event.getRawY();
downButtonX = v.getX();
downButtonY = v.getY();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
v.setX(downButtonX + event.getRawX() - downEventX);
v.setY(downButtonY + event.getRawY() - downEventY);
}
return true;
}
});
}
}
這樣,一個簡單的通過 CoordinatorLayout 來進行 View 的交互的例子就完成了哥桥。
View 的交互是通過 Behavior 來進行的辙浑,可以使用系統(tǒng)定義好的 Behavior,也可以像本例一樣自定義 Behavior拟糕。
CoordinatorLayout 的神奇之處就在于它能夠讓它的子 View 們知道彼此的存在判呕,CoordinatorLayout 作為一個通信的橋梁,通過 Behavior 進行通信送滞,把一個 View 的變化通知給另一個 View侠草。