[1] 첫 앱 만들기 [3] 간단한 UI (User Interface) 만들기

간단한 User Interface (UI)만들기

이번 시간에 배울 것

  1. 리니어 레이아웃(Linear Layout)  생성
  2. 텍스트 필드(Text Field) 추가
  3. 문자열 추가(String Resources)
  4. 버튼(Button) 추가
  5. 입력 상자(Input Box) – 화면 넓이에 맞는

함께 봐야 할 것

Layouts


Why 간단한 UI 만들기?

우리의 프로그램은 눈에 보이는 프로그램입니다. 버튼과 텍스트, 이미지등등이 화면에서 보이지요. 그 것들을 만들고 배치하는 과정이 이 수업에 있습니다.

이번 시간에는 텍스트필드(text field)와 버튼(button)을 포함한 XML 레이아웃을 생성합니다.
다음 시간에는 여러분의 앱이 반응하도록 만들겠습니다.
특정 버튼을 누를 때, 텍스트 필드의 내용물(예를 들어 아이디 비밀번호 등등)을 다른 액티비티에 보내주는 동작을 만드는거죠.

버튼이나 텍스트필드들은 View 객체 중 하나입니다. 이러한 View 객체는 UI들을 담당하는 것들이 많지요.
이 버튼들이나 텍스트들을 배치하기 위해서는 일련의 약속이 있어야 합니다. 누구는 어디에 있어라
누구는 누구의 옆에 있어라 등등을 약속하는데요, 이런 약속들은 ViewGroup로 하는 것입니다.

안드로이드는 XML을 지원합니다. 이것들은 subclass들의 View 나 ViewGroup 해당하지요.
그래서 여러분이 UI 요소들의 상속을 이용해서, 여러분의 UI를 XML로 정의할 수 있도록 합니다.
(해석을 다시 하겠습니다.)

레이아웃들은 ViewGroup의 자식클래스입니다. 이 예제에서는 LinearLayout 를 다루게 됩니다.

그림 1. ViewGroup 객체가 View 객체를 어떻게 가지는지 보여주는 개념도

Alternative Layouts

XML파일을 통해서 정적으로 UI 레이아웃을 짤 수도 있지만, java 코드에서 동적으로도 생성할 수 있습니다.
여러분이 여러 레이아웃을 여러 스크린 사이즈에 맞게 생성하기 위해서는 코드에서 작성하는것은 매우 중요하지요.
예를 들어 여러분이 두 개의 레이아웃 버전을 생성하고, 시스템에게 작은 스크린용 레이아웃이나 큰 스크린의 레이아웃으로 각각 요청할 수 있습니다. 자세한 설명은 Supporting Different Devices 에 있습니다.

Linear Layout 생성하기 <LinearLayout>


  1. 안드로이드 스튜이오의 res/layout 디렉토리에서  activity_my.xml 파일을 열겠습니다.
    프로젝트를 새성할 때 선택한 BlankActivity 템플릿은 자동으로 activity_my.xml 파일을 만들어 줍니다.
    이 파일은 RelativeLayout 가 기본 레이아웃이며 TextView가 그 하위에 있습니다.
  2. Preview 창에서, 숨김 버튼을 클릭하여 미리보기 창을 닫습니다  (궂이 닫을 필요까진 없어요)
    참고로 Android Studio에서 레이아웃 파일을 열면 Preview 창을 볼 수 있습니다.
    이 창에서 각 요소들을 클릭하면 WYSIWYG 방식(보이는 대로 수정가능한) 의 툴이 열립니다.
    이 수업에서 여러분은 XML을 직접 다룰 것이기 때문에 WYSIWYG 방식은 잠시 보류하겠습니다.
  3. <TextView> element를 제거합니다.
  4. <RelativeLayout> element 를 지우고 <LinearLayout> 로 대체합니다.
  5. android:orientation 속성을 추가합니다. 그리고 “horizontal” 값을 넣어줍니다.
  6. android:padding  속성을 지웁니다. 그리고 tools:context 속성을 넣어줍니다

결과적으로 다음과 같이xml  이 되겠네요

res/layout/activity_my.xml 파일 내용 :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

LinearLayout 은 뷰그룹입니다. (ViewGroup 의 종류중 하나죠).
LinearLayout은 자식 View들을 방향에 따른 배치를 하는데요, 수평이나 수직으로 배치합니다.
수평이나 수직으로 배치하는 속성은 android:orientation 입니다.
LinearLayout 에 속해있는 각각의 뷰들은 스크린에 나타게 됩니다.

또 다른 두 개의 속성이 있습니다.
android:layout_width 과 android:layout_height 입니다.
이 것들은 모든 뷰들의 가로, 세로 크기를 결정하게 해 줍니다.

LinearLayout 은 레이아웃에서 기초적인 view 기 때문에, “match_parent” 로 속성 값을 넣어줌으로써,
앱에서 사용할 수 있는 전체 스크린을  채울 수 있게 됩니다.
이 값들은 각 뷰들의 가로나 세로를 부모의 뷰로 맞추게끔 확장하도록 하지요.

좀 더 자세한 정보는 Layout guide를 보시길 바랍니다.

텍스트 필드 추가하기 <EditText>


텍스트 필드를 추가해 보겠습니다. 모든 뷰 오브젝트가 그렇 듯, 여러분은 반드시 특정 XML 속성(attribute)을 정의해 줘야 합니다. EditText 에 특성(properties)을 부여하기 위해서죠.

번역자인 제가 궁금해서 attribute 와 properties 에 대한 조사를 해 보았습니다. 옥스퍼드 영어사전에서는,

attribute : 자질, 속성
properties : (사물의) 속성[특성]

라고 정의되어 있습니다. 즉, attribute 보편적 속성이라는 말입니다.
사람들은 모두 이름, 성, 나이 등등의 속성을 가질 수 있습니다.
그리고 이름을 “철수” 라고 정의해주면 그 사람은 특정한 인물이 되겠지요.
그 특정 인물의 특성은 보편적인 속성에 특정한 속성 값이 들어간 것이라고 볼 수 있겠네요

  1. activity_my.xml 파일에서, <LinearLayout> 엘리먼트(요소) 안에서, <EditText> 엘리먼트를 정의합니다.
    id 속성을 @+id/edit_message 이라고 정의합니다.
  2. layout_width 속성과 layout_height 속성을 wrap_content 로 지정합니다.
  3. hint 속성에 edit_message 문자열 오브젝트로 지정해 줍니다.

<EditText> 엘리먼트는, 위의 내용을 적용하여 다음과 같은 코드를 만듭니다.

res/layout/activity_my.xml 

<EditText android:id="@+id/edit_message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:hint="@string/edit_message" />

여기에 여러분이 추가한 <EditText> 속성들이 있습니다.

android:id
이것은 유일한 구분자입니다.
앱을 구동시키는 코드가 이 객체를 뷰에서 찾을 때 사용하는 이름표 비슷한 역할을 합니다.
(id라는게 통상 그렇잖아요? 내 id 는 다른 사람의 id 와 겹치지 않게 하지요).
예를 들어, 특정 오브젝트를 읽고, 조작할 때, id 를 찾아서 사용하는 것입니다.
@ 기호 (at 이라고 읽습니다) 는 리소스 객체를 XML로부터 참조할 때 필요합니다.
다음은 리소스 타입입니다.
여기서는 id 라는 리소스 타입을 씁니다.
/ 기호 (슬래쉬)가 그 뒤에 붙고, 이름이 붙습니다(edit_message).
+ 기호 : 리소스 타입(id 같은..) 전에 나오는 + 기호는, 리소스 아이디를 처음으로 정의할 때만 필요합니다.
여러분이 앱을 컴파일할 때, SDK 툴은 이 ID로 새로운 리소스 ID를 생성하려고 사용합니다.
그 리소스 ID는 결국 EditTest 엘리먼트를 참조할 것입니다. 그 작업은 우리 프로젝트의 gen/R.java 파일에서 진행됩니다.
위의 리소스ID는 한 번 이런 식으로 선언되면, + 기호는 다시 쓸 필요가 없습니다.
처음에 새로 한 번만 쓰면 되는 것입니다.
+ 기호는 처음에 새로운 ID를 정의할 때만 필요합니다.
그리고 실체 있는 리소스 (예를 들어 string이나 layout 들)에는 필요가 없습니다.
(그러고보니 아래쪽에 힌트는 + 기호가 사용되지 않았어요).
좀 더 자세한 정보를 보기 위해서 아래의 resource objects 를 참고하세요.

리소스 오브젝트 (Resource Objects)

리소스 오브젝트는 유일한 정수형 이름입니다.
앱 리소스와 관련이 있지요.
예를 들어 비트맵 이미지나, 레이아웃 파일, 문자열 등이 이에 해당합니다.

모든 리소스는 그에 상응하는 리소스 오브젝트를 가지고 있습니다.
여러분의 프로젝트의 gen/R.java 파일에 이미 정의가 되어 있습니다.

R 클래스 안에 있는 오브젝트 이름을 여러분의 리소스를 참조하기 위하여 사용할 수 있습니다.
예를 들어, 어떤 문자열 값을 android:hint 속성에 가져다 쓸 수 있습니다.

또한 임의적인 리소스 ID들을 생성할 수 있습니다.
이 임의의 ID는 android:id 속성을 사용하는 뷰에 관련이 있습니다.
이 것은 다른 코드에서 뷰를 참조하도록 허용합니다

(원문: Every resource has a corresponding resource object defined in your project’s gen/R.java file. You can use the object names in the R class to refer to your resources,

such as when you need to specify a string value for the android:hint attribute. You can also create arbitrary resource IDs that you associate with a view using the android:id attribute, which allows you to reference that view from other code)

R.java 파일은 SDK가 앱을 컴파일 할 때 마다 자동으로 만들어집니다.
이 파일은 사용자가 임의수정해서는 안됩니다.

더 자세한 정보를 위해서는 참고하세요 : Providing Resources.

android:layout_width ,  android:layout_height
정해놓은 고정된 사이즈를 사용하는 대신,
“wrap_content” 라는 값을 사용하면, 뷰는 자신의 내용물이 보이는 데 필요한 만큼의 크기로 알맞게 조절됩니다.
“match_parent”를 사용하면 EditText 엘리먼트는 스크린을 가득 채우게 됩니다. 부모 LinearLayout 에 맞춰 그 사이즈가 맞춰 지는 것입니다. 더 자세한 정보는 Layouts 가이드를 살펴보세요.

android:hint
기본적으로 표시되는 문자열입니다. 텍스트필드가 비어 있을 때 힌트가 보여졌다가 사용자가 글자를 입력하기 시작하면 그 곳의 영역은 문자가 사라지지요. 일종의 가이드를 제시하기 위한 장치라고 보면 됩니다. 하드코딩된(직접 써 넣는 방식을 하드코딩이라고 합니다) 문자열을 값으로 쓰는 대신, “@string/edit_message” 을 쓰게 되면 string 리소스를 참조하게 됩니다. 다른 파일에서 정의를 해 놓은 값들을 이 곳에 넣을 수 있는 것입니다. 컨크리트 리소스를 참조하는 것이기 때문에(identifier가 아니라), + 기호는 필요 없습니다. 하지만 여러분이 미리 정의해 놓은 문자열 리소스가 아직 없기 때문에, 처음에는 컴파일 에러가 납니다. 다음 섹션에서 문자열을 정의함으로써 고치겠습니다.stringError주의 : 이 스트링 리소스는 ID 엘리먼트와 같은 이름을 갖고 있습니다: edit_message. 즉, 힌트와 ID가 같은 이름을 갖고 있다는 것입니다. 하지만, 리소스를 참조하는 것들은 언제나 리소스 타입에 의해서  범위가 정해지기 때문에 (id 나 string), 같은 이름을 쓰는 것이 충돌을 일으키지는 않습니다.

문자열 리소스 추가하기 : Add String Resources


기본적으로, 여러분의 안드로이드 프로젝트는 문자열 리소스 파일을 가지고 있습니다.
위치는 res/values/strings.xml 에 있어요.
여기서 여러분은 새로운 "edit_message" string을 추가할거에요.
그리고 그 값으로 “Enter a message.” 라고 써 줄 겁니다.

  1. 안드로이드 스튜디오에서,  res/values 에서, strings.xml 파일을 오픈합니다
  2. "edit_message" 을 추가합니다. 값은 “Enter a message” 입니다.
  3. "button_send" 을 추가합니다 값은 “Send” 입니다. 다음 수업에서 string을 이용해서 버튼을 생성할 겁니다
  4. "hello world" string을 제거합니다.

위의 결과로 strings.xml 은 다음과 같이 완성되겠지요.

res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My First App</string>
    <string name="edit_message">Enter a message</string>
    <string name="button_send">Send</string>
    <string name="action_settings">Settings</string>
    <string name="title_activity_main">MainActivity</string>
</resources>

위의 UI에서 텍스트는, 언제나 각각의 문자열을 리소스로 등록합니다.(하드코딩 하는게 아닙니다).
String 리소스를 사용함으로써 우리는 한 곳에서 모든 UI 텍스트를 다룰 수 있습니다.
string 리소스를 한 곳에서 관리할 수 있다는 것이지요.
이러한 방법은 원하는 텍스트를 쉽게 찾고, 내용을 업데이트 할 수 있게 해 줍니다.
문자열을 표면화 하는 것은 또한 여러분이 여러분의 앱을 여러 언어를 사용할 수 있게 할 수 있는데요,
각각의 string 리소스에 대해서 alternative definitions를 제공 할 수 있습니다.

좀 더 자세한 정보를 얻기 위해서 Supporting Different Devices 수업을 참고하세요.

버튼 추가하기 : Add a Button


  1. 안드로이드 스튜디오 내에서, res/layout 디렉토리에서 activity_my.xml 파일을 수정합니다.
  2. <LinearLayout> 엘리먼트 내에서, 위에서 정의했던 <EditText>  바로 다음에 <Button> 엘리먼트를 정의합니다
  3. 버튼의 너비와 높이 속성을 "wrap_content" 로 정합니다. 버튼은 딱 자신의 텍스트 라벨(레이블?) 이 필요한 만큼만 크기를 알아서 지정할 것입니다.
  4. 버튼의 라벨(레이블?)을 정의합니다. 버튼에 어떤 글자를 새길 것인지를 정하는 것입니다. android:text 속성에 값을 입력해서 이 글자를 바꿀 수 있는데요, 하드코딩할 수도 있지만 우리는 위에서 배운대로 string 리소스를 따로 관리할 것입니다. 바로 위의 섹션에서 만들었 듯, button_send 라는 string 리소스로 지정합니다.

위의 스텝을 마치면 <LinearLayout> 은 다음과 같습니다.

res/layout/activity_my.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
      <EditText android:id="@+id/edit_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />
      <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send" />
</LinearLayout>

주의: 이 버튼은 android:id 속성이 필요 없습니다. 이 버튼은 액티비티 코드에서 참조하는 것이 아니기 때문이지요.

(코멘트 : 아하! 그렇군요! 액티비티 코드에서 참조를 할 게 아니라면 id 속성이 궂이 필요 없군요! 그래서 버튼은 그냥 저렇게만 되어 있는 것이었어요.)

레이아웃은 현재 EditText 와 Button 위젯이 각각의 내용물에 맞게끔 각각의 사이즈가 정해지도록 설계되었습니다.

그림 2. EditText 와 Button 위젯은 너비가 “wrap_content“로 지정되어 있는 모습

너비를 wrap_content 로 정하는 것이, 버튼에 있어서는 적당하지만 텍스트 필드에는 적합하지 않습니다.
왜냐하면 사용자가 좀 더 길게 텍스트를 작성할 수 있기 때문이지요.
그래서 사용하지 않는 공간을, 텍스트 필드로 채우는 것이 좋겠네요.
weight 특성을 이용해서 해 볼 수 있습니다.
명시적으로 android:layout_weight 속성을 사용해서 할 수 있습니다.

weight 값은 숫자입니다.
이 숫자는 남은 양을 각각의 뷰가 얼마나 나눠 가질지를 명시하는 것입니다.
주변 뷰에서 사용한 공간의 양과 많은 관계가 있습니다.
이러한 개념은 마치 우리가 칵테일같은 음료를 만들 때 재료들을 섞는 량을 정해주는 것과 비슷합니다.
“소다와 시럽을 2:1로 섞는다면, 칵테일에 소다가 2/3 들어 있습니다.” 처럼 말이지요.
한 뷰에 weight 를 2로 주고 다른 하나를 1로  준다면,  총량은 3입니다. 그래서 첫 뷰는 총 공간의 2/3을 차지하며, 두 번째 뷰는 나머지를 차지하게 됩니다.
세 번째 뷰를 추가하고 weight 를 1 준다면 어떻게 될까요? 첫번째 뷰 : 2, 두 번째 뷰 : 1, 세 번째 뷰 : 1 이기 때문에 총 공간의 2/4, 1/4, 1/4 씩 가져가게 됩니다.

모든 뷰의 기본 weight 값은 0입니다.
그래서 만약 우리가 여러 view 중 weight 값을 0보다 크게 하면 그 화면만 보이게 됩니다. 공간이 얼마나 남아있는지 상관 없이 그렇게 됩니다.

Input Box 를 스크린 너비에 꽉 채우도록 만들기


레이아웃의 나머지 공간을 EditText 엘리먼트로 모두 채우기 위해서 다음을 따라하세요:

  1. activity_my.xml 파일에서, <EditText> 요소의 layout_weight 속성의 값을 1로 할당합니다.
  2. 그리고, <EditText> 요소의 layout_width 속성을 0dp 로 지정합니다. (오호… 0dp로 지정하는군요)
  3. res/layout/activity_my.xml

    <EditText
        android:layout_weight="1"
        android:layout_width="0dp"
        ... />

    weight를 정하는 데에 레이아웃 효율을 높이기 위해서, 우리는 EditText 의 폭(width)을 0dp 가 되도록 바꿔야 합니다.
    폭을 0로 세팅라는 것은 레이아웃의 퍼포먼스를 향상킵니다.
    Setting the width to zero improves layout performance because using "wrap_content" as the width requires the system to calculate a width that is ultimately irrelevant because the weight value requires another width calculation to fill the remaining space. (해석이 어렵네요. 일단 그냥 0dp 로 두면 퍼포먼스가 좋아진다니까 넘어 가겠습니다.)

    그림 3 은 우리가 모든 weight을 EditText 에 놓은 결과를 보여줍니다.

    그림 3. EditText  위젯에게 레이아웃 weight가 전부 부여되었습니다. 그래서 LinearLayout 내의 모든 남은 공간으로 채워지게 된 것입니다.

이렇게 해서 activity_my.xml 레이아웃 파일을 완성할 수 있습니다.

res/layout/activity_my.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <EditText android:id="@+id/edit_message"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send" />
</LinearLayout>

앱 실행하기 : Run Your App


이 레이아웃은 기본 Activity class에 적용됩니다. 기본 Activity class 는 우리가 프로젝트를 생성할 때 SDK가 생성해 낸 것입니다. 앱을 구동시켜서 결과를 보겠습니다.

  • 안드로이드 스튜디오 툴바에서 Run  버튼을 클릭합니다.
  • 또는 커맨드 라인에서 여러분의 안드로이드 프로젝트가 있는 폴더로 이동 후 다음과 같이 실행합니다.
  • ant debug
    adb install bin/MyFirstApp-debug.apk

다음 수업시간에서는 어떻게 버튼을 눌렀을 때 반응하게 하는지 배워보겠습니다. 텍스트 필드, 다른 액티비티 시작하기 등등이 있습니다.

출처 : 안드로이드 공식 메뉴얼 페이지
번역 : uartis

Advertisements

2 thoughts on “[1] 첫 앱 만들기 [3] 간단한 UI (User Interface) 만들기

    은찬 김 said:
    2016년 10월 17일 4:34 오후

    감사합니다.

    좋아요

    은찬 김 said:
    2016년 10월 17일 4:35 오후

    감사합니다~

    좋아요

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중