Поиск по сайту:

Координатор AndroidМакет


До сих пор мы использовали Android CoordinatorLayout во многих наших руководствах. Но мы не вдавались в подробности. В этом уроке мы обсудим и настроим CoordinatorLayout в приложении для Android.

Координатор AndroidМакет

Поведение CoordinatorLayout

Для FAB в CoordinatorLayout было указано поведение по умолчанию, которое заставляет его анимироваться соответствующим образом, когда с ним взаимодействует другое представление. Сделайте Ctrl/CMD+ Щелкните FloatingActionButton в макете/действии, и вы увидите, что Behavior был определен в классе с аннотацией. Это должно выглядеть так:

@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)

FloatingActionButton.Behavior — это класс поведения по умолчанию, используемый в FAB. Мы можем определить наши собственные поведения, расширив класс CoordinatorLayout.Behavior. Здесь T — класс, поведение которого мы хотим определить. В приведенном выше случае это CoordinatorLayout.Behavior.

  • Поведение работает только с прямым дочерним элементом CoordinatorLayout.
  • Необходимо, чтобы CoordinatorLayout был корневым макетом действия.

Теперь давайте добавим виджет Button внизу нашего экрана. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.journaldev.coordinatorlayoutbehaviours.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <include layout="@layout/content_main" />

    <!--<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />-->

    <android.support.v7.widget.AppCompatButton
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|start"
        android:text="CLICK ME"
        android:id="@+id/button"
        android:layout_margin="@dimen/fab_margin"
        android:layout_width="match_parent"/>

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

Мы закомментировали FAB из приведенного выше макета. Теперь замените прослушиватель FloatingActionButton на AppCompatButton в MainActivity.java, как показано ниже.

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

  • дочерний элемент: это представление, в котором будет выполняться действие.
  • зависимость: это представление, которое вызывает поведение дочернего элемента.

В приведенном выше случае AppCompatButton является дочерним элементом, а SnackBar — зависимостью. Примечание. Для поведения по умолчанию FloatingActionButton зависимость — это не только SnackBar. Есть и другие элементы View, которые запускают поведение FloatingActionButton. Давайте начнем с создания нашего собственного класса Behavior, который перемещает вверх AppCompatButton. Назовем его CustomMoveUpBehavior.java.

public class CustomMoveUpBehavior extends CoordinatorLayout.Behavior {

  public CustomMoveUpBehavior(Context context, AttributeSet attrs) {
      super(context, attrs);
  }

}

Два необходимых метода, которые следует переопределить в приведенном выше классе, — это layoutDependsOn и onDependentViewChanged. Давайте добавим переопределить их в наш класс.

package com.journaldev.coordinatorlayoutbehaviours;

import android.os.Build;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.view.View;

public class CustomMoveUpBehavior extends CoordinatorLayout.Behavior {

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
        child.setTranslationY(translationY);
        return true;
    }

}

layoutDependsOn проверяет, является ли зависимость, запускающая поведение, экземпляром SnackBar. OnDependentViewChanged используется для перемещения дочернего представления (кнопка AppCompat) на основе базового математического расчета.

Прикрепление поведения к android CoordinatorLayout

Чтобы прикрепить CustomMoveUpBehavior.java, мы создадим Custom AppCompatButton и добавим аннотации, как показано ниже.

package com.journaldev.coordinatorlayoutbehaviours;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.AppCompatButton;
import android.util.AttributeSet;

@CoordinatorLayout.DefaultBehavior(CustomMoveUpBehavior.class)
public class CustomButton extends AppCompatButton {
    public CustomButton(Context context) {
        super(context);
    }

    public CustomButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

Внесите следующие изменения в файл activity_main.xml и MainActivity.java. Замените тег xml AppCompatButton следующим.

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

Замените соответствующую кнопку onClickListener в файле MainActivity.java.

CustomButton fab = (CustomButton) findViewById(R.id.button);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Hey Button. Define a Custom Behaviour. Else I'll take your space", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
public class CustomRotateBehavior extends CoordinatorLayout.Behavior {

  public CustomRotateBehavior(Context context, AttributeSet attrs) {
      super(context, attrs);
  }

@Override
    public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) {
        float translationY = getFabTranslationYForSnackbar(parent, child);
        float percentComplete = -translationY / dependency.getHeight();
        child.setRotation(180 * percentComplete);
        child.setTranslationY(translationY);
        return false;
    }

    private float getFabTranslationYForSnackbar(CoordinatorLayout parent,
                                                FloatingActionButton fab) {
        float minOffset = 0;
        final List dependencies = parent.getDependencies(fab);
        for (int i = 0, z = dependencies.size(); i < z; i++) {
            final View view = dependencies.get(i);
            if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(fab, view)) {
                minOffset = Math.min(minOffset,
                        ViewCompat.getTranslationY(view) - view.getHeight());
            }
        }

        return minOffset;
    }

}

Метод getFabTranslationYForSnackbar(parent,child) вычисляет, насколько далеко вверху экрана должен подняться SnackBar, чтобы FAB начал изменяться. Прежде чем мы внесем соответствующие изменения, давайте просмотрим структуру нашего проекта.

Пример структуры проекта Android CoordinatorLayout

Пример кода Android CoordinatorLayout

Теперь вместо расширения FloatingActionButton мы можем просто определить app:layout_behavior в представлении FloatingActionButton и указать его на наш подкласс. Вот как теперь выглядит наш файл activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.journaldev.coordinatorlayoutbehaviours.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:layout_behavior="com.journaldev.coordinatorlayoutbehaviours.CustomRotateBehavior"
        android:src="@android:drawable/arrow_down_float" />

    <!--<com.journaldev.coordinatorlayoutbehaviours.CustomButton
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|start"
        android:text="CLICK ME"
        android:id="@+id/button"
        android:layout_margin="@dimen/fab_margin"
        android:layout_width="match_parent"/>-->

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

MainActivity.java теперь выглядит так.

package com.journaldev.coordinatorlayoutbehaviours;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatButton;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        /*CustomButton fab = (CustomButton) findViewById(R.id.button);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "You've added the CustomMoveUpBehavior. Now I'll let you move", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });*/

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Hey FAB. Please Rotate 180 degrees when I'm up.", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Скачать пример проекта Android CoordinatorLayout

Ссылка: Официальный документ