天天看點

Android Material Design之CoordinatorLayout一、CoordinatorLayout簡介二、CoordinatorLayout作用三、CoordinatorLayout.Behavior研究四、自定義Behavior項目源碼總結參考資料

一、CoordinatorLayout簡介

java.lang.Object
   ↳    android.view.View
       ↳    android.view.ViewGroup
           ↳    android.support.design.widget.CoordinatorLayout 
           

實作了NestedScrollingParent接口,CoordinatorLayout, NestedScrollView, SwipeRefreshLayout都實作了這個接口

CoordinatorLayout is a super-powered FrameLayout. 是以屬性和FrameLayout有點像

CoordinatorLayout 控件是design下最重要的一個控件,也是最複雜、功能最強大的,這從他的作用就可以看的出來

二、CoordinatorLayout作用

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的作用就兩個:

  • 作為一個最頂層根布局因為CoordinatorLayout本身就是繼承ViewGroup
  • 作為一個容器協調子View的行為(通過CoordinatorLayout.Behavior)

是以這裡最重要就是這個Behavior了,如果你完全掌握了Behavior,CoordinatorLayout就搞定了

三、CoordinatorLayout.Behavior研究

檢視CoordinatorLayout的源碼我們可以看到這是一個抽象類,裡面定義了很多方法,如果需要使用我們要繼承CoordinatorLayout.Behavior然後重新一些方法。

我們拿AppBarLayout為例,AppBarLayout中有兩個Behavior,一個是拿來給它自己用的,另一個是拿來給它的兄弟結點用的,我們重點關注下AppBarLayout.ScrollingViewBehavior這個類。

我們用到的appbar_scrolling_view_behavior指的也是AppBarLayout.ScrollingViewBehavior這個類

通過檢視ScrollingViewBehavior也是繼承CoordinatorLayout.Behavior

java.lang.Object
   ↳    android.support.design.widget.CoordinatorLayout.Behavior<V extends android.view.View>
       ↳    android.support.design.widget.AppBarLayout.ScrollingViewBehavior 
           

我們看看CoordinatorLayout.Behavior類中的以下方法:

1、layoutDependsOn

@Override
 public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
       //如果dependency是AppBarLayout的執行個體,說明它就是我們所需要的Dependency
       return dependency instanceof AppBarLayout;
 }
           

這個方法告訴CoordinatorLayout,這個view是依賴AppBarLayout的,後續父親可以利用這個方法,查找到這個child所有依賴的兄弟結點。在CoordinatorLayout.Behavior直接return false;

2、onDependentViewChanged

//每次dependency位置發生變化,都會執行onDependentViewChanged方法
 @Override
 public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
        View dependency) {
        return false;
 }
           

這個方法,可以在這個回調中記錄dependency的一些位置資訊,在onLayoutChild中利用儲存下來的資訊進行計算,然後得到自身的具體位置。

3、onLayoutChild

public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
            return false;
        }
           

這個方法是用來子view用來布局自身使用,如果依賴其他view,那麼系統會首先調用

4、onMeasureChild

public boolean onMeasureChild(CoordinatorLayout parent, V child,
                int parentWidthMeasureSpec, int widthUsed,
                int parentHeightMeasureSpec, int heightUsed) {
            return false;
        }
           

這個是CoordinatorLayout在進行measure的過程中,利用Behavior對象對子view進行大小測量的一個方法。

在這個方法内,我們可以通過parent.getDependencies(child);這個方法,擷取到這個child依賴的view,然後通過擷取這個child依賴的view的大小來決定自身的大小。

5、NestedScroll

public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout,
                V child, View directTargetChild, View target, int nestedScrollAxes) {
            return false;
        }

 public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child,
                View directTargetChild, View target, int nestedScrollAxes) {
            // Do nothing
        }  

 public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
            // Do nothing
        }

 public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target,
                int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
            // Do nothing
        }    
           

這幾個方法剛好是NestedScrollingParent的方法(CoodinatorLayout是繼承了NestedScrollingParent的),也就是對CoodinatorLayout進行的一個代理(Proxy),即CoordinatorLayout自己不對這些消息進行處理,而是傳遞給子view的Behavior,進行處理。利用這樣的方法,實作了view和view之間的互動和視覺的協同(布局、滑動)。

有興趣可以看 鴻 洋大神的NestedScrolling機制完全解析:

Android NestedScrolling機制完全解析 帶你玩轉嵌套滑動

四、自定義Behavior

實作如下紅色button,高度保持跟藍色View一樣,x軸方向相反

Android Material Design之CoordinatorLayout一、CoordinatorLayout簡介二、CoordinatorLayout作用三、CoordinatorLayout.Behavior研究四、自定義Behavior項目源碼總結參考資料

構造方法

public MyBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics display = context.getResources().getDisplayMetrics();
        width = display.widthPixels;
    }
           

一定要重寫這個構造函數。因為CoordinatorLayout源碼中parseBehavior()函數中直接反射調用這個構造函數。

static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[] {
        Context.class,
        AttributeSet.class
};
           

然後我們實作layoutDependsOn、onDependentViewChanged方法,自定義Behavior就完成了

下面是MyBehavior 的源碼

public class MyBehavior extends CoordinatorLayout.Behavior<Button> {

    private int width;

    public MyBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics display = context.getResources().getDisplayMetrics();
        width = display.widthPixels;
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, Button child, View dependency) {
        //如果dependency是TempView的執行個體,說明它就是我們所需要的Dependency
        return dependency instanceof FollowView;
    }

    //每次dependency位置發生變化,都會執行onDependentViewChanged方法
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, Button child, View dependency) {

        //根據dependency的位置,設定Button的位置
        int top = dependency.getTop();
        int left = dependency.getLeft();

        int x = width - left - child.getWidth();
        int y = top;

        setPosition(child, x, y);

        return true;
    }

    private void setPosition(View v, int x, int y) {
        CoordinatorLayout.MarginLayoutParams layoutParams = (CoordinatorLayout.MarginLayoutParams) v.getLayoutParams();
        layoutParams.leftMargin = x;
        layoutParams.topMargin = y;
        v.setLayoutParams(layoutParams);
    }
}
           

項目源碼

https://github.com/Yi520153/DesignCoordinatorLayout

總結

可以看到CoodinatorLayout給我們實作了一個可以被子view代理實作方法的一個布局。這和傳統的ViewGroup不同,子view從此知道了彼此之間的存在,一個子view的變化可以通知到另一個子view。CoordinatorLayout所做的事情就是當成一個通信的橋梁,連接配接不同的view。使用Behavior對象進行通信。

參考資料

CoordinatorLayout的使用如此簡單

關于CoordinatorLayout與Behavior的一點分析

CoordinatorLayout布局的使用方式

CoordinatorLayout與滾動的處理

Android Support Design 中 CoordinatorLayout 與 Behaviors 初探