安卓协调器布局

到目前为止,我们已经在很多教程中使用了Android协调员布局。然而,我们还没有深入到它的细节。在本教程中,我们将讨论并定制Android应用程序中的协调员布局。

Android# CoordinatorLayout

Android CoordinatorLayout是一个超级强大的[FrameLayout](/community/tutorials/android-framelayout-absolutelayout-example-tutorial)。它能提供的比看起来要多得多。它对子视图有额外的控制级别。它协调子视图的动画和过渡。让我们创建一个新的Android Studio项目,并选择默认具有)组成。点击它会显示一个[SnackBar](/community/tutorials/android-snackbar-example-tutorial),如下所示。android coordinatorlayout default behavior您是否注意到,浮动操作按钮会向上移动,为SnackBar让路,并在SnackBar消失时返回?这不是魔法这是CoordinatorLayout中浮动操作按钮的行为方式。备注 :CoordinatorLayout还可以扩展工具栏以显示更多内容,或者在滚动时将其折叠,这在您滚动WhatsApp用户的个人资料屏幕时很常见。别担心,我们将在后面的教程中研究这个问题。一个问题会突然出现在我们的脑海中--CoordinatorLayout如何知道如何处理子视图?答案就在下一节。

协调员布局行为

协调员布局中的FAB已被指定为默认的行为 ,当另一个视图与其交互时,它会相应地产生动画效果。在布局/活动中按Ctrl/CMD+单击FloatingActionButton,您将看到已在类上定义了一个带有注释的** 行为** 。它应该如下所示:

1@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)

FloatingActionButton.Behavior 是FAB上使用的默认** 行为** 类。我们可以通过扩展类** OrganatorLayout.Behavior** 来定义我们自己的** 行为** 。这里的T是我们希望定义其** 行为** 的类。在上面的例子中,它是** 协调员布局.Behavior** 。

行为 仅作用于协调员Layout的直接子对象。

  • 协调员布局有必要成为活动的根布局

现在让我们在屏幕底部添加一个Button小部件。activity_main.xml

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    xmlns:tools="https://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    android:fitsSystemWindows="true"
 8    tools:context="com.journaldev.coordinatorlayoutbehaviours.MainActivity">
 9
10    <android.support.design.widget.AppBarLayout
11        android:layout_width="match_parent"
12        android:layout_height="wrap_content"
13        android:theme="@style/AppTheme.AppBarOverlay">
14
15        <android.support.v7.widget.Toolbar
16            android:id="@+id/toolbar"
17            android:layout_width="match_parent"
18            android:layout_height="?attr/actionBarSize"
19            android:background="?attr/colorPrimary"
20            app:popupTheme="@style/AppTheme.PopupOverlay" />
21
22    </android.support.design.widget.AppBarLayout>
23
24    <include layout="@layout/content_main" />
25
26    <!--<android.support.design.widget.FloatingActionButton
27        android:id="@+id/fab"
28        android:layout_width="wrap_content"
29        android:layout_height="wrap_content"
30        android:layout_gravity="bottom|end"
31        android:layout_margin="@dimen/fab_margin"
32        android:src="@android:drawable/ic_dialog_email" />-->
33
34    <android.support.v7.widget.AppCompatButton
35        android:layout_height="wrap_content"
36        android:layout_gravity="bottom|start"
37        android:text="CLICK ME"
38        android:id="@+id/button"
39        android:layout_margin="@dimen/fab_margin"
40        android:layout_width="match_parent"/>
41
42</android.support.design.widget.CoordinatorLayout>

我们已经从上面的布局中注释掉了FAB。现在将MainActivity.Java 中的FloatingActionButton监听器替换为AppCompatButton,如下所示。

1AppCompatButton fab = (AppCompatButton) findViewById(R.id.button);
2        fab.setOnClickListener(new View.OnClickListener() {
3            @Override
4            public void onClick(View view) {
5                Snackbar.make(view, "Hey Button. Define a Custom Behaviour. Else I'll take your space", Snackbar.LENGTH_LONG)
6                        .setAction("Action", null).show();
7            }
8        });

这就是应用程序现在的样子。有什么猜测吗?安卓协调器布局按钮默认behaviour要定义自定义行为,我们需要注意两个重要元素:

child :执行* 行为 ** 的视图。 dependency :视图将触发子对象的* 行为 **

在上面的例子中,AppCompatButton是子对象,Snackbar是依赖项。注意 :对于FloatingActionButton的默认** 行为** ,依赖关系不仅仅是Snackbar。还有其他在FloatingActionButton上触发** 行为** 的View元素。让我们首先创建我们自己的自定义** Behavior** 类,它向上移动AppCompatButton。我们将其命名为** CustomMoveUpBehavior.Java** 。

1public class CustomMoveUpBehavior extends CoordinatorLayout.Behavior {
2
3  public CustomMoveUpBehavior(Context context, AttributeSet attrs) {
4      super(context, attrs);
5  }
6
7}

在上述类中需要重写的两个必备方法是layoutDependsOn 和** onDependentViewChanged** 。让我们在我们的类中添加覆盖它们。

 1package com.journaldev.coordinatorlayoutbehaviours;
 2
 3import android.os.Build;
 4import android.support.design.widget.CoordinatorLayout;
 5import android.support.design.widget.Snackbar;
 6import android.view.View;
 7
 8public class CustomMoveUpBehavior extends CoordinatorLayout.Behavior {
 9
10    @Override
11    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
12        return dependency instanceof Snackbar.SnackbarLayout;
13    }
14
15    @Override
16    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
17        float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
18        child.setTranslationY(translationY);
19        return true;
20    }
21
22}

layoutDependsOn 检查触发行为的依赖项是否是实例Snackbar。** onDependentViewChanged** 用于基于基本的数学计算上移子视图(AppCompatButton)。

将该行为附加到Android协调员Layout

为了附加CustomMoveUpBehavior.java ,我们将创建一个Custom AppCompatButton并添加注释,如下所示。

 1package com.journaldev.coordinatorlayoutbehaviours;
 2
 3import android.content.Context;
 4import android.support.design.widget.CoordinatorLayout;
 5import android.support.v7.widget.AppCompatButton;
 6import android.util.AttributeSet;
 7
 8@CoordinatorLayout.DefaultBehavior(CustomMoveUpBehavior.class)
 9public class CustomButton extends AppCompatButton {
10    public CustomButton(Context context) {
11        super(context);
12    }
13
14    public CustomButton(Context context, AttributeSet attrs) {
15        super(context, attrs);
16    }
17
18    public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
19        super(context, attrs, defStyleAttr);
20    }
21}

activity_main.xml 和** MainActivity.java** 中执行以下更改:将AppCompatButton xml标记替换为以下标记。

1<com.journaldev.coordinatorlayoutbehaviours.CustomButton
2        android:layout_height="wrap_content"
3        android:layout_gravity="bottom|start"
4        android:text="CLICK ME"
5        android:id="@+id/button"
6        android:layout_margin="@dimen/fab_margin"
7        android:layout_width="match_parent"/>

替换MainActivity.Java中各自的ButtononClickListener

1CustomButton fab = (CustomButton) findViewById(R.id.button);
2        fab.setOnClickListener(new View.OnClickListener() {
3            @Override
4            public void onClick(View view) {
5                Snackbar.make(view, "Hey Button. Define a Custom Behaviour. Else I'll take your space", Snackbar.LENGTH_LONG)
6                        .setAction("Action", null).show();
7            }
8        });

现在运行的应用程序应该是这样的:Android coordinatorlayout不是很酷吗?现在,让我们尝试实现FAB的自定义行为。当Snackbar显示时,我们将触发它旋转和向上移动。我们实现了一个CustomRotateBehavior.Java类。下面给出了它。

 1public class CustomRotateBehavior extends CoordinatorLayout.Behavior {
 2
 3  public CustomRotateBehavior(Context context, AttributeSet attrs) {
 4      super(context, attrs);
 5  }
 6
 7@Override
 8    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
 9        return dependency instanceof Snackbar.SnackbarLayout;
10    }
11
12    @Override
13    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
14        float translationY = getFabTranslationYForSnackbar(parent, child);
15        float percentComplete = -translationY / dependency.getHeight();
16        child.setRotation(180 * percentComplete);
17        child.setTranslationY(translationY);
18        return false;
19    }
20
21    private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
22                                                FloatingActionButton fab) {
23        float minOffset = 0;
24        final List dependencies = parent.getDependencies(fab);
25        for (int i = 0, z = dependencies.size(); i < z; i++) {
26            final View view = dependencies.get(i);
27            if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) {
28                minOffset = Math.min(minOffset,
29                        ViewCompat.getTranslationY(view) - view.getHeight());
30            }
31        }
32
33        return minOffset;
34    }
35
36}

方法`getFabTranslationYForSnackbar(父项,子项)‘计算Snackbar应该出现在屏幕上多远的位置,以便Fab开始更改。在进行相关更改之前,让我们先浏览一下我们的项目结构。

Android协调员布局示例项目结构

安卓协调员布局example

Android CoordinatorLayout示例代码

现在,我们只需在FloatingActionButton视图中定义app:Layout_Behavior 并将其指向我们的子类,而不是扩展FloatingActionButton。这就是我们的** active_main.xml** 现在的样子。

 1<?xml version="1.0" encoding="utf-8"?>
 2<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
 3    xmlns:app="https://schemas.android.com/apk/res-auto"
 4    xmlns:tools="https://schemas.android.com/tools"
 5    android:layout_width="match_parent"
 6    android:layout_height="match_parent"
 7    android:fitsSystemWindows="true"
 8    tools:context="com.journaldev.coordinatorlayoutbehaviours.MainActivity">
 9
10    <android.support.design.widget.AppBarLayout
11        android:layout_width="match_parent"
12        android:layout_height="wrap_content"
13        android:theme="@style/AppTheme.AppBarOverlay">
14
15        <android.support.v7.widget.Toolbar
16            android:id="@+id/toolbar"
17            android:layout_width="match_parent"
18            android:layout_height="?attr/actionBarSize"
19            android:background="?attr/colorPrimary"
20            app:popupTheme="@style/AppTheme.PopupOverlay" />
21
22    </android.support.design.widget.AppBarLayout>
23
24    <include layout="@layout/content_main" />
25
26    <android.support.design.widget.FloatingActionButton
27        android:id="@+id/fab"
28        android:layout_width="wrap_content"
29        android:layout_height="wrap_content"
30        android:layout_gravity="bottom|end"
31        android:layout_margin="@dimen/fab_margin"
32        app:layout_behavior="com.journaldev.coordinatorlayoutbehaviours.CustomRotateBehavior"
33        android:src="@android:drawable/arrow_down_float" />
34
35    <!--<com.journaldev.coordinatorlayoutbehaviours.CustomButton
36        android:layout_height="wrap_content"
37        android:layout_gravity="bottom|start"
38        android:text="CLICK ME"
39        android:id="@+id/button"
40        android:layout_margin="@dimen/fab_margin"
41        android:layout_width="match_parent"/>-->
42
43</android.support.design.widget.CoordinatorLayout>

MainActivity.java 现在如下所示。

 1package com.journaldev.coordinatorlayoutbehaviours;
 2
 3import android.os.Bundle;
 4import android.support.design.widget.FloatingActionButton;
 5import android.support.design.widget.Snackbar;
 6import android.support.v7.app.AppCompatActivity;
 7import android.support.v7.widget.AppCompatButton;
 8import android.support.v7.widget.Toolbar;
 9import android.view.View;
10import android.view.Menu;
11import android.view.MenuItem;
12
13public class MainActivity extends AppCompatActivity {
14
15    @Override
16    protected void onCreate(Bundle savedInstanceState) {
17        super.onCreate(savedInstanceState);
18        setContentView(R.layout.activity_main);
19        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
20        setSupportActionBar(toolbar);
21
22        /*CustomButton fab = (CustomButton) findViewById(R.id.button);
23        fab.setOnClickListener(new View.OnClickListener() {
24            @Override
25            public void onClick(View view) {
26                Snackbar.make(view, "You've added the CustomMoveUpBehavior. Now I'll let you move", Snackbar.LENGTH_LONG)
27                        .setAction("Action", null).show();
28            }
29        });*/
30
31        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
32        fab.setOnClickListener(new View.OnClickListener() {
33            @Override
34            public void onClick(View view) {
35                Snackbar.make(view, "Hey FAB. Please Rotate 180 degrees when I'm up.", Snackbar.LENGTH_LONG)
36                        .setAction("Action", null).show();
37            }
38        });
39    }
40
41    @Override
42    public boolean onCreateOptionsMenu(Menu menu) {
43        // Inflate the menu; this adds items to the action bar if it is present.
44        getMenuInflater().inflate(R.menu.menu_main, menu);
45        return true;
46    }
47
48    @Override
49    public boolean onOptionsItemSelected(MenuItem item) {
50        // Handle action bar item clicks here. The action bar will
51        // automatically handle clicks on the Home/Up button, so long
52        // as you specify a parent activity in AndroidManifest.xml.
53        int id = item.getItemId();
54
55        //noinspection SimplifiableIfStatement
56        if (id == R.id.action_settings) {
57            return true;
58        }
59
60        return super.onOptionsItemSelected(item);
61    }
62}

让我们最后一次运行我们的应用程序,看看新的行为安卓协调员布局example这结束了安卓协调员布局的例子。我们从浏览Fab小部件的默认行为开始,最后用我们自己的旋转行为覆盖了它。也不要错过按钮上的行为。这是一个很长的路。您可以通过下面的链接下载** Android协调员布局行为项目** 。

下载Android协调员布局示例Project

参考资料:官方Doc

Published At
Categories with 技术
Tagged with
comments powered by Disqus