Android Layout
아래 내용은 안드로이드 공식문서 및 개발자를 위한 레시피 tistory 을 참고하였습니다.
https://recipes4dev.tistory.com/66?category=658689!
https://recipes4dev.tistory.com/87?category=658689
https://developer.android.com/guide/topics/ui/declaring-layout
Layout
Layout 은 사전적 의미로 "배치" 라는 뜻이다.
레이아웃은 앱에서 사용자 인터페이스를 위한 구조(Activity
등)를 결정한다.
- 레이아웃의 모든 요소는
View
와ViewGroup
객체의 계층 구조를 사용하여 빌드된다. View
는 사용자가 보고 상호작용할 수 있는 것.ViewGroup
은 View 및 기타 ViewGroup 객체의 레이아웃 구조를 정의하는 보이지 않는 컨테이너이다.
만약 우리가 ConstraintLayout
안에 LinearLayout
을 만들고 두 개의 Button
을 만 든 후 LinearLayout
안에 세 개의 TextView
을 만든 다면 위 그림과 똑같은 구조가 되는 것이다.
이 때 ConstraintLayout
과 LinearLayout
이 ViewGroup
이고, 다른 Button
과 TextView
는 View
로 분류된다.
레이아웃을 선언하는 방법
UI 요소를 XML로 선언. (선언적 방식)
- Android는 위젯, 레이아웃과 같이 View 클래스와 서브클래스를 간단한 XML 문법을 통해 선언한다.
- Android Studio의 Layout Editor를 사용해서 마우스로 드로그 앤 드롭으로도 빌드할 수 있지만 보통 키보드로 빌드한다.
런타임에 레이아웃 요소 인스턴스화 (프로그래밍 방식)
- 직접 프로그래밍하여
View
및ViewGroup
객체를 만들고 그 속성을 따로 선언, 조작할 수 있다.
위 두 가지를 모두 사용하여 앱의 UI를 빌드할 수 있다. 예를 들어 앱의 기본 레이아웃을 XML에서 선언한 다음, 런 타임에 레이아웃을 수정할 수도 있다!
XML
XML 쓰기
XML 어휘를 사용하여 UI Layout과 화면 요소를 중첩된 요소를 사용하는 방식으로 디자인.
루트 요소를 정의하고 더 많은 레이아웃 객체 또는 위젯을 하위 요소로 View 계층 구조를 빌드할 수 있다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a TextView" />
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button" />
</LinearLayout>
XML 리소스 로드
앱을 컴파일할 때 각 XML 레이아웃 파일이 View 리소스 안에 컴파일된다. Activity.onCreate()
콜백 구현해서 레이아웃 리소스를 로드해야 한다.
이 떄 setContentView()
를 호출하고 R.layout.main\_layout
의 형태로 참조한다.
(Resource에 있는 layout 중 main\_layout
을 참조한다는 의미. 이때 main_layout 자리에 해당 레아아웃의 이름이 들어간다.)
fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_layout)
}
속성
모든 View
, ViewGroup
객체는 고유한 XML 속성들을 지원한다.
(예_ ID, 레이아웃 매개변수, 위치정보, 크기, padding, margin 등)
ID
모든 View 객체는 뷰를 고유하게 식별할 수 있는 정수 ID와 연결될 수 있다.
XML 에서는 아래처럼 사용한다.
android:id="@+id/my_button"
(@
) 는 XML Parser 가 ID 문자열의 나머지를 파싱하고 확장하여 ID 리소스로 식별해야 한다는 뜻,
(+
) 는 Android(framework)에 이 리소스가 없기 때문에 반드시 생성하여 리소스에 추가해야 한다는 뜻이다.
🤔그렇다면 (+) 가 없는 경우도 있을까?
Android 프레임워크는 다른 ID 리소스도 많이 제공한다.
우리 앱 내에 있는 것이 아닌 안드로이드 프레임워크 내에 있는 리소스의 ID를 참조할 때는 아래처럼 작성해주어야 한다.
android:id="@android:id/empty"
android 패키지 네임스페이스가 들어가면 로컬 리소스 클래스가 아니라 android.R 리소스 클래스에서 ID를 참조한다.
일반적으로 뷰를 생성하고 이를 앱에서 참조할 때는
1. 레이아웃 파일에서 뷰/위젯을 정의, ID 할당
<Button android:id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_button_text"/>
2.
그리고 뷰 객체의 인스턴스를 생성하고 이를 레이아웃에서 받아온다.
val myButton: Button = findViewById(R.id.my_button)
레이아웃 매개변수
Layout의 종류에 따라 View가 있는 ViewGroup에 적절한 View 레이아웃 매개변수를 정의할 수 있다. (layout\_something
)
즉, 상위 뷰 그룹이 각 하위 뷰의 레이아웃 매개변수를 정의한다. 물론 하위요소에 각기 다른 LayoutParams
도 정의할 수 있다.
(layoutParams
는 이 레이아웃이 어디에 위치할지 결정해주는 속성이다.)
너비와 높이도 정확한 치수로 정할 수 있지만 보통 wrap\_content
나 match\_parent
로 설정한다.
wrap\_content
: 필요한 치수대로 알아서 크기를 조절하라.match\_parent
: 상위 뷰그룹이 허용하는 한 최대 크기로 커져라.
레이아웃 위치
뷰는 직사각형이다. 위치는 한쌍의 왼쪽 및 상단 좌표, 두개의 치수가 너비와 높이를 나타내는 형식[pixel]
뷰의 위치는 getLeft() 및 getTop() 메서드로 검색할 수 있다.
만약 getLeft()가 20을 리턴한다면 뷰가 그 뷰의 부모의 왼쪽 가장자리에서 오른쪽으로 20pix 떨어진 곳에 있다는 의미.
그 외 getRight() (= getLeft() + getWidth() ) , getBottom() 계산
사실 이러한 방식으로 위치는 거의 지정하지 않는다. 그래서 코드블록도 귀찮아서 안 했다. ㅎ
크기, padding, margin
1. 크기 : 하나의 뷰는 두 쌍의 너비 및 높이 값을 갖는다.
- 첫번째 쌍 : 측정된 너비 및 측정된 높이. 이는 뷰가 부모 내에서 얼마나 커지고나 하는지? getMeasuredWidth() 및 getMeasuredHeight()로 치수를 리턴할 수 있다.
- 두번째 쌍 : 단순 너비 및 높이(= drawable width / height) . 뷰가 화면에 표시되는 실제 크기이다. getWidth() 및 getHeight() 호출
2. padding
- 정해진 픽셀 수를 사용하여 뷰의 내용을 안쪽으로 밀어낼 수 있다. 예를 들어 왼쪽 패딩 2 이면 뷰의 내용을 왼쪽 가장자리에서 오른쪽으로 2픽셀 밀어낸다. setPadding(left:int, top:int, right:int, bottom:int)로 설정, getPaddingLeft(), (Top(), Right(), Bottom()) 로 리턴한다.
3. margin
- 뷰에서는 margin은 직접 제공하지 않는다. margin 상위 뷰그룹과 같이 존재할 때 사용된다.
실제로 자주 사용하는 공통 속성
layout\_height
: 세로 길이
layout\_width
: 가로 길이
layout\_margin
: View와 상위 레이아웃 사이의 공간(바깥 쪽에 해당 크기만큼의 공간이 생김)
padding
: View와 View 안의 내용 사이의 공간 (안쪽에 해당 크기만큼의 공간이 생김.)
layout\_gravity
: 상위 레이아웃에서의 위치 정렬 (or연산자('|')를 이용해서 혼합 사용가능)
gravity
: 해당 속성에서의 하위 속성 위치 정렬
일반 Layout의 종류
UI 디자인을 달성하기 위해 하나 이상의 레이아웃을 다른 레이아웃 안에 중첩할 수 있다.
하지만 최대한 중첩을 적게 하는 것이 좋다. 얕을수록 레이아웃이 더 빠르게 그려진다. (가로로 넓은 계층이 세로로 깊은 계층보다 좋다)
linearLayout
Linear : "선형의" -> 말그대로 레이아웃 안의 요소들을 가로 OR 세로 방향으로 선형적으로 나열 할 수 있다.
- orientation : 요소들이 나열되는 방향을 지정해준다. 지정할 수 있는 방향으로 horizontal(가로), vertical(세로)가 있다.
- layout_weight : 가중치를 의미한다. 요소들을 나열할 때 화면의 크기에 비례해서 요소의 크기를 결정할 때 사용한다.
- weightSum : 가중치의 합을 의미한다. 가중치를 주어서 요소를 나열할 때 공백을 구성하고 싶을 때 사용한다.
RelativeLayout
Relative : "상대적인" -> 레이아웃의 요소들을 상대적으로 나열하고 싶을 때 유용하게 사용.
- 뷰와 뷰 사이의 상대적인 위치를 결정할 때
- 부모인 RelativeLayout 기준으로 상대적인 위치를 결정할 때
- 맞춤 정렬을 하고자 할 때
FrameLayout
Frame : "액자" -> 액자에 사진을 꽂아놓고 보관하는 것처럼 여러 개의 뷰를 바꿔가면서 화면에 표시할 수 있다.
주로 하나의 자식 View 만 표시할 때 사용하는 Layout 클래스이다. 물론 여러 View을 자식으로 추가할 수 있다. 이 때 겹쳐진 형태로 표시되고, 가장 최근에 추가된 View 가 가장 위에 표시된다.
안드로이드에서는 특정한 이유가 없는 한 FrameLayout이 오직 하나의 뷰만 표시하도록 권고한다.(FrameLayout 안에 크기가 다른 뷰들을 겹치지 않게 구성하는 것이 어렵다네요)
TableLayout
Table : "표" -> 표처럼 사용할 수 있으며 열(Coulmn), 행(Row)로 표현된다.
- TableRow 라는 요소를 사용하여 행(Row)을 추가할 수 있다.
- TableRow 안에 View를 선언하여 열(column)을 추가할 수 있다.
GridLayout
자식을 직사각형 그리드에 배치하는 레이아웃.
그리드는 보이는 연역을 셀로 구분하는 선 집합으로 구성된다.
rowSpec 및 columnSpec 은 각각 행과, 열을 자식들이 그룹 안에서 어떻게 정렬되야 하는지를 정의한다.
DrawerLayout
Drawer : "서랍" -> 화면을 서랍처럼 열고 닫는 기능을 한다.
- DrawerLayout을 사용하기 위해서는 사용할 요소(View,TextView)가 자식(child)으로 추가되어 있어야 한다.
- 추가로 어느 방향에서 열릴지 layout_gravity값이 설정되어 있어야 한다.
- xml 파일을 새로 생성하여 DrawerLayout을 구현하든 DrawLayout 안에 TextView를 생성하든 DrawerLayout에서 제공하는 함수의 원형을 보면 두 개가 같다는 것을 알 수 있다.
ConstraintLayout
Constraint : "제약" -> 여러가지 제약 조건들을 이용해서 뷰의 크기와 위치를 결정한다.
RelativeLayout의 "상대적인 위치 관계", LinearLayout의 "가중치" , Chain의 "요소 그룹화" 의 특징을 모두 가진다.
대부분의 복잡한 뷰를 구성할 때 이 레이아웃은 항상 쓰인다고 볼 수 있다.
어댑터로 레이아웃 빌드
레이아웃의 콘텐츠가 동적이거나 미리 정의되지 않았다면, AdapterView
의 서브클래스인 레이아웃을 사용하여 런타임에 뷰로 레이아웃을 채울 수 있다.
우리는 Adapter
로 레이아웃에 데이터를 바인딩하면 된다.
이 때 Adapter
는 데이터 소스와 AdapterView
레이아웃 사이의 중개자 역할을 한다. Adapter
가 데이터를 검색하여 각 항목을 뷰로 변환해서 AdpaterView
레이아웃에 추가될 수 있도록 한다.
이 포스팅에서는 안드로이드에서의 기본적인 레이아웃과 LinearLayout 등의 자주 쓰이는 여러 Layout을 소개했습니다. 예전에 공부하고 정리했던 내용을 다시 다듬기만 했는데 술술 읽혀서 다행이네요.
다음 포스팅에서부터 구체적으로 해당 Layout들을 알아볼 것입니다. 다 정리되면 아래 링크도 같이 포함해서 수정할게요!