MotionLayout 은 앱에서 모션과 위젯 애니메이션을 관리하는 데 사용할 수 있는 레이아웃 유형입니다.

MotionLayout 은 ConstraintLayout 의 서브클래스이며 ConstraintLayout 의 다양한 레이아웃 기능을 기초로합니다.

ConstraintLayout 라이브러리의 일부인 MotionLayout 은 지원 라이브러리로 사용 가능하며, API 레벨 14와 호환됩니다.

그림 1. 기본터치 컨트롤 모션입니다.

 

MotionLayout 은 레이아웃 전환과 복잡한 모션 처리를 연결하며 속성 애니메이션 프레임워크, TransitionManager 및 CoordinatorLayout 의 혼합된 기능을 제공합니다. 

 

레이아웃 사이의 전환 외에도 MotionLayout 을 통해 레이아웃 속성에 애니메이션을 적용할 수 있습니다.

한  기본적으로 검색 가능 전환(seekable transitions)을 지원합니다. 이 말은 터치 입력과 같은 어떤 조건을 기준으로 전환 내의 어떤 포인트를 즉시 보여줄 수 있다는 것을 의미합니다. 또한 MotionLayout에서는 키프레임도 지원하므로 사용자의 필요에 맞게 완전히 맞춤설정된 전환을 사용할 수 있습니다.

 

MotionLayout 은 완전히 선언적인 것으로, 복잡도에 상관없이 XML로 모든 전환을 설명할 수 있습니다.

 ☆참고 : MotionLayout은 직접 하위 요소와만 호환됩니다. 중첩 레이아웃 계층 구조 또는 액티비티 전환은 지원하지 않습니다. 

디자인 고려 사항 

MotionLayout 은 버튼 및 제목 표시줄과 같이 사용자가 상호작용하는 UI 요소를 이동, 크기 조절 및 애니메이션화하기 위한 것입니다. 앱의 모션은 단지 애플리케이션의 불필요한 특수 효과가 되어서는 안 됩니다. 사용자가 애플리케이션 기능을 이해하는 데 도움이 되어야 합니다. 모션을 사용하여 앱을 디자인하는데 관한 자세한 내용은 모션 이해의 머티리얼 디자인 섹션을 참조하세요. 

 시작하기

 프로젝트에서 MotionLayout 사용을 시작하려면 다음 단계를 따르세요.

1. ConstraintLayout 종속 항목 추가

프로젝트에서 MotionLayout 을 사용하려면 ConstraintLayout 2.0 종속 항목을 앱의 build.gradle 파일에 추가합니다.

AndroidX를 사용중이라면 다음 종속 항목을 추가하세요. 

    dependencies {
        implementation
'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
   
}   

 AndroidX를 사용하지 않으면 다음 지원 라이브러리 종속성을 추가하세요.

    dependencies {
        implementation
'com.android.support.constraint:constraint-layout:2.0.0-beta1'
   
}

2. MotionLayout 파일 만들기

MotionLayout은  ConstraintLayout 의 서브클래스이므로 다음 예에서와 같이 레이아웃 리소스 파일에서 클래스 이름을 바꿔 기존 ConstraintLayout을 MotionLayout 으로 전환할 수 있습니다.

    <!-- before: ConstraintLayout -->
   
<androidx.constraintlayout.widget.ConstraintLayout .../>
   
<!-- after: MotionLayout -->
   
<androidx.constraintlayout.motion.widget.MotionLayout .../> 

다음은 그림 1에서 모션을 생성하는 데 사용할 수 있는 MotionLayout 파일의 전체 예입니다.

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        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:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">

        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />

    </androidx.constraintlayout.motion.widget.MotionLayout>
            

3. MotionScene 만들기

이전 MotionLayout 예에서 app:layoutDescription 속성은 MotionScene 을 참조합니다.

MotionScene 은 해당 레이아웃의 모든 모션 설명을 포함하는 XML 리소스 파일입니다.

레이아웃 정보를 모션 설명과 별도로 유지하기 위해 각 MotionLayout 은 별도의 MotionScene을 참조합니다.

MotionScene의 정의는 MotionLayout 의 유사한 정의보다 우선한다는 점에 유의합니다.

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">

        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>

        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>

        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>

    </MotionScene>
        

<Transition> 에는 모션의 기본 정의가 포함되어 있습니다.

motion:constraintSetStart 및 motion:constraintSetEnd 는 모션의 엔드포인트 참조입니다. 
이러한 엔드포인트는 나중에 <MotionScene>의 <ConstraintSet> 요소에 정의됩니다.

motion:duration 은 모션이 완료되는 데 걸리는 시간을 밀리초 단위로 지정합니다.

 

<OnSwipe> 를 사용하면 터치를 통해 모션을 제어할 수 있습니다.

 motion:touchAnchorId 는 스와이프하고 드래그할 수 있는 뷰를 나타냅니다.

motion:touchAnchorSide 는 오른쪽으로 뷰를 드래그하는 것을 나타냅니다.

motion:dragDirection 은 드래그의 진행방향을 나타냅니다. 예를 들어 motion:dragDirection="dragRight" 는 오른쪽으로 드래그하면 진행률이 증가한다는 의미입니다.

 

<ConstraintSet> 를 통해서는 모션을 설명하는 다양한 제약조건을 정의합니다.

이 예에서는 모션의 엔드포인트마다 한 개씩 ConstraintSet 를 정의합니다.

이 엔드포인트는 세로로는 가운데에 위치합니다. (app:layout_constraintTop_toTopof="parent" 및 app:layout_constraintBottom_toBottomOf="parent" 사용). 가로로는 화면의 맨 왼쪽과 오른쪽에 엔드포인트가 있습니다.

 Interpolated Attributes

 MotionScene 파일에서 COnstraintSet 요소에는 전환하는 동안 추가되는 추가 속성이 포함될 수 있습니다. 위치 및 경계 이외에 다음 속성은 MotionLayout을 통해 추가됩니다.

  • alpha

  • visibility

  • rotation, rotationX, rotationY

  • translationZ, translationY, translationX

  • scaleX, scaleY

Custom attributes

<Constraint> 에서 <CustomAttribute> 요소를 사용하여 위치 또는 View 속성과 관련되지 않은 속성의 전환을 지정할 수 있습니다. 

    <Constraint
        android:id="@+id/button" ...>
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60"/>
    </Constraint>

<CustomAttribute> 에는 다음과 같은 두 가지 고유 속성이 있습니다.

  • motion:attributeName 은 필수이며 getter 및 setter 메서드가 있는 객체와 일치해야 합니다.
    getter와 setter는 특정 패턴과 일치해야 합니다. 예를 들어, Google의 View에는 기본적으로 getBackgroundColor() 및 setBackgroundColor() 메서드가 있으므로 backgroundColor 가 지원됩니다.

  • 입력해야하는 다른 속성은 값 유형을 기반으로 합니다. 지원되는 다음 유형 중에서 선택하세요.

    • motion:customColorValue - 색상
    • motion:customIntegerValue - 정수
    • motion:customFloatValue - 부동수
    • motion:custromStringValue - 문자열
    • motion:customDimension - 측정기준
    • motion:customBoolean - 부울

 맞춤 속성을 지정할 때 시작 및 종료 <ConstraintSet> 요소 모두에 엔드포인트 값을 정의해야합니다.

 예: 배경색 변경

 앞의 예를 기반으로 그림 2에 표시된 대로 보기에서 모션의 일부로 색상을 변경해 보겠습니다.

그림2. 뷰가 이동하면 배경색이 변경됩니다.

 아래와 같이 <CustomAttribute> 요소를 각 <ConstraintSet> 요소에 추가합니다.

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent">
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="#D81B60" />
        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent">
            <CustomAttribute
                motion:attributeName="backgroundColor"
                motion:customColorValue="#9999FF" />
        </Constraint>
    </ConstraintSet>
    

 추가 MotionLayout 속성

 위의 예에 있는 속성 외에도 MotionLayout 에는 다음과 같이 지정할 수 있는 다른 속성이 있습니다.

  • app:applyMotionScene="boolean" 은 MotionScene 적용 여부를 나타냅니다.
    이 속성의 기본값은 true 입니다.

  • app:showPaths="boolean" 은 모션이 실행 중일 때 모션 경로를 표시할지 나타냅니다.
    이 속성의 기본값은 false 입니다.

  • app:progress="float" 를 사용하면 전환 진행 상황을 명시적으로 지정할 수 있습니다.
    0(전환시작)부터 1(전환종료)까지 부동 소수점 값을 사용할 수 있습니다.

  • app:currentState="reference" 를 사용하면 특정 ConstraintSet 를 지정할 수 있습니다.
  • app:motionDebug 를 사용하면 모션에 관한 추가 디버그 정보를 표시할 수 있습니다.
    가능한 값은 'SHOW_PROGRESS', 'SHOW_PATH' 또는 'SHOW_ALL' 입니다.

SUMMARY

MotionLayout 은 앱에서 모션과 위젯 애니메이션을 관리하는 데 사용할 수 있는 레이아웃 유형입니다.

기본적으로 검색 가능 전환(seekable transitions)을 지원합니다. 이 말은 터치 입력과 같은 어떤 조건을 기준으로 전환 내의 어떤 포인트를 즉시 보여줄 수 있다는 것을 의미합니다. 또한 키프레임도 지원하므로 사용자의 필요에 맞게 전환을 사용할 수 있습니다.

 

MotionScene은 해당 레이아웃의 모든 모션 설명을 포함하는 XML 리소스이며, 레이아웃 정보를 모션 설명과 별도로 유지하기 위해 MotionLayout은 별도의 MotionScene을 참조합니다. MotionScene의 정의는 MotionLayout 의 유사한 정의보다 우선합니다.

 

<Transition> 에는 모션의 기본 정의가 포함되어 있습니다.

motion:constraintSetStart 및 motion:constraintSetEnd 는 모션의 엔드포인트 참조입니다. 
이러한 엔드포인트는 나중에 <MotionScene>의 <ConstraintSet> 요소에 정의됩니다.

 

<OnSwipe> 를 사용하면 터치를 통해 모션을 제어할 수 있습니다.

<ConstraintSet> 를 통해서는 모션을 설명하는 다양한 제약조건을 정의합니다.

 

<CustomAttribute> 에는 다음과 같은 두 가지 고유 속성이 있습니다.

  • motion:attributeName 은 필수이며 getter 및 setter 메서드가 있는 객체와 일치해야 합니다.
    getter와 setter는 특정 패턴과 일치해야 합니다. 

  • 입력해야하는 다른 속성은 값 유형을 기반으로 합니다. 

맞춤 속성을 지정할 때 시작 및 종료 <ConstraintSet> 요소 모두에 엔드포인트 값을 정의해야합니다.

Reference

MotionLayout : developer.android.com/training/constraint-layout/motionlayout?hl=ko#androidx

'Android > Android Developer' 카테고리의 다른 글

Layout 레이아웃  (0) 2020.12.01
ConstraintLaytout  (0) 2020.11.02

Layout

레이아웃은 앱에서 사용자 인터페이스를 위한 구조(예: 액티비티)를 정의합니다.

레이아웃의 모든 요소는 ViewViewGroup 객체의 계층을 사용하여 빌드됩니다. 

일반적으로 View는 사용자가 보고 상호작용할 수 있는 것을 그립니다. 

View Group은 그림 1과 같이 View와 ViewGroup 객체의 레이아웃 구조를 정의하는 투명 컨테이너입니다. 

 

그림 1. 레이아웃을 정의하는 뷰 계층.

일반적으로 View 객체는 '위젯' 이라고 하고 여러 하위 클래스 중 하나가 될 수 있습니다.

(예 : Button 또는 TextView)

 

ViewGroup 객체는 대개 '레이아웃' 이라고 부르고 다양한 레이아웃 구조를 제공하는 여러 유형 중 하나일 수 있습니다. (예: LinearLayout 또는 ConstraintLayout)

 

레이아웃을 정의하는 방법

  • UI 요소를 XML로 선언.

  • 런타임에 레이아웃 요소 인스턴스화.

XML에서 UI를 선언하면 동작을 제어하는 코드와 앱을 표현하는 것을 분리할 수 있습니다.

또한 XML 파일을 사용하면 다양한 화면 크기와 방향에 여러 가지 레이아웃을 쉽게 제공할 수 있습니다.

 

Android 프레임워크는 위 방법 중 하나 또는 두 가지 모두를 사용하여 앱의 UI를 빌드하는 유연한 수단을 제공합니다.

예를 들어 앱의 기본 레이아웃을 XML에서 선언한 다음, 런타임에서 레이아웃을 수정할 수 있습니다.

XML 쓰기

Android의 XML 어휘를 사용하면 UI 레이아웃과 그 안에 들어있는 화면 요소를 HTML에서 웹 페이지를 디자인할 떄와 같은 방식으로 신속하게 디자인할 수 있습니다. 

 

각 레이아웃 파일에는 반드시 딱 하나의 루트 요소만 있어야 하며, 이는 View 또는 ViewGroup 객체여야 합니다.

루트 요소를 정의한 후에 더 많은 레이아웃 객체 또는 위젯을 하위 요소로 추가하여 계층적으로 레이아웃을 정의하는 뷰 계층을 빌드할 수 있습니다. 

 

레이아웃을 XML로 선언하고 나면 그 파일을 Android 프로젝트의 res/layout/ 폴더 내에 .xml 확장자로 저장하여 적절하게 컴파일되도록 합니다.

 

레이아웃 리소스

레이아웃 리소스는 Activity의 UI 또는 UI 구성요소의 아키텍처를 정의합니다.

 

파일 위치

  • res/layout/filename.xml

  • 파일 이름이 리소스 ID로 사용됩니다.

컴파일된 리소스 데이터 유형

  • View 리소스를 가리키는 리소스 포인터입니다.

리소스 참조

  • 자바 : R.layout.filename

  • XML : @[package:]layout/filename

더보기

요소

<ViewGoup>

다른 View 요소의 컨테이너. 다양한 ViewGroup 객체가 있으며 각 객체를 사용하여 여러 방식으로 하위 요소의 레이아웃을 지정할 수 있습니다. VIewGroup 객체이는 LinearLayout, RelativeLayout, FrameLayout 등이 있습니다.

 

ViewGroup의 모든 파생 객체가 중첩된 View를 허용한다고 가정해서는 안됩니다. 일부 ViewGroup은 AdapterVIew 클래스를 구현한 것이며 이 클래스는 Adapter 하위에서만 하위 요소를 걸정합니다.

 

속성

android:id

  • 리소스 ID. 요소의 고유한 리소스 이름이며 이를 사용하여 애플리케이션에서 ViewGroup의 참조를 가져올 수 있습니다.

android:layout_height   및   android:layout_width

  • 크기 또는 키워드. 필수사항. 크기 값(또는 크기 리소스) 또는 키워드("match_parent" 또는 "wrap_content")

더 많은 속성이 ViewGroup 기본 클래스에서 지원되며 사용가능한 모든 속성의 참조는 ViewGroup 클래스의 대응하는 문서를 확인하세요.

 

<View>

일반적으로 '위젯'이라고 하는 개별 UI 구성요소입니다. VIew 객체에는 TextVIew, Button, CheckBox 등이 있습니다.

 

속성

android:id

  • 리소스 ID. 요소의 고유한 리소스 이름이며 이를 사용하여 애플리케이션에서 ViewGroup의 참조를 가져올 수 있습니다.

android:layout_height   및   android:layout_width

  • 크기 또는 키워드. 필수사항. 크기 값(또는 크기 리소스) 또는 키워드("match_parent" 또는 "wrap_content")

더 많은 속성이 View 기본 클래스에서 지원되며 사용가능한 모든 속성의 참조는 대응하는 참조 문서를 확인하세요.

 

<requestFocus>

View 객체를 나타내는 모든 요소는 빈 요소를 포함할 수 있고 이 빈 요소는 화면에서 상위 요소에 초기 포커스를 줍니다. 이러한 요소는 파일당 하나만 포함할 수 있습니다.

 

<include>

레이아웃에 레이아웃 파일을 포함합니다.

속성

layout

  • 레이아웃 리소스. 필수사항. 레이아웃 리소스를 가리키는 참조입니다.

android:id

  • 리소스 ID. 요소의 고유한 리소스 이름이며 이를 사용하여 애플리케이션에서 ViewGroup의 참조를 가져올 수 있습니다.

android:layout_height   및  android:layout_width

  • 크기 또는 키워드. 필수사항.  크기 값(또는 크기 리소스) 또는 키워드("match_parent" 또는 "wrap_content"

<include> 내에 포함된 레이아웃에서 루트요소에 의해 지원되는 다른 레이아웃 속성을 포함할 수 있고 그러한 속성은 루트 요소에 정의된 속성을 재정의합니다.

주의 : <include> 태그를 사용하여 레이아웃 속성을 재정의하면 다른 레이아웃 속성을 적용하기 위해 andorid:layout_height, andorid:layout_width를 모두 재정의해야 합니다.

 

레이아웃을 포함하는 또 다른 방법은 ViewStub을 사용하는 것입니다. ViewStub은 가벼운 View로서, 명시적으로 펼칠 때까지 레이아웃 공간을 소비하지 않으며 이 시점에 android:layout 속성에 의해 재정의된 레이아웃 파일을 포함합니다. ViewStub을 사용하는 방법에 관한 자세한 내용은 주문형 뷰 로드를 참조합니다.

 

<merge>

레이아웃 계층 구조에 그려지지 않은 대체 루트 요소입니다. 루트 요소로 이 요소를 사용하면 이 레이아웃이 이미 적절한 상위 뷰를 포함하여 <merge> 요소의 하위 요소를 포함하는 레이아웃에 배치되는 경우에 유용합니다.

<include>를 사용하여 이 레이아웃을 다른 레이아웃 파일에 포함하고 이 레이아웃이 다른 ViewGroup 컨테이너가 필요하지 않을 때에 특히 유용합니다. 레이아웃 병합에 관한 자세한 내용은 <include/>로 레이아웃 재사용을 참조하세요.

 

android:id값 

ID 값의 경우 일반적으로 "@+id/name" 구문 형식을 사용해야 합니다. 더하기 기호(+)는 새 리소스 ID를 나타내며 리소스 정수가 아직 존재하지 않는다면 aapt 도구는 R.java 클래스에 새 리소스 정수를 만듭니다.

 

android:layout_height 및 android:layout_width의 값

높이 및 너비 값은 Android에서 지원하는 모든 크기 단위(px, dp, sp, pt, in, mm) 또는 다음의 키워드를 사용하여 표현할 수 있습니다.

  • match_parent : 상위 요소의 크기와 일치하도록 크기를 설정합니다. fill_parent 지원을 중단하기 위해 API 레벨 8에서 추가 되었습니다.

  • wrap_content

XML 리소스 로드

앱을 컴파일하는 경우, 각 XML 레이아웃 파일이 View 리소스 안에 컴파일 됩니다.

Activity.onCreate() 콜백 구현에서 앱 코드로부터 레이아웃 리소스를 로드해야 합니다.

setContentView() 를 호출하고 R.layout.layout_file_name의 형태로 레이아웃 리소스에 대한 참조로 전달합니다.

예를 들어 XML 레이아웃이 main_layout.xml로 저장된다면 다음과 같이 액티비티에 대해 로드합니다.

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

 액티비티 내의 onCreate() 콜백 메서드는 액티비티가 시작될 때 Android 프레임워크에 의해 호출됩니다.

 

특성

모든 View와 ViewGroup 객체는 고유한 여러가지 XML 특성을 지원합니다.

어떤 특성은 View 객체에만 적용되지만(예: TextView는 textSize 특성 지원), 이 특성은 이 클래스를 확장할 수 있는 View 객체로부터 상속받은 것입니다. 어떤 특성은 루트 View 클래스에서 상속되기 때문에(예: id 특성) 모든 View 객체에 공통적으로 적용됩니다.

 

그리고 나머지 특성은 "레이아웃 매개변수"로 간주됩니다. 이들은 View 객체의 특정한 레이아웃 방향을 설명하는 것으로, 이는 해당 객체의 상위 ViewGroup 객체에서 정의된 바에 따릅니다.

 

ID

View 객체는 트리 내에서 뷰를 고유하게 식별할 수 있는 ID가 연결될 수 있습니다. 

앱을 컴파일할 때 이 ID는 정수로 참조되지만, 일반적으로 레이아웃 XML 파일의 id 특성에서 문자열로 할당됩니다.

이는 모든 View 객체에 공통적인 XML 특성이며(View 클래스에서 정의), 매우 자주 사용하게 될 것입니다.

 

문자열 시작 부분에 있는 앳 기호(@)는 XML 파서가 ID 문자열의 나머지를 파싱하고 확장하여 ID 리소스로 식별해야 한다는 것을 나타냅니다. 더하기 기호(+)는 이것이 새 리소스 이름이며, 이것을 반드시 생성하여 리소스에 추가해야 한다는 것을 뜻합니다. 

 

Android 리소스를 참조할 때에는 더하기 기호는 필요하지 않지만 android 패키지 네임스페이스를 다음과 같이 반드시 추가해야 합니다.

android:id="@android:id/empty"

android 패키지 네임스페이스가 들어가면 이제 로컬 리소스 클래스에서가 아니라 android.R 리소스 클래스에서 ID를 참조하게 됩니다.  

 레이아웃 매개변수

layout_something  이라는 XML 레이아웃 특성이 뷰가 상주하는 ViewGoup에 대해 적절한 뷰의 레이아웃 매개변수를 정의합니다. 

 

모든 ViewGroup 클래스가 중첩된 클래스를 하나씩 구현하며 이것이 ViewGroup.LayoutParams 를 확장합니다.

이 하위 클래스에는 각 하위 뷰의 크기와 위치를 뷰 그룹에 적절한 방식으로 정의하는 속성 유형이 들어있습니다.

그림 2에서 볼 수 있듯이, 상위 뷰 그룹이 각 하위 뷰의 레이아웃 매개변수를 정의합니다.

 

그림2. 각 뷰와 연관된 레이아웃 매개변수가 있는 뷰 계층을 시각화한 것.

모든 LayoutParams 하위 클래스에는 설정 값에 대한 각기 자신만의 구문이 있다는 점을 참고하세요.

각 하위 요소는 자신의 상위에 적합한 LayoutParams를 정의해야 합니다. 다만 이것은 자신의 하위에 대해 각기 다른 LayoutParams도 정의할 수 있습니다.

 

모든 ViewGroup에는 너비와 높이(layout_width, layout_height)가 포함되며, 각 뷰는 이들을 반드시 정의해야 합니다. 선택사항으로 여백과 테두리도 포함하는 LayoutParams도 많습니다.

 

너비와 높이는 정확한 치수로 지정할 수 있습니다. 다만 이것은 자주 하지 않는 것이 좋습니다.

그보다는 다음과 같은 상수 중 하나를 사용하여 너비 또는 높이를 설정하는 경우가 더 많습니다.

  • wrap_content는 콘텐츠에 필요한 치수대로 자동으로 크기를 조정하도록 뷰에 지시합니다.

  • match_parent는 상위 뷰 그룹이 허용하는 한 최대한으로 커지도록 뷰에 지시합니다.

 일반적으로 픽셀과 같이 절대적인 단위를 사용하여 레이아웃 너비와 높이를 지정하는 것은 권장하지 않습니다.

그 대신, 밀도 독립적인 픽셀 단위(dp), wrap_content 또는 match_parent와 같이 상대적인 측정치를 사용하는 것이 더 낫습니다. 이렇게하면 앱이 다양한 기기 화면 크기에 걸쳐서도 적절하게 표시되도록 보장하는데 도움이 되기 때문입니다.

 

레이아웃 위치

뷰의 모양은 직사각형입니다. 뷰에는 위치가 있으며, 이는 한 쌍의 왼쪽 및 상단좌표, 그리고 두 개의 치수가 너비와 높이를 나타내는 형식으로 표현됩니다. 위치와 치수의 단위는 픽셀입니다.

 

뷰의 위치를 검색할 수 있습니다. getLeft() 및 getTop() 메서드를 호출하면 됩니다.

getLeft()는 뷰를 나타내는 직사각형의 왼쪽, 즉 X좌표를 반환합니다.

getTop()은 뷰를 나타내는 직사각형의 상단, 즉 Y좌표를 반환합니다.

이들 메서드는 둘 다 해당 뷰의 상위에 상대적인 뷰의 위치를 반환합니다.

예를들어 getLeft() 가 20을 반환하는 경우 이는 해당 뷰가 그 뷰의 바로 상위의 왼쪽 가장자리에서 오른쪽으로 20픽셀 떨어진 곳에 있다는 뜻입니다.

 

그 외에도 불필요한 계산을 피하기 위해 여러가지 편의 메서드가 제공됩니다. 

getRight() 및 getBottom()을 들 수 있습니다. 이 메서드는 해당 뷰를 나타내는 직사각형의 오른쪽과 하단가장자리의 좌표를 반환합니다.

 

예를 들어 getRight()를 호출하는 것은 getLeft() + getWidth() 계산과 비슷합니다.

크기, 패딩 및 여백

뷰의 크기는 너비와 높이로 표현됩니다. 사실 하나의 뷰는 두 쌍의 너비 및 높이 값을 소유합니다.

 

첫 번째 쌍을 측정된 너비 및 측정된 높이라고 합니다. 이들 치수는 뷰가 상위 내에서 얼마나 커지고자 하는지를 정의합니다.

측정된 치수를 가져오려면 getMeasuredWidth() 및 getMeasuredHeidght() 를 호출합니다. 

 

두 번째 쌍은 단순히 너비 및 높이라고 일컬으며, 때로는 그리기 너비(drawing width) 및 그리기 높이(drawing height)로 부를 때도 있습니다. 이러한 치수는 그리는 시간과 배치 후에 뷰가 화면에 표시되는 실제 크기를 정의합니다. 이들 값은 측정된 너비및 높이와 달라도 되지만 꼭 달라야 하는 것은 아닙니다. 너비와 높이를 가져오려면 getWidth() 및 getHeight()을 호출하면 됩니다.

 

뷰의 치수를 측정하기 위해 뷰는 자신의 패딩을 감안합니다. 패딩은 뷰의 왼쪽, 상단, 오른쪽 및 하단 부분에 대해 픽셀로 표시됩니다. 패딩은 정해진 픽셀 수를 사용하여 뷰의 콘텐츠를 오프셋하는 데 쓰일 수도 있습니다. 

예를 들어 왼쪽 패딩을 2로 설정하면 해당 뷰의 콘텐츠를 왼쪽 가장자리에서 오른쪽으로 2픽셀 밀어냅니다.

패딩을 설정할 때는 setPadding(int, int, int, int) 메서드를 사용하면 되고,

이를 쿼리하려면 getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom()을 사용하면 됩니다.

 

뷰는 패딩을 정의할 수 있지만, 여백(margin)에 대한 지원은 전혀 제공하지 않습니다. 다만 뷰 그룹이 그와 같은 지원을 제공합니다.

일반 레이아웃

ViewGroup 클래스의 각 하위 클래스는 각기 고유한 방식으로 자신 안에 중첩된 뷰를 표시합니다.

아래는 Android 플랫폼에서 기본 제공되는, 보다 보편적인 레이아웃 유형을 몇 가지 나타낸 것입니다.

 하나 이상의 레이아웃을 또 다른 레이아웃에 중첩하여 UI 디자인을 이룰 수도 있지만, 레이아웃 계층을 가능한 한 얕게 유지하도록 애써야 합니다. 중첩된 레이아웃이 적을수록 레이아웃이 더욱 빠르게 그려집니다.
(가로로 넓은 뷰 계층이 깊은 뷰 계층보다 낫습니다)

LinaearLayout

여러 하위 요소를 하나의 가로 또는 세로 방향 행으로 정리하는 레이아웃.

이 레이아웃은 창의 길이가 화면 길이를 웃도는 경우 스크롤바를 생성합니다.

RelativeLayout

여러 하위 객체의 위치를 서로 상대적으로 나타내거나, 상위와 상대적으로 나타낼 수 있도록 해줍니다.

WebView

웹 페이지를 표시합니다.

 

SUMMARY

레이아웃은 앱에서 사용자 인터페이스를 위한 구조를 정의합니다.

레이아웃의 모든 요소는 View 와 ViewGroup 객체의 계층을 사용하여 빌드됩니다.

 

레이아웃을 XML로 선언할 시 동작을 제어하는 코드와 앱을 표현하는 것을 분리할 수 있습니다. 또한 XML 파일을 사용하면 다양한 화면 크기와 방향에 여러 가지 레이아웃을 쉽게 제공할 수 있습니다. 

 

View 객체는 트리 내에서 뷰를 고유하게 식별할 수 있는 ID가 연결될 수 있으며, 앱을 컴파일할 때 이 ID는 정수로 참조되지만, 일반적으로 레이아웃 XML 파일의 id 특성에서 문자열로 할당됩니다.

 

View 의 모양은 직사각형입니다. 뷰에는 위치가 있으며, 이는 한 쌍의 왼쪽 및 상단좌표, 그리고 두 개의 치수가 너비와 높이를 나타내는 형식으로 표현됩니다. 위치와 치수의 단위는 픽셀입니다.

 

Reference

레이아웃 : developer.android.com/guide/topics/ui/declaring-layout?hl=ko

레이아웃 리소스 : developer.android.com/guide/topics/resources/layout-resource?hl=ko

'Android > Android Developer' 카테고리의 다른 글

MotionLayout  (0) 2020.12.02
ConstraintLaytout  (0) 2020.11.02

ConstraintLayout을 사용하면 플랫 뷰 계층 구조(중첩 뷰 그룹이 없음)로 크고 복잡한 레이아웃을 만들 수 있습니다.

 

 ConstraintLayout에서 뷰의 위치를 정의하려면 보기의 가로 및 세로 제약조건을 각각 하나 이상 추가해야 합니다. 

각 제약조건은 다른 뷰, 상위 레이아웃 또는 보이지 않는 안내선을 기준으로 한 정렬 또는 연결을 나타냅니다. 

각 제약조건은 세로 또는 가로 축을 따라 뷰의 위치를 정의하므로, 각 뷰에는 축마다 하나 이상의 제약조건이 있어야 합니다.

 

뷰를 Layout Editor에 놓으면 제약조건이 없어도 둔 위치에 그래돌 남습니다. 이는 단지 더 쉽게 편집하도록 한 것이며, 기기에서 레이아웃을 실행할 때 뷰에 제약조건이 없으면 [0,0](맨 위 왼쪽 모서리) 위치에 그립니다.

 

제약조건이 누락되어도 컴파일 오류가 발생하지는 않지만, Layout Editor에서는 누락된 제약조건을 툴바에 오류로 표시합니다. 오류 및 기타 경고를 보려면 Show Warnings and Errors를 클릭하세요. 제약조건이 누락되지 않도록 Layout Editor에서는 자동 연결 및 제약조건 추론 기능을 사용하여 제약조건을 자동으로 추가합니다.

 

ConstraintLayout을 프로젝트에 추가 

프로젝트에서 ConstraintLayout을 사용하려면 다음을 진행합니다.

1. 모듈 수준 build.gradle 파일에 선언된 maven.google.com 저장소가 있는지 확인합니다.

    repositories {
        google
()
   
}

2. 다음 예와 같이 동일한 build.gradle 파일에 종속 항목으로 라이브러리를 추가합니다. 최신버전은 다음 예에 표시된 버전과 다를 수 있습니다.

  dependencies {
    implementation
"androidx.constraintlayout:constraintlayout:2.0.0"
}

3. 툴바 또는 동기화 알림에서 Sync Project with Gradle Files를 클릭합니다.

 

 제약조건 추가 또는 삭제

상위 요소 포지셔닝

그림7. 상위 요소의 가로제약조건

 

뷰의측면을 레이아웃의 대응하는 가장자리로 제한합니다.

 

그림에서 뷰의 왼쪽은 상위 레이아웃의 왼쪽 가장자리에 연결되어 있습니다. 여백을 사용하여 가장자리로부터의 거리를 정의할 수 있습니다.

 

 

 

위치 순서 지정

 

 가로 또는 세로로 두 뷰가 표시되는 순서를 정의합니다.

 

그림에서 B는 항상 A의 오른쪽에 있도록 제한되고 C는 A 아래 있도록 제한됩니다. 그러나 이 제약조건은 정렬을 의미하지 않으므로, B는 여전히 위 아래로 이동할 수 있습니다.

 

 

  

정렬

 

뷰의 가장자리를 다른 뷰의 가장자리에 맞게 정렬합니다.

 

위의 그림에서 B의 왼쪽은 A의 왼쪽에 맞게 정렬됩니다.

뷰의 중심으로 정렬하려면 양쪽에 제약조건을 만듭니다.

 

 

 

 

 

제약조건에서 안쪽으로 보기를 드래그하여 기준에서 벗어나 정렬할 수 있습니다.   

예를 들어 아래 그림에서는 24dp 벗어나 정렬된 B를 보여줍니다.

이와 같은 오프셋은 제한된 뷰의 여백으로 정의됩니다. 

 

정렬할 뷰를 모두 선택하나 후 툴바에서 Align을 클릭하여 정렬 유형을 선택할 수도 있습니다.

 

 

기준선 정렬 

  

뷰의 텍스트 기준선을 다른 뷰의 텍스트 기준선에 맞춥니다.

 

그림에서 B의 첫 번째 줄은 A의 텍스트에 맞게 정렬됩니다.

 

기준선 제약조건을 만들려면 제한할 텍스트 뷰를 마우스 오른쪽 버튼으로 클릭한 다음 Show Baseline을 클릭합니다. 그런다음 텍스트 기준선을 클릭하고 선을 다른 기준선으로 드래그 합니다. 

  

안내선으로 제한 

 

뷰를 제한할 수 있는 세로 또는 가로 안내선을 추가할 수 있습니다. 안내선은 앱 사용자에게 표시되지 않습니다. 레이아웃의 가장자리를 기준으로 dp 단위 또는 백분율을 기반으로 레이아웃에 안내선을 배치할 수 있습니다. 

  

안내선을 만들려면 툴바에서 Guidelines를 클릭한 다음 Add Vertical Gduieline 또는 Add Horizontal Guideline을 클릭합니다.

 

점선을 드래그하여 위치를 변경하고 안내선 가장자리의 원을 클릭하여 측정 모드를 전환합니다.

 

경계선으로 제한 

  

안내선과 비슷하게 경계선은 뷰를 제한하는 데 사용할 수 있는 표시되지 않는 선입니다. 단, 경계선은 자체 위치를 정의하지 않으며, 경계선 내로 제한된 뷰 위치를 기반으로 경계선 위치가 이동됩니다. 뷰를 특정한 하나의 뷰가 아니라 뷰 집합으로 제한하려고 할 때 유용합니다.

 

예를 들어 그림에서는 C가 경계선의 오른쪽으로 제한된다는 것을 보여줍니다. 경계는 A와 B의 끝으로 설정됩니다. 따라서 A 또는 B의 오른쪽 중 맨 오른쪽에 있는 것에 따라 경계선이 이동합니다. 

 

경계선을 만들려면 다음 단계를 따르세요.

 1. 툴바에서 Guidelines를 클릭한 후 Add VerticalBarrier 또는 Add Horizontal Barrier를 클릭합니다.

 

 2. Component Tree 창에서 경계선 내의 원하는 뷰를 선택하여 경계선 구성요소로 드래그합니다.

 

 3. Component Tree에서 경계선을 선택하고 Attributes 창을 연 후 barrierDirection을 설정합니다.

 

이제 다른 뷰에서 경계선으로의 제약조건을 만들 수 있습니다. 

 

제약조건 편향 조정 

뷰의 양쪽에 제약 조건을 추가하면 두 제약 조건 사이의 중심에 뷰가 위치하며 기본적으로 편향은 50%입니다. 

 

뷰 크기 조정 

그림 14. 보기를 선택할 때 Attributes 창에는 1 크기 비율, 2 제약조건 삭제, 3 높이/너비 모드, 4 여백 및 5 제약조건 편향을 제어하는 기능이 포함되어 있습니다. 6 제약조건 목록에서 제약조건을 클릭하여 Layout Editor에서 개별 제약조건을 강조 표시할 수도 있습니다.

 

 그림 14에서 번호 3으로 표시된 기호를 클릭하여 높이와 너비를 계산하는 방법을 변경할 수 있습니다.

 

  • 고정 : 아래 텍스트 상자에서 특정 측정기준을 지정하거나 편집기에서 뷰의 크기를 조정합니다.

 

 

  • 콘텐츠 래핑 : 뷰가 콘텐츠에 맞게 필요한 만큼만 확장됩니다.

 

 

  • 제약조건과 일치 : 뷰가 양쪽의 제약조건에 맞게 최대한 많이 확장됩니다(뷰의 여백을 처리한 후).
    그러나 다음 속성과 값을 사용하여 동작을 수정할 수 있습니다.

  • layout_constraintWidth_default

    • 넓히기 : 양쪽의 제약조건에 맞게 뷰를 최대한 확장합니다. 이것이 기본 동작입니다.

    • 래핑 : 콘텐츠에 맞게 필요한 만큼만 뷰를 확장하지만, 제약조건에 필요하면 여전히 뷰를 그보다 작게 만들 수 있습니다. 따라서 이 모드를 사용하는 것과 콘텐츠 래핑을 사용하는 것의 차이점은 너비를 콘텐츠 래핑으로 설정하면 너비가 항상 콘텐츠 너비와 정확히 일치하는 반면, layout_constraintWidth_default를 래핑으로 설정한 상태에서 제약조건과 일치를 사용하면 뷰가 콘텐츠 너비보다 작아질 수 있습니다.

  • layout_contraintWidth_min

    뷰의 최소 너비에 dp 측정기준을 사용합니다.

  • layout_constraintWidth_max

    뷰의 최대 너비에 dp 측정기준을 사용합니다.

키 프레임 애니메이션

 ConstraintLayout에서 ConstraintSet 및 TransitionManager를 사용하여 요소의 크기와 위치 변경사항을 애니메이션으로 보여줄 수 있습니다.

★ 참고 : TransitionManager는 Android 4.0 (API 레벨 14) 이상용 지원 라이브러리에서 사용할 수 있습니다.

ConstraintSet 는 ConstraintLayout 에 있는 모든 하위 요소의 제약조건, 여백 및 패딩을 나타내는 경량 개체입니다.

ConstraintSet 를 보고있는 ConstraintLayout에 적용하면 레이아웃에서 모든 하위 요소의 제약조건을 업데이트합니다.

 

ConstraintSet 를 사용하여 애니메이션을 빌드하려면 애니메이션의 시작 및 종료 키프레임 역할을 할 두 개의 레이아웃 파일을 지정합니다. 그런다음 두 번째 키프레임 파일에서 ConstraintSet 를 로드하고 보고있는 ConstraintLayout에 적용할 수 있습니다.

 ★ 중요 : ConstraintSet 애니메이션은 하위 요소의 크기와 위치만 애니메이션으로 보여줍니다.
색상과 같은 다른 속성은 애니메이션으로 보여주지 않습니다

간단한 코드 예에서는 단일 버튼을 맨 아래로 이동하는 애니메이션을 만드는 방법을 보여줍니다.

 

layout/keyframe_one.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:backgroundTint="@android:color/holo_blue_bright"
        android:onClick="animateToKeyframeTwo"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

layout/keyframe_tow.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:backgroundTint="@android:color/holo_blue_bright"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 MainActivity.kt

class MainActivity : AppCompatActivity() {

    lateinit var constraintLayout: ConstraintLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.keyframe_one)
        constraintLayout = findViewById(R.id.constraint_layout)
    }

    fun animateToKeyframeTwo(view:View) {
        val constraintSet = ConstraintSet()
        constraintSet.load(this, R.layout.keyframe_two)
        TransitionManager.beginDelayedTransition(constraintLayout)
        constraintSet.applyTo(constraintLayout)
    }
}

실행화면

Reference

ConstraintLayout : developer.android.com/training/constraint-layout?hl=ko

 

'Android > Android Developer' 카테고리의 다른 글

MotionLayout  (0) 2020.12.02
Layout 레이아웃  (0) 2020.12.01

+ Recent posts