참고자료 ) https://www.androidauthority.com/using-coordinatorlayout-android-apps-703720/
coordinatorlayout을 이용해서 구현가능한 작업 예시
1. Intro
A CoordinatorLayout
is this thing:
public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent {
...
}
from the support library ( compile 'com.android.support:design:25.3.1'
), which seems at first like an innocent old FrameLayout
, until you discover its real powers – Behavior
s!
CoordinatorLayout는 기본적으로 FrameLayout이다.
A Behavior
is an object attached to a child of a CoordinatorLayout
, which defines its interaction with another View
, ( a dependency) within the same layout.
CoordinatorLayout 아래에 있는 한 element가 다른 View(dependency라고 불리는) 의 변화에 따라 어떻게 변화할것인지를 정의하고 있는 object가 Behavior 이다. 상태변화가 관찰되어지는 View를 dependency라고 한다.
So, a CoordinatorLayout
monitors every movement of its children, and notifies the ones with attached Behavior
s for a dependency change.
Something like this:
The SnackBar
here is called a dependency – which makes sense, because the child depends on its movement in order to behave in a certain way specified by its attached Behavior
.
Following Material Design guidelines, this behavior is the correct interaction between a SnackBar
and a FloatingActionButton
.
2. Let’s get started!
Everything should run in a context or under the supervision of a CoordinatorLayout
, so let’s create a fresh Activity with a CoordinatorLayout
as its content-view root element.
Create a new project, and add a new Activity by selecting the “Basic Activity” template:
Take a look at activity_main.xml, it should contain the following:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.rany.albeg.wein.behaviors.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
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:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
Since the default behavior of FloatingActionButton
is to run away from the SnackBar
like we wish to implement ourselves, take it off of the XML tree and insert something like an AppCompatButton
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout>
...
<android.support.v7.widget.AppCompatButton
android:id="@+id/bt_click_me"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:text="Click me"/>
</android.support.design.widget.CoordinatorLayout>
Edit MainActivity
accordingly, and modify onCreate()
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
AppCompatButton btn = (AppCompatButton) findViewById(R.id.bt_click_me);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Yeah buddy!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
3. Implementation
To create a Behavior
we’ll need to create a class that extends CoordinatorLayout.Behavior<V>
where V
is a type of a class which extends View
and represents the type of the child – in our case it’ll be AppCompatButton
:
public class CustomMoveUpBehavior extends
CoordinatorLayout.Behavior<AppCompatButton> {
...
}
We’re almost done! To complete programming our custom behavior and define the unique interaction between a child and a dependency, we’ll need to:
- Override
layoutDependsOn(...)
This method gets called ( at least once in response to a layout request ) by the parent CoordinatorLayout
to determine whether the supplied child view has another specific sibling view as a layout dependency.
In other words, CoordinatorLayout
sees the SnackBar
and asks us :
“Hey, is this AppCompatButton depends on this SnackBar ?” and we should answer “Yes!” in order to further react in accordance to SnackBar
’s movement:
@Override
public boolean layoutDependsOn(CoordinatorLayout parent,
AppCompatButton child,
View dependency) {
return dependency instanceof Snackbar.SnackbarLayout;
}
위의 코드를 설명하면 CoordinatorLayout내의 element 상태가 변화하면 CoordinatorLayout는 layoutDependsOn()를 통하여 View obj인 dependency가 Snackbar.SnackbarLayout instance인지 확인한다. 맞으면 true를 return한다. CoordinatorLayout는 자신의 모든 child element를 이 함수layoutDependsOn()에 넣어 해당 View가 dependency가 맞는지 아닌지 확인한다. 사실 layoutDependsOn()는 상태 변화에도 호출되지만 최초로 화면이 구성될때도 호출된다.
- Override
onDependentViewChanged(...)
This method gets called by the parent CoordinatorLayout
after the relevant layoutDependsOn(...)
returns true
, in which we need to actually move stuff!
In our case, for the button to run away from the SnackBar
, we’ll want to translate its Y position to be the difference between SnackBar
’s current Y translation and its height!
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent,
AppCompatButton child,
View dependency) {
float tY = dependency.getTranslationY() - dependency.getHeight();
child.setTranslationY(tY);
return true;
}
위위의 코드 layoutDependsOn 의 과정을 거쳐 dependency의 변화가 관측되었다면 onDependentViewChanged()에 전달된 상태변화가 감지된 dependency와 그에 따라 조정이 필요한 child view를 함수내에서 조정한다.
We return true
to say: “Hey CoordinatorLayout! Our Behavior changed AppCompatButton’s position”
CustomMoveUpBehavior
is done and ready to be attached!
There are several ways to attach a Behavior
to View
, and I’ll choose to go with the common way – via XML.
In order to attach CustomMoveUpBehavior
to AppCompatButton
via XML, add the following constructor first:
public CustomMoveUpBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
and now jump into activity_main.xml
and just add the following attribute to AppCompatButton
’s XML tag:
<android.support.v7.widget.AppCompatButton
...
app:layout_behavior="your.package.name.CustomMoveUpBehavior"
...
/>
replacing your.package.name as necessary.