Android开发 之 (协调布局)CoordinatorLayout与(依赖行为)Behavior

本文探讨Android开发中的关键组件CoordinatorLayout及其Behavior特性,揭示如何利用它们实现高级界面交互和AppBarLayout的联动效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CoordinatorLayout与Behavior

翻译过来就是协调布局和依赖行为,这两个是内部类关系

在我这里有两种用途:看效果


第一种,两个空间的y坐标形成依赖关系,坐标依赖



第二种,滑动以来关系

上代码:
第一种:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.example.zxq.bsquxian.views.ScrPositionTextView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="#FF0"
        android:background="#000"
        android:text="main"/>
    <Button
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:text="BUTTOn"
        app:layout_behavior="com.example.zxq.bsquxian.views.MyBehavior"
        >
    </Button>

</android.support.design.widget.CoordinatorLayout>
当然了这种效果是基于协调布局开发的,所以布局必须使用协调布局
代码中button添加一个属性layout_behavior就是建立以来关系的属性,MyBehavior这个类是自定义的,这里属性值:自定义的类的包名+类名。

自定义的MyBehavior类:
package com.example.zxq.bsquxian.views;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;

/**
 * Created by Administrator on 2017/7/25 0025.
 */

public class MyBehavior extends CoordinatorLayout.Behavior<Button> {
    public MyBehavior(Context context, AttributeSet attrs)
    {
        super(context,attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, Button child, View dependency) {
        //如果dependency 是 ScrPositionTextView, 就依赖
        return dependency instanceof ScrPositionTextView;
    }

    //每次dependency位置发生变化,都会执行onDependentViewChanged方法
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, Button btn, View dependency) {

        //根据dependency的位置,设置Button的位置
        int x = 0;
        int y = (int) dependency.getY();
        setPosition(btn, 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);
    }
}
在上面的layoutDependsOn方法中判断依赖对象,要依赖到哪个组件上。这里依赖了一个自定义TextView,当然这里也可以通过id判断依赖关系

自定义的TextView:
package com.example.zxq.bsquxian.views;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;

/**
 * Created by Administrator on 2017/7/25 0025.
 */

public class ScrPositionTextView extends android.support.v7.widget.AppCompatTextView {
    private int startx;
    private int starty;
    public ScrPositionTextView(Context context) {
        super(context);
    }

    public ScrPositionTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrPositionTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                startx= (int) event.getRawX();
                starty= (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int lastX= (int) event.getRawX();
                int lastY= (int) event.getRawY();
                int movex= lastX-startx;
                int movey= lastY-starty;
                startx= lastX;
                starty= lastY;
                CoordinatorLayout.MarginLayoutParams layoutParams= (CoordinatorLayout.MarginLayoutParams) getLayoutParams();
                int left = layoutParams.leftMargin+movex;
                int top = layoutParams.topMargin+movey;
                layoutParams.leftMargin=left;
                layoutParams.topMargin=top;
                setLayoutParams(layoutParams);
                requestFocus();
                break;
        }
        return true;
    }
}
这里动态改变textview的位置就ok,自己的y坐标会自动关联到那个button上去的。



第二种代码:
Behavior最大的用处在于对滑动事件的处理。就像CollapsingToolbarLayout的那个酷炫效果一样。
自定义的Behavior:这里需要重写以下几个方法

package com.example.zxq.bsquxian.views;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by Administrator on 2017/7/27 0027.
 */

public class ScrollBehavior extends CoordinatorLayout.Behavior {
    int offsetTotal = 0;
    boolean scrolling = false;

    public ScrollBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return true;//这里返回true,才会接受到后续滑动事件。
    }

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        //进行滑动事件处理
        offset(child,dyConsumed);
    }

    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
        //当进行快速滑动
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
        return super.onInterceptTouchEvent(parent, child, ev);
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
        return super.onTouchEvent(parent, child, ev);
    }

    public void offset(View child,int dy){
        int old = offsetTotal;
        int top = offsetTotal - dy;
        top = Math.max(top, -child.getHeight());
        top = Math.min(top, 0);
        offsetTotal = top;
        if (old == offsetTotal){
            scrolling = false;
            return;
        }
        int delta = offsetTotal-old;
        child.offsetTopAndBottom(delta);
        scrolling = true;
    }

}

布局文件;
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/second"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/textView"
                style="@style/TextAppearance.AppCompat.Display3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="128dp"
                android:background="@android:color/holo_red_light"
                android:text="A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ" />
        </LinearLayout>
    </android.support.v4.widget.NestedScrollView>

    <ImageView
        android:id="@+id/first"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        app:layout_behavior="com.example.zxq.bsquxian.views.ScrollBehavior"
        android:background="@mipmap/meinv"/>

</android.support.design.widget.CoordinatorLayout>

注意被依赖的View只有实现了NestedScrollingChild接口的才可以将事件传递给CoordinatorLayout。
但注意这个滑动事件是对于CoordinatorLayout的。所以只要CoordinatorLayout有NestedScrollingChild就会滑动,他滑动就会触发这几个回调。无论你是否依赖了那个View。
Imageview设置关联属性

有关自己的事件处理可以在这2个回调与View中的事件分发是一样的。所有Behavior能在子View之前收到CoordinatorLayout的所有触摸事件。可以进行拦截,如果拦截事件将不会流经子View。因为这2个方法都是在CoordinatorLayout的 回调中

其实之前讲的AppBarLayout效果也是这个原理:
AppBarLayout自带一个Behivior。直接在源码里注解声明的。这个Behivior也只能用于AppBarLayout。
作用是让他根据CoordinatorLayout上的滚动手势进行一些效果(比如收缩)。与ScrollingViewBehavior是无关的,加不加ScrollingViewBehavior不影响收缩。
只不过只有某些可滑动View才会把滑动事件响应给CoordinatorLayout才能继而响应给AppBarLayout。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值