본문 바로가기
컴퓨터 공학/Android

[Do it 개정6판_안드로이드 스튜디오]둘째마당_03 기본 위젯과 드로어블 사용하기

by hahehohoo 2019. 11. 28.
반응형

03-1 기본 위젯 다시 한 번 자세히 공부하기

■ 텍스트뷰 자세히 살펴보기

- 화면에 글자를 보여주는 역할

- strings.xml 파일에 작성한 문자열을 지정할 수 있음, 이 파일에 정의된 문자열은 text 속성에서 @string/... 와 같은 형식응로 참조해야 합니다. 

- XML 레이아웃 파일과 문자열 파일을 구분하는 것이 좋음

 

- 안드로이드에서 다국어를 지원하려면?

더보기

app/res 폴더 안에 두 개의 폴더를 만든 후 그 안에서 stings.xml 파일을 넣어둔다. 영어는 values-en, values-ko

- textColor 속성 : 텍스트뷰에서 표시하는 문자열의 색상, '#AARRGGBB' 포맷 사용

- textSize 속성 : 단말 해상도에 따라 글자의 크기를 일정한 크기로 보일 수 있게 하며 폰트를 변경했을 때 해당 폰트도 반영되도록 해 줍니다. 

- textStyle 속성 : 문자열의 스타일 속성 "normal", "bold","italic"

- textFace 속성 : 문자열의 폰드 

- maxLines 속성 : 텍스트뷰에서 표시하는 문자열의 최대 줄 수 

 

■ 버튼

- 사용자가 클릭하면 클릭에 대한 반응을 하는 위젯

- 텍스트뷰를 상속하여 정의되어 있다. 

- 간단하게 처리할 수 있는 방법은 onClickListener를 정의하여 버튼에 설정하는 것

- 체크 박스와 라디오 버튼은 단순히 클릭 이벤트만 처리하는 것이 아니라 상태 값을 저장하고 선택/해제 상태를 표시할 수 있습니다.

 

- button.xml을 앱의 첫 화면으로 등록하려면 MainActivity.java 파일을 열고 setContentView() 메서드에 전달되는 파라미터의 값을 R.layout.Button 으로 변경  

 

 

■ 에디트텍스트

 

 

■ 이미지뷰와 이미지 버튼

- 이미지뷰와 이미지 버튼은 이미지를 화면에 표시할 때 사용하는 가장 간단한 위젯이다. 

- 이 둘의 차이는 버튼처럼 사용할 수 있다는 점 이외에는 없다. 

- 이미지 파일은 res 폴더 안에 들어 있는 리소스 중의 하나이기 때문

 

- res 속성 : 원본 이미지

- maxWidth, maxHeight 속성 : 이미지가 표시되는 최대 폭, 높이 설정

- tint 속성 : 이미지의 색상 설정 가능

- scaleType 속성 : 이미지뷰의 크기에 맞게 원본 이미지의 크기를 자동으로 늘리거나 줄여서 보여줄 때

 

이미지 버튼은 일반적인 버튼과는 다르게 눌린 상태와 그렇지 않은 상태를 표시하지 않기 때문에 이 문제를 해결하려면 Selecter를 만들어 사용해야 한다. 

 

■ 텍스트뷰와 에디트텍스트의 다른 기능들

- 텍스트뷰와 에디트텍스트뷰 등은 모두 뷰를 상속받아 만들어진 것 

 

- 커서 관련 속성 : 입력된 문자열의 마지막 지점으로 이동하도록 되어 있다. 

예1) selectAllOnFocus 속성을 true로 설정하면 포커스를 받을 때 문자열 전체가 선택

예2) 커서가 보이지 않게 하려면 cursorVisible 속성을 "false" 값으로 설정

 

- 자동 링크 관련 속성

 

 

- 줄 간격 조정 관련 속성

 

- 대소문자 표시 관련 속성 : 속성 값으로 "characters","words","sentences" 등을 지정할 수 있는데 각각의 값으로 설정하면 글자, 단어, 문자 단위로 맨 앞 글자를 대문자로 표시할 수 있음

 

- 줄임 표시 관련 속성 : ellipsize 속성을 사용하면 입력한 내용의 생략 부분을 설정할 수 있다.

 

- 힌트 표시 관련 속성

 

- 편집 가능 관련 속성 : 입력되어 있는 문자열을 편집하지 못하게 하고 싶다면 editable 속성 값을 "false"로 설정

 

- 문자열 변경 처리 관련 속성 : 에디트텍스트에 입력된 문자를 확인하거나 입력된 문자가 필요한 포매솨 맞는지 확이할 때 getText() 메서드를 사용, 이 메서드가 리턴하는 것은 Editable 객체인데 이 객체의 toString() 메서드를 이용하면 일반 String 타입의 문자열을 확인할 수 있음

 

 - addTextChnagedListener() 메서드를 사용하면 TextWatcher 객체를 설정할 수 있음. 이 객체는 텍스트가 변경될 때마다 발생하는 이벤트를 처리한다. 

 

03-2 드로어블 만들기

■ 뷰의 배경 이미지

- 상태에 따라 그래픽이나 이미지가 선택적으로 보이게 할 수 있다.

-

 

 

■ 드로어블

- 뷰에 설정할 수 있는 객체이며 그 위에 그래픽을 그릴 수 있다. 

- 뷰의 상태에 따라 뷰에 보여줄 그래픽을 다르게 지정할 수 있다. 

 

■ 상태 드로어블 만들기

 

 

- finger_drawable.xml 파일 안에 <selector> 태그를 확인할 수 있다. 최상위 태그인 <selector> 태그 안에는 <item> 태그를 넣을 수 있음

- state_ 로 시작하는 속성은 상태를 나타내는데 간단한 예로 state_pressed 속성은 눌린 상태를 말하고, state_pocused 포커스를 받은 상태

- 다음과 같이 코드를 작성하고, activity_main.xml 파일의 버튼의 background 속성의 값을 @drawable/finger_drawable로 변경

 

■ 세이프 드로어블 만들기

 

- XML로 도형을 그릴 수 있게 해줌

- 앱의 배경색에 그러데이션 효과 주기 : <gradient> 태그 사용하기

- 테두리만 있는 버튼 만들기

도형 안쪽은 투명하게, 테두리는 색만

03-3 이벤트 처리 이해하기

■ 이벤트 처리 방식

- 사용자의 화면 터치에 대한 이벤트를 처리해야 여러 기능을 구현할 수 있다

- 터치 이벤트를 쉽게 처리할 수 있도록 '클릭 이벤트(Click Event)를 별도로 제공한다. 

 

- XML이 아니라 소스 코드에서 클릭 이벤트를 처리하도록 하려면 버튼의 setOnClickListener() 메서드를 이용해 리스너를 설정할 수 있습니다. 

- 화면에서 발생하는 이벤트를 버튼과 같은 위젯 객체에 전달한 후 그 이후의 처리 과정을 버튼에 위임한다고 해서 '위임 모델(Delegation Model)'이라고 부릅니다. 

- 코드를 만들 때 사용하는 이 패턴은 각각의 뷰마다 하나의 이벤트 처리 루틴을 할당해 준다. -> 이벤트를 이벤트 루프에서 받아 처리할 때처럼 코드가 복잡해지지 않고 이벤트를 위젯마다 개별적으로 처리하는 객체 지향 코드를 만들 수 있다

- onClickListener는 이벤트가 발생하면 즉시 동작할 수 있도록 만들어주는 리스너 중 하나

 

■ 터치 이벤트 처리하기

코드

더보기

package com.ogrg.sampleevent;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = findViewById(R.id.textView);

View view = findViewById(R.id.view);
view.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View view, MotionEvent motionEvent){
int action = motionEvent.getAction();

float curX = motionEvent.getX();
float curY = motionEvent.getY();

if(action == MotionEvent.ACTION_DOWN){
println("손가락 눌림: "+ curX + curY);
}else if(action == MotionEvent.ACTION_MOVE){
println("손가락 움직임: "+ curX + curY);
}else if(action == MotionEvent.ACTION_UP){
println("손가락 뗌: "+ curX +","+ curY);
}
return true;
}
});
}

public void println(String s) {
textView.append(s+"\n");
}
}

- OnTouch () 메서드로는 MotionEvent 객체가 파라미터로 전달

 

■ 제스처 이벤트 처리하기

- 터치 이벤트 중에서 스크롤 등을 구별한 후 알려주는 이벤트

- 제스처 이벤트를 처리해주는 클래스는 GesturDetector

 

 

■ 키 이벤트 처리하기

 

 

■ 단말 방향을 전환했을 때 이벤트 처리하기

- 단말 방향이 바뀔 때 액티비티가 메모리에서 없어졌다가 새로 만들어진다

- 이 경우에 액티비티 안에 선언해 두었던 변수 값이 사라지므로 변수의 값을 저장했다가 복원하는 방법을 알아야 함

-> onSaveInstanceState 콜백 메서드(액티비티가 종료되기 전의 상태를 저장)가 제공 됨

- 이 때 저장한 상태는 onCreate() 메서드가 호출될 때 전달되는 번들 객체로 복원할 수 있다. 

 

- 번들 객체에 데이터를 넣으면 그 데이터는 단말에 저장되고 onCreate() 메서드가 호출될 때 파라미터로 전달됨

- onCreate() 메서드의 파라미터는 savedInstanceState라는 이름으로  되어있으며, 이 객체에서 데이터를 가져와 name 변수에 다시 할당하면 데이터를 복구하게 됨

 

- 액티비티는 바뀌지 않고 단순히 화면에 보이는 레이아웃만 바꾸고 싶다면 액티비티를 굳이 없앴다가 다시 만들 필요가 없다. 

- 액티비티를 유지하는 방법은?

- 기본적으로 단말의 방향 전환은 내부 센서에 의해 방향이 바뀌는 시점을 알 수 있다. 

- 방향이 바뀌는 시점의 이벤트를 앱에 전달한 다음 추가적인 기능이 동작하도록 만든다. 

-> 메니페스트에 액티비티를 등록할 때 configChanges 속성을 설정해야 합니다. 

app/manifests/AndroidManifest.xml

더보기

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ogrg.sampleorientation2">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:configChanges="orientation|screenSize|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

- configChanes 속성 값이 설정되면 시스템은 액티비티의 상태 변화를 액티비티 쪽으로 알려주기만 하면 된다. 

- configChanges 속성 값으로 "orientation|screenSize|keyboardHidden" 설정하면 단말의 방향이 바뀔 때마다 액티비티에서 인식할 수 있고, 메서드가 자동 호출

 

 

- 방향을 고정하고 싶다면?

- mainfests 파일에서 코드 수정하기

▼ 코드

더보기

<activity android:name=".MainActivity"
android:screenOrientation="landscape"
android:configChanges="orientation|screenSize|keyboardHidden">

 

03-4 토스트, 스낵바 그리고 대화상자 사용하기

- 코드를 만들어서 실행하다 보면 중간 중간 디버깅 메시지를 확인해 보거나 사용자에게 간단한 메시지를 보여줘야 하는 경우가 있다

- 디버깅을 위해서는 일반적으로 Log 클래스를 사용해서 로그를 출력할 수 있다. 

- 이 로그는 안드로이드 스튜디오 하단에 보이는 Logcat 창에서 확인할 수 있다. 

 

- 토스트는 앱 위에 떠있는 뷰라고 할 수 있음

- Context 객체는 일반적으로 Context 클래스를 상속한 액티비티를 사용할 수 있음

 

■ 토스트 위치 바꿔 보여주기

- 임의의 좌표를 지정해서 보여주기

 

▼ 코드_activity_main.xml

더보기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:hint="X 위치"
android:inputType="numberSigned"
/>

<EditText
android:id="@+id/editText2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:hint="X 위치"
android:inputType="numberSigned"
/>
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="띄우기"
android:textSize="20sp"
android:onClick="onButtonClicked"/>

</LinearLayout>
</LinearLayout>

※ 설명

- inputTyper 속성을 numberSigned로 지정하여 양수로 된 숫자만 입력할 수 있도록 만들어 둠

- 버튼은 눌렀을 때 MainActivity 클래스의 onButtonClicked 메서드가 호출되도록 onClick 속성을 설정

▼ 코드_MainActivitiy.java

더보기

package com.ogrg.sampletoast;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

EditText editText;
EditText editText2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

editText = findViewById(R.id.editText);
editText2 = findViewById(R.id.editText2);
}

public void onButton1Clicked(View v){
try{
Toast toastView = Toast.makeText(this,"위치가 바뀐 토스트 메시지입니다. ",Toast.LENGTH_LONG);
int xOffset = Integer.parseInt(editText.getText().toString());
int yOffset = Integer.parseInt(editText.getText().toString());

toastView.setGravity(Gravity.TOP|Gravity.TOP, xOffset, yOffset);
toastView.show();
}catch (NumberFormatException e){
e.printStackTrace();
}
}
}

 

※ 설명 

- xOffset 과 yOffset을 토스트의 위치를 지정하는 데 사용

- xOffset 과 yOffset의 범위는 dpi에 따라 달라질 수 있으며 픽셀 값으로 설정

 

 

■ 토스트 모양 바꿔 보여주기

- 토스트를 위한 layout를 정의한다면 LayoutInflater 객체를 이용해 직접 메모리에 객체화해야 한다.  

 

▼ 코드_activity_main.xml

더보기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<EditText
android:id="@+id/editText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:hint="X 위치"
android:inputType="numberSigned"
/>

<EditText
android:id="@+id/editText2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:hint="X 위치"
android:inputType="numberSigned"
/>

<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="띄우기"
android:textSize="20sp"
android:onClick="onButton1Clicked"
/>

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="모양 바꿔 띄우기"
android:onClick="onButton2Clicked"/>

</LinearLayout>
</LinearLayout>

▼ 코드_MainActivitiy.java

더보기

package com.ogrg.sampletoast;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

EditText editText;
EditText editText2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

editText = findViewById(R.id.editText);
editText2 = findViewById(R.id.editText2);
}

public void onButton1Clicked(View v){
try{
Toast toastView = Toast.makeText(this,"위치가 바뀐 토스트 메시지입니다. ",Toast.LENGTH_LONG);
int xOffset = Integer.parseInt(editText.getText().toString());
int yOffset = Integer.parseInt(editText.getText().toString());

toastView.setGravity(Gravity.CENTER|Gravity.CENTER, xOffset, yOffset);
toastView.show();
}catch (NumberFormatException e){
e.printStackTrace();
}
}

public void onButton2Clicked(View v){
LayoutInflater inflater = getLayoutInflater();

View layout = inflater.inflate(
R.layout.toastborder,
(ViewGroup) findViewById(R.id.toast_layout_root));
TextView text = layout.findViewById(R.id.text);

Toast toast = new Toast(this);
text.setText("모양 바꾼 토스트");
toast.setGravity(Gravity.CENTER,0,-100);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(layout);
toast.show();

}
}

 

- XML 레이아웃을 메모리에 로딩한다고 생각

- 대상이 되는 레이아웃의 이름이 R.layout.toastborder로 되어 있다.

- 새롭게 만들 토스트의 형태를 정의한 것

 

▼ 코드_toastborder.xml

더보기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toast_layout_root"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
>

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:textSize="32dp"
android:background="@drawable/abc_vector_test"
/>

</LinearLayout>

 

※ 설명 ※

- 레이아웃 안에 텍스트뷰 태그가 하나 정의되어 있고 그 id는 text로 되어있는데 토스트 뷰를 위한 레이아웃은 항상 이 형태로 정의되어야 한다. 

▼ 코드_toast.xml

더보기

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<stroke
android:width="4dp"
android:color="#ffffff00"
/>
<solid
android:color="#ff883300"
/>
<padding
android:left="20dp"
android:top="20dp"
android:right="20dp"
android:bottom="20dp"/>
<corners
android:radius="15dp"
/>
</selector>

 

※ 설명 ※

- 이렇게 정의한 XML 정보는 자바 코드의 setView() 메서드를 이용해 토스트 객체에 설정

■ 스낵바 보여주기

- 간단한 메세지를 보여줄 때는 스낵바를 사용

- 스낵바는 외부 라이브러리로 추가되었기 때문에 스낵바가 들어있는 디자인 라이브러리를 프로젝트에 추가해야 사용할 수 있다

 

- 외부 라이브러리를 추가하려면 [File] -[Project Structure...] 좌측 [Dependencies] 탭을 누른다. 

라이브러리 추가하는 법

 

■ 알림 대화상자 보여주기

- 사용자에게 확인을 받거나 선택하게 할 때 사용한다. 

- 입력을 받기보다는 일방적으로 메세질ㄹ 전달하는 역할, 예, 아니요 정도만

 

- AlertDialog 클래스는 알림 대화상자 보여주는 가장 단순한 방법을 제공 

 

03-5 프로그레스바 사용하기

■ 프로그레스바

- XML 레이아웃에 프로그래스바를 추가할 때는 <ProgressBar> 태그 사용

- 프로그레스바가 갖는 값의 최대 범위는 max 속성으로 설정하고 현재 값은 progress 속성으로 설정

 

- 프로그레스바를 XML 레이아웃에 추가하려면 단순히 태그를 <ProgressBar>로 만들어 주면 된다. 

 

 코드_MainActivitiy.java

더보기

package com.ogrg.sampleoproress;

import androidx.appcompat.app.AppCompatActivity;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends AppCompatActivity {
ProgressDialog dialog;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ProgressBar progressBar = findViewById(R.id.progressBar2);
progressBar.setIndeterminate(false);
progressBar.setProgress(80);

Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
dialog = new ProgressDialog(MainActivity.this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage("데이터를 확인하는 중입니다. ");

dialog.show();
}
});

Button button2 = findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener(){

@Override
public void onClick(View view){
if(dialog != null){
dialog.dismiss();
}
}
});
}
}

- 멈추지 않는 프로그레스바를 대화상자 안에서 보여주려면 ProgressDialog 객체를 하나 만들고 그 스타일을 ProgressDialog.STYLE_SPINNER로 설정

- 이렇게 만든 ProgressDialog 객체는 show() 메서드를 호출하면 화면에 표시 

- 어떤 이벤트가 발생했을 때 대화상자를 보이지 않게 하고 싶다면 dismiss() 메서드를 호출하면 된다. 

 


도전 05 두 종류의 버튼 모양 만들기

 

도전 06 시크바와 프로그레스바 보여주기

 

반응형


댓글