웹/모바일 안드로이드 기초

2.3 버튼과 입력컨트롤

버튼과 이미지 버튼

버튼은 가장 흔하고 많이 사용되는 위젯 입니다. 입력된 데이터를 저장하거나 서버로 전송하는 경우 혹은 사용자에게 Yes, No 형태의 결정을 요구하는 등 사용자 인터페이스 구현에 다양하게 활용 됩니다.

여기서는 보다 효과적인 UI 구성을 위해 버튼을 디자인하는 방법과 이미지 버튼을 만드는 방법을 살펴 봅니다.

버튼은 입체감있게 올라온(Raised) 일반적인 형태의 버튼과 평평한(Flat) 버튼이 있습니다. 완전한 버튼 구조에 배경과 이미지를 포함한 버튼은 이미지 버튼이라고 합니다.

일반적으로 버튼 디자인 유형은 다음과 같습니다.

[그림 추가해야 함]

버튼에 들어가는 텍스트는 text 속성에 텍스트를 입력하면 되고 아이콘을 넣기 위해서는 image asset을 추가해서 사용해야 합니다.

image asset 추가

버튼에 들어가는 아이콘은 png 등 이미지파일을 사용할 수 있지만 그냥 사용하는 경우 버튼 크기에 맞도록 이미지를 수정해야 하며 그렇게 만들어진 이미지는 사용자 디바이스의 화면 크기나 해상도등에 따라 다르게 보일 수 있고 폰의 테마에 따라서도 일관성 없는 모양이 될 수 있기 때문에 반드시 image asset 을 추가해 사용하도록 합니다.

[그림 추가해야 함]

그외 다양한 아이콘을 만드는 방법은 Image Asset Studio로 앱 아이콘 만들기를 참고해 주세요.

버튼에 아이콘 적용

일반 버튼의 경우 버튼 위젯의 drawbleLeft/Right/Top/Bottom/Start/End 속성으로 아이콘을 지정할 수 있습니다. 앞에서 만든 아이콘을 @drawable/ic_mail과 같이 등록 합니다.

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/button_text"
    android:drawableLeft="@drawable/ic_mail"
    ...
/>

일반 버튼의 경우 아이콘과 텍스트가 함께 있는 경우 사용하며 텍스트를 입력하지 않을 경우 공간이 남게 되어 보기 좋지 않습니다. 이때 버튼 크기를 임의로 조정하는 것은 바람직 하지 않습니다. 텍스트 없이 아이콘만 있는 버튼을 만드는 경우 Button 대신 ImageButton을 사용해야 하며 이 경우 위젯을 레이아웃 에디터에서 선택해 추가할때 자동으로 아이콘을 선택할 수 있는 화면이 나오게 되며 선택하지 않을 경우 버튼이 추가되지 않습니다.

플랫 버튼

텍스트 버튼 또는 경계선없는 버튼 이라고도 하는 플랫 버튼 은 평평하게 보이고 그림자가없는 텍스트 전용 버튼입니다. 플랫 버튼의 주요 이점은 단순성입니다. 플랫 버튼은 아래 그림과 같이 사용자 상호 작용이 필요한 대화 상자에 유용합니다. 이 경우 대화 상자의 모든 요소에서 모양과 느낌을 유지하기 위해 단추가 주변 텍스트와 동일한 글꼴 및 스타일을 사용하도록합니다.

[그림 추가해야 함]

플랫 버튼은 Button 위젯의 style 속성에 다음과 같이 지정하면 됩니다. style 속성에는 몇몇 사용가능한 버튼 유형이 있으므로 참고하기 바랍니다.

style="?android:attr/borderlessButtonStyle" 

이벤트 처리

버튼 이벤트 처리는 일반적인 View 의 이벤트 처리와 동일합니다. 이벤트 처리와 관련해서는 2.2: 이벤트 핸들링을 참고하기 바랍니다.



입력 컨트롤

입력 컨트롤은 앱 UI에서 데이터 입력을 허용하는 위젯입니다. 사용자로부터 무언가를 입력받기 위한 위젯들로 스크린 키보드를 사용하여 텍스트나 숫자를 입력하거나 체크박스, 라디오 버튼 및 드롭 다운 메뉴에서 옵션을 선택하고 설정을 변경하는등의 동작을 수행합니다.

안드로이드는 UI에 대한 다양한 입력 컨트롤을 제공하며 대표적인 입력 컨트롤은 다음과 같습니다.

[그림: 입력컨트롤], 출처: https://developer.android.com
  1. EditText: 키보드를 통한 텍스트 입력
  2. SeekBar: 터치로 좌우 슬라이딩을 통한 선택
  3. CheckBox: 여러 항목(item)중 다중 선택이 가능한 체크박스
  4. RadioGroup: 여러 항목중 하나만 선택이 가능한 라디오 버튼 그룹
  5. Switch: on-off 형태의 스위치로 켜고 끄는 동작을 수행, ToggleButton도 유사함
  6. Spinner: 드롭다운 형태로 하나의 선택이 가능

대부분의 입력 컨트롤은 레이아웃 에디터의 팔렛트에 등록되어 있으며 TextButton 으로 분류 됩니다. SeekBarWidgets 에 있으며 SpinnerContainer 에 등록되어 있습니다.

그 외 다양한 입력컨트롤은 안드로이드 개발자 문서를 참고하기 바랍니다.

RadioGroup, RadioButton

라디오 버튼 입력을 만들기 위해서는 동일 선택 그룹을 묶기 위해 RadioGroup을 컨테이너로 사용 합니다. 각각의 입력 요소들은 RadioButton으로 정의 해야 하며 각각의 버튼은 이벤트 처리를 위해 동일한 이벤트 핸들러 메서드를 호출하도록 해야 합니다.

이벤트 핸들러 메서드에서는 어떤 항목이 선택되었는지 확인하고 처리하는 코드의 구현이 필요 합니다.

<RadioGroup
    android:id="@+id/drinkMenu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    <RadioButton
        android:id="@+id/coffee"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Coffee" 
        android:onClick="onDrinkMenuClicked"
        />

    <RadioButton
        android:id="@+id/tea"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Tea" 
        android:onClick="onDrinkMenuClicked"
        />
</RadioGroup>

만일 개별 버튼 선택시 이벤트 동작이 이루어지지 않고 확인 혹은 주문과 같은 별도의 버튼을 통해 이벤트를 처리하는 경우 이벤트 핸들러 메서드에서 어떤 버튼이 선택되었는지 확인하는 과정이 필요 합니다.

public void onDrinkMenuClicked(View view) {
   boolean checked = ((RadioButton) view).isChecked();
   
   switch(view.getId()) {
      case R.id.coffee:
         if (checked)
            ...
            break;
      case R.id.tea:
         if (checked)
            ...
            break;
   }
}

CheckBox

체크박스는 라디오 버튼과 거의 동일하게 구현 합니다. 다만 라디오 버튼과는 달리 중복 선택이 가능하므로 별도의 그룹 개념이 없습니다. 그렇지만 화면 구성상의 편의를 위해 CheckBox 위젯들은 별도의 레이아웃이나 컨테이너로 묶어주는 것이 좋습니다. 보통 별도의 LinearLayout에 CheckBox 를 추가하거나 RadioGroup을 사용합니다.

이벤트 처리에 있어서도 선택시점 혹은 별도의 버튼을 통한 이벤트 처리시 해당 체크박스가 선택되었는지 확인하고 처리하는 코드가 구현되어야 합니다.

Spinner

스피너는 앞에서 살펴본 것 처럼 드롭 다운 형태의 입력 컨트롤 입니다. 스피너에는 선택 가능한 항목들이 추가되어야 하는데 이러한 이유로 분류상 Containers에 포함 됩니다.

Spinner 에 데이터를 추가하기 위해서는 아이템 항목을 xml 리소스에 등록해 두고 entries 속성을 이용해 지정하거나 프로그램 코드로 구현하는 방법이 있습니다.

기본 제공되는 모양을 그냥 사용하는 경우에는 entries 속성을 사용하는 것이 간편하고 세부적인 디자인을 변경하거나 커스터마이징이 필요하면 코드로 구현해야 합니다. 항목들을 데이터베이스나 외부로 부터 받아오는 값을 사용하는 경우에도 코드 구현이 필요 합니다.

먼저 스피너의 항목으로 사용할 값들을 arrays.xml 에 string-array 로 등록 합니다. strings.xml 에 추가해도 상관 없습니다.

arrays.xml

<string-array name="labels_order">
    <item>Appetizer</item>
    <item>Main</item>
    <item>Drink</item>
    <item>Dessert</item>
</string-array>

entries 속성으로 항목 추가

레이아웃 디자이너의 속성창이나 xml 파일에 다음과 같이 속성을 추가 합니다.

activity_main.xml

<Spinner android:id="@+id/spinner"
    ...
    android:entries="@array/jobList"
/>

코드로 항목 추가

스피너에 데이터를 연결하려면 Adapter가 필요하며 Adapter는 스피너와 데이터를 연결해주는 일종의 게이트웨이 역할을 수행 합니다.

먼저 스피너 View 를 바인딩하고 항목들을 표시하기 위한 Adapter를 생성 합니다. 이때 배열 데이터를 출력할 어댑터는 android.R.layout.simple_spinner_item 을 사용하고 각각의 항목을 출력하기 위한 뷰 어댑터는 android.R.layout.simple_spinner_dropdown_item을 사용 합니다. 물론 용도에 따라 다른 레이아웃을 적용할수도 있습니다

MainActivity.java

spinner = findViewById(R.id.spinner_order);

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
    this, R.array.jobList, 
    android.R.layout.simple_spinner_item);
    
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

spinner.setAdapter(adapter);

이벤트 처리를 위해서는 스피너에 setOnItemSelectedListener를 등록 합니다.

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});

SeekBar

SeekBar는 슬라이더 형식의 입력 위젯으로 터치를 이용해 좌우로 이동해서 특정 값을 선택하는 구조 입니다. 보통 화면 밝기나 볼륨 조절 UI를 생각하면 됩니다.

SeekBar 자체는 다른 위젯들과 마찬가지로 사용할 수 있지만 슬라이더를 움직일때 기본적으로 값이 나타나지 않기 때문에 값을 보여주기 위한 이벤트 처리가 병행 되어야 하며 조절 범위 설정이 필요 합니다.

activity_main.xml

<SeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:mix="15"
    android:max="100"
    android:progress="50" 
    android:thumb="@drawable/thumb"
/>

MainActivity.java

...
SeekBar age;
TextView ageTxt;

protected void onCreate(Bundle savedInstanceState) {

    age = findViewById(R.id.ageSeekBar);
    ageTxt = findViewById(R.id.age);

    age.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){    
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            ageTxt.setText(String.valueOf(progress));    
        }
    }
    ...
}

실습 및 참고자료

실습: 버튼과 입력 컨트롤을 이용한 풍부한 UI 구성

다양한 버튼과 입력 컨트롤로 구성된 사용자 등록 양식을 만들어 봅니다.

본 예제는 다음과 같은 내용들을 학습하기 위한 내용으로 구성 됩니다.

프로젝트 준비

실행 결과

따라하기 및 코드 설명

유튜브 동영상 강좌를 참고해 주세요


참고자료