談CoordinatorLayout.Behavior

Behavior 是 CoordinatorLayout為其 <b>子視圖</b> 提供的一種交互行為插件。
它實(shí)現(xiàn)了用戶可以操作子視圖的一種或多種交互行為灯荧,包括包括拖拽礁击,F(xiàn)ling(滑翔)或任何其他手勢(shì)。

直接子類

直接子類.png

CoordinatorLayout逗载、AppBarLayout哆窿、SwipeDismissBehavior等使用方法

自定義

<p>自定義Behavior,這里分為兩類:

  • <b>Dependent機(jī)制</b>:
    layoutDependsOnonDependentViewChanged作為一組厉斟。<b>Dependent機(jī)制</b>最常見(jiàn)的案例就是 FloatingActionButtonSnackBar的交互行為挚躯。如圖
  • <b>Nested機(jī)制</b>
    onStartNestedScrollonNestedScroll作為一組。<b>Nested機(jī)制</b>要求 CoordinatorLayout包含了一個(gè)實(shí)現(xiàn)了 NestedScrollingChild 接口的滾動(dòng)視圖控件擦秽,比如v7包中的 RecyclerView码荔,設(shè)置 Behavior屬性的Child View會(huì)隨著這個(gè)控件的滾動(dòng)而發(fā)生變化漩勤。如圖

如下只標(biāo)注了Behavior部分方法。開(kāi)發(fā)者可以根據(jù)自身業(yè)務(wù)需求有選擇的復(fù)寫(xiě)缩搅。

<b>部分方法</b>

  • layoutDependsOn

此方法用于判斷給定的View和同級(jí)View是否作為布局依賴關(guān)系越败。

/**
 * @param parent
 * @param child      給定的View,即應(yīng)用了layout_behavior的View
 * @param dependency 任何與child同級(jí)的View
 * @return 如果返回true誉己,那么parent將做兩件事:
 *          1.將忽略View的順序眉尸,總是先去布局dependency,之后布局child巨双。
 *          2.當(dāng)dependency視圖的布局或位置發(fā)生改變時(shí)噪猾,調(diào)用onDependentViewChanged方法。
 */
public boolean layoutDependsOn(CoordinatorLayout parent, 
                                View child, 
                                View dependency) {
    //判斷dependency是否是需要的依賴項(xiàng)筑累,如果是袱蜡,則返回true
    return false;
}
  • onDependentViewChanged

此方法用于對(duì)依賴視圖的改變做出響應(yīng)。開(kāi)發(fā)者可以復(fù)寫(xiě)此方法從而改變child的大小和位置慢宗,并返回true坪蚁。

public boolean onDependentViewChanged(CoordinatorLayout parent, 
                                        View child, 
                                        View dependency) {
    //處理child的位置或大小,并返回true
    return true;
}
  • onStartNestedScroll

此方法用于判斷是否進(jìn)行嵌套滾動(dòng)。與CoordinatorLayout的任何直接子項(xiàng)相關(guān)聯(lián)的任何Behavior都可以響應(yīng)此事件镜沽。如果返回true敏晤,表明CoordinatorLayout應(yīng)該充當(dāng)此滾動(dòng)的嵌套滾動(dòng)父項(xiàng)。只有返回true缅茉,才會(huì)執(zhí)行后續(xù)的嵌套滾動(dòng)方法嘴脾。

/**
 * @param coordinatorLayout
 * @param child             關(guān)聯(lián)Behavior的CoordinatorLayout的子View
 * @param directTargetChild CoordinatorLayout的子View或包含嵌套滾動(dòng)操作的View。比如RecycleView外層的RelativeLayout
 * @param target            嵌套滾動(dòng)的View
 * @param nestedScrollAxes  嵌套滾動(dòng)的坐標(biāo)軸蔬墩。SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL
 * @return
 */
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, 
                                    View child, 
                                    View directTargetChild, 
                                    View target, 
                                    int nestedScrollAxes) {
    return false;
}
  • onNestedScroll

此方法用于處理嵌套滾動(dòng)译打。
每次嵌套滾動(dòng)由嵌套滾動(dòng)子元素更新時(shí),onNestedScroll被調(diào)用拇颅,滾動(dòng)的消費(fèi)組件和未消費(fèi)組件以像素提供奏司。

/**
 *
 * @param coordinatorLayout
 * @param child
 * @param target
 * @param dxConsumed 水平方向滾動(dòng)增量,
 * @param dyConsumed 垂直方向滾動(dòng)增量樟插,如果大于0韵洋,手指上滑中;如果小于0,手指下滑中黄锤。
 * @param dxUnconsumed 同dyUnconsumed描述
 * @param dyUnconsumed 正常情況下麻献,始終為0,當(dāng)View處于最頂部或最底部猜扮,用戶仍然強(qiáng)制下滑或上滑時(shí),dy則不為0
 */
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, 
                            View child, 
                            View target, 
                            int dxConsumed, 
                            int dyConsumed, 
                            int dxUnconsumed, 
                            int dyUnconsumed) {
    if (dyConsumed > 0 && dyUnconsumed == 0) {
        System.out.println("上滑中监婶。旅赢。齿桃。");
    }
    if (dyConsumed == 0 && dyUnconsumed > 0) {
        System.out.println("到邊界了還在上滑。煮盼。短纵。");
    }
    if (dyConsumed < 0 && dyUnconsumed == 0) {
        System.out.println("下滑中。僵控。香到。");
    }
    if (dyConsumed == 0 && dyUnconsumed < 0) {
        System.out.println("到邊界了,還在下滑报破。悠就。。");
    }
}

原理分析

  1. Behavior所屬

通過(guò)查看CoordinatorLayout源碼可以知道充易,它有一個(gè)內(nèi)部類LayoutParams梗脾,用于存儲(chǔ)CoordinatorLayout的所有子View布局參數(shù),其中Behavior也是LayoutParams的一個(gè)屬性值盹靴。因此和文章開(kāi)始的描述保持了一致炸茧,Behavior只能設(shè)置到CoordinatorLayout子View上。

/**
 * Parameters describing the desired layout for a child of a {@link CoordinatorLayout}.
 */
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
    /**
     * A {@link Behavior} that the child view should obey.
     */
    Behavior mBehavior;
    //省略n多代碼
}
  1. 設(shè)置Behavior兩種方式

  • app:layout_behavior布局屬性

在布局中設(shè)置稿静,值為自定義 Behavior類的名字字符串(包含路徑)梭冠,有兩種寫(xiě)法,包含包名的全路徑和以”.”開(kāi)頭的省略項(xiàng)目包名的路徑改备。

app:layout_behavior="com.yolo.myapplication.MyBehavior"
app:layout_behavior="@string/appbar_scrolling_view_behavior"

  • @CoordinatorLayout.DefaultBehavior類注解

在需要使用 Behavior的控件源碼定義中添加該注解控漠,然后通過(guò)反射機(jī)制獲取。系統(tǒng)的 AppBarLayout绍妨、 FloatingActionButton都采用了這種方式润脸,所以無(wú)需在布局中重復(fù)設(shè)置。

  1. Behavior實(shí)例化

在LayoutParams構(gòu)造方法中他去,調(diào)用了parseBehavior(context, attrs, a.getString( R.styleable.CoordinatorLayout_Layout_layout_behavior))方法毙驯。判斷名稱,然后通過(guò)反射機(jī)制實(shí)例化Behavior灾测。從而回調(diào)Behaivor的其他方法爆价。<p>
注意:在自定義 Behavior時(shí),一定要重寫(xiě)第二個(gè)帶參數(shù)的構(gòu)造函數(shù)媳搪,否則這個(gè) Behavior是不會(huì)起作用的铭段。

static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
    if (TextUtils.isEmpty(name)) {
        return null;
    }

    final String fullName;
    if (name.startsWith(".")) {
                //如果behavior的值以 . 開(kāi)頭,則自動(dòng)補(bǔ)全包名信息
        // Relative to the app package. Prepend the app package name.
        fullName = context.getPackageName() + name;
    } else if (name.indexOf('.') >= 0) {
        // Fully qualified package name.
        fullName = name;
    } else {
        // Assume stock behavior in this package (if we have one)
        fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
                ? (WIDGET_PACKAGE_NAME + '.' + name)
                : name;
    }

    try {
        Map<String, Constructor<Behavior>> constructors = sConstructors.get();
        if (constructors == null) {
            constructors = new HashMap<>();
            sConstructors.set(constructors);
        }
        Constructor<Behavior> c = constructors.get(fullName);
        if (c == null) {
                        //通過(guò)反射實(shí)例化Behavior
            final Class<Behavior> clazz = (Class<Behavior>) Class.forName(fullName, true,
                    context.getClassLoader());
            c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
            c.setAccessible(true);
            constructors.put(fullName, c);
        }
        return c.newInstance(context, attrs);
    } catch (Exception e) {
        throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
    }
}

推薦閱讀

Android 一步一步分析Behavior
(譯)掌握 Coordinator Layout

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秦爆,一起剝皮案震驚了整個(gè)濱河市序愚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌等限,老刑警劉巖爸吮,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芬膝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡形娇,警方通過(guò)查閱死者的電腦和手機(jī)锰霜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)桐早,“玉大人癣缅,你說(shuō)我怎么就攤上這事『逶停” “怎么了友存?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)炫七。 經(jīng)常有香客問(wèn)我爬立,道長(zhǎng),這世上最難降的妖魔是什么万哪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任侠驯,我火速辦了婚禮,結(jié)果婚禮上奕巍,老公的妹妹穿的比我還像新娘吟策。我一直安慰自己,他們只是感情好的止,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布檩坚。 她就那樣靜靜地躺著,像睡著了一般诅福。 火紅的嫁衣襯著肌膚如雪匾委。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天氓润,我揣著相機(jī)與錄音赂乐,去河邊找鬼。 笑死咖气,一個(gè)胖子當(dāng)著我的面吹牛挨措,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播崩溪,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浅役,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了伶唯?” 一聲冷哼從身側(cè)響起觉既,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后瞪讼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體岭参,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年尝艘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姿染。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡背亥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悬赏,到底是詐尸還是另有隱情狡汉,我是刑警寧澤,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布闽颇,位于F島的核電站盾戴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏兵多。R本人自食惡果不足惜尖啡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剩膘。 院中可真熱鬧衅斩,春花似錦、人聲如沸怠褐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奈懒。三九已至奠涌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間磷杏,已是汗流浹背溜畅。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茴丰,地道東北人达皿。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像贿肩,于是被迫代替她去往敵國(guó)和親峦椰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容