Android-CoordinatorLayout.……

[Android]CoordinatorLayout简介(二)几

2020-12-16  本文已影响0人  dafasoft

参考资料

CoordinatorLayout简介(一)CoordinatorLayout的简单使用

Behavior的基类是CoordinatorLayout#Behavior,先看一下类继承关系:


image.png

可以看出,系统默认实现的Behavior大致分类六类:

我们逐个分析

SwipeDismissBehavor

看先文档简介:

An interaction behavior plugin for child views of CoordinatorLayout to provide support for the 'swipe-to-dismiss' gesture.

翻译:一个为CoordinatorLayout的子View提供"滑动消失"支持的交互插件

OK 那我们大概就知道它的作用了

看下使用方式:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context="com.dafasoft.MainActivity">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_behavior="com.google.android.material.behavior.SwipeDismissBehavior">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="230dp"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                android:scaleType="fitXY"
                android:src="@drawable/yellow_zero"/>

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:background="?attr/colorPrimary"
                app:tabIndicatorColor="@color/teal_700"
                app:tabIndicatorHeight="4dp"
                app:tabSelectedTextColor="#000"
                app:tabTextColor="#fff"/>
        </com.google.android.material.appbar.AppBarLayout>

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>

然后运行代码 啪一下闪退了,很快啊!

发生甚么事了? 怎么回事?

看下CoordinatorLayout#parseBehavior的部分代码,这个方法的作用是根据我们在xml中设置的layout_behavior来解析成真正的Behavior对象,我们看下其中的部分逻辑:

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) {
                final Class<Behavior> clazz =
                        (Class<Behavior>) Class.forName(fullName, false, 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);
        }

我们获取Constructor的时候,是获取的一个带参数的Constructor方法,CONSTRUCTOR_PARAMS的值分别是Context和AttributeSet

因此,假如我们要使用SwipeDismissBehavor,需要自定义一下:

public class TestSwipeDismissBehavior extends SwipeDismissBehavior {
    public TestSwipeDismissBehavior(Context context, AttributeSet attributes) {
        super();
    }
}

然后将app:layout_behavior="com.google.android.material.behavior.SwipeDismissBehavior"这一行改为
app:layout_behavior=".behavior.TestSwipeDismissBehavior"

看下效果:


SwipeDismissBehavior1[00_00_03--00_00_23].gif

官方为我们提供的SwipeDismissBehavior的实现类,有且只有一个BaseTransientBottomBar#Behavior, 它的使用是在SnackBar中

什么是SnackBar

Snackbar显示在所有屏幕其它元素之上(屏幕最顶层),同一时间只能显示一个snackbar。

Snackbar的基本使用很简单,与Toast类似。

Snackbar.make(view, message_text, duration)
   .setAction(action_text, click_listener)
   .show();

make()方法是生成Snackbar的。Snackbar需要一个控件容器view用来容纳,官方推荐使用CoordinatorLayout来确保Snackbar和其他组件的交互,比如滑动取消Snackbar、Snackbar出现时FloatingActionButton上移。显示时间duration有三种类型LENGTH_SHORT、LENGTH_LONG和LENGTH_INDEFINITE。

setAction()方法可设置Snackbar右侧按钮,增加进行交互事件。如果不使用setAction()则只显示左侧message。

Snackbar.make(coordinatorLayout,"这是massage", Snackbar.LENGTH_LONG).setAction("这是action", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this,"你点击了action",Toast.LENGTH_SHORT).show();
     }
 }).show();

效果:


SnackBar[00_00_01--00_00_08].gif

ExpandableBehavior

看下官方文档


image.png

过期了...使用MaterialContainerTransform替代了

pass吧...

FloatingActionButton#Behavior

这个Behavior官方是给FloatingActionButton特供的

我们看一下FloatingActionButton吧

FloatingActionButton是5.0版本出现的控件,显示一个圆形悬浮按钮。需要添加Design依赖库(现在已迁移至Androidx中)并且使用Theme.AppCompat主题

FloatingActionButton配置
属性 说明
android:src 显示的图标,最好是24dp的
app:backgroundTint 正常的背景颜色
app:rippleColor 按下时的背景颜色
app:elevation 正常的阴影大小(默认6dp)
app:pressedTranslationZ 按下时的阴影大小(默认12dp)
app:borderWidth 边框宽度
app:layout_anchor 设置FAB的锚点,即以哪个控件为参照设置位置
app:layout_anchorGravity FAB相对于锚点的位置
app:fabSize normal或mini(对应56dp和40dp)

布局:

<com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/floatingActionButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right|bottom"
            android:layout_margin="20dp"
            app:rippleColor="#ffe5e5e5"
            app:backgroundTint="@color/black"
            app:elevation="6dp"
            app:pressedTranslationZ="6dp"
            app:fabSize="mini"
            app:borderWidth="0dp"
            android:src="@drawable/ic_dragon_avatar_9"/>

效果如下


微信图片_20201216120006.jpg
与SnackBar的联动效果:

FloatingActionButton天然支持与SnackBar的联动,我们只需要将FloatingActionButton设置为CoordinatorLayout的子View,在展示SnackBar时,SnackBar#make方法的View参数传入CoordinatorLayout的对象即可

Snackbar.make(coordinatorLayout,"这是massage", Snackbar.LENGTH_LONG).setAction("这是action", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(MainActivity.this,"你点击了action",Toast.LENGTH_SHORT).show();
     }
 }).show();

效果图:

SnackBar_FloatingActionButton[00_00_02--00_00_22].gif

通过继承FloatingActionButton#Behavior还可以实现其他各种各样的联动效果

继承自ViewOffsetBehavior

这一部分Behavior是我们在日常开发中使用频次最高的
其中两个最重要的Behavior:

当我们需要实现滚动控件和AppBarLayout的折叠、悬浮等效果时,滚动控件必须制定Behavior为ViewOffsetBehavior或其子类,否则是不会有协同滑动的效果的

AppBarLayout#Behavior是AppBarLayout中各种炫酷效果的基石,AppBarLayout#Behavior负责收取和处理从CoordinatorLayout传来的滑动或者嵌套滑动事件,并根据这些事件对AppBarLayout的子控件和其自身进行变换

有同学会说我们在xml中定义AppBarLayout时并没有指定Behavior啊,是的,如果我们没有手动指定,系统会默认指定AppBarLayout的Behavior为AppBarLayout#Behavior,这是通过AppBarLayout的类注解实现的:

@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
public class AppBarLayout extends LinearLayout {

    static final int PENDING_ACTION_NONE = 0x0;
    static final int PENDING_ACTION_EXPANDED = 0x1;
    static final int PENDING_ACTION_COLLAPSED = 0x2;
    static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
    static final int PENDING_ACTION_FORCE = 0x8;
      ...

这两种Behavior的代码较为复杂且江湖地位显赫,本篇不作过多介绍,在接下来我们分析CoordinatorLayout源码时会着重讲解

BottomSheetBehavior

BottonSheetBehavior用来实现从底部滑出的抽屉效果,我们经常可以在音乐播放APP和地图APP中见到这种效果
BottomSheetBehavior支持的属性:

属性 含义
behavior_peekHeight 当控件隐藏时折叠的高度
behavior_hideable 是否可以隐藏
app:behavior_skipCollapsed 是否跳过折叠状态

使用方式;
xml的定义:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout
            android:id="@+id/bottomSheetLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
            app:behavior_peekHeight="50dp"
            app:behavior_hideable="true">
            <androidx.constraintlayout.utils.widget.ImageFilterView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="fitXY"
                android:src="@drawable/yellow_zero_two"/>

        </LinearLayout>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

    <Button
        android:id="@+id/clickBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击"/>
</RelativeLayout>

Activity:

public class BottomSheetBehaviorActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bottom_sheet_behavior);
        findViewById(R.id.clickBtn).setOnClickListener(v -> {
            LinearLayout bottomSheetLayout = findViewById(R.id.bottomSheetLayout);
            BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
            bottomSheetBehavior.setState(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED ? BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_COLLAPSED);
        });

        findViewById(R.id.floatingActionButton).setOnClickListener(v -> {
            LinearLayout bottomSheetLayout = findViewById(R.id.bottomSheetLayout);
            BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
            bottomSheetBehavior.setState(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED ? BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_COLLAPSED);
        });
    }
}

效果图:


BottomSheetBehavior[00_00_04--00_00_24].gif

上一篇下一篇

猜你喜欢

热点阅读