토스트
- 토스트는 간단한 메시지를 잠깐 보여주는 뷰로, 앱 위에 떠있는 뷰라고 할 수 있다.
- 토스트는 포커스를 받지 않으므로 쉽고 간단하게 사용가능하며 디버깅 목적으로 사용하기에도 용이.
<!--[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"
/>
<!-- 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="Y 위치"
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"/>
</LinearLayout>
</LinearLayout>
<!--[MainActivity.java]-->
package com.example.toast;
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;
import com.google.android.material.snackbar.Snackbar;
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_SHORT);
int xOffset = Integer.parseInt(editText.getText().toString());
int yOffset = Integer.parseInt(editText2.getText().toString());
toastView.setGravity(Gravity.TOP|Gravity.TOP, xOffset, yOffset);
toastView.show();
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
- makeText 메소드의 첫 번째 인자인 Context 객체는 일반적으로 Context 클래스를 상속한 액티비티를 사용할 수 있으며, 액티비티를 참조할 수 없는 경우에는 getApplicationContext() 메소드를 호출하면 Context 객체가 반환된다.
- 위의 코드는 토스트의 위치를 변경하여 출력하도록 하는 코드이다.
- 위치 변경을 위해 setGravity() 메소드를 사용하여 값을 설정하지만, Android R(11) 부터 text Toast는 설정 기능이 no-op가 되어 gravity나 margin을 customize 할 수 없게 되었다.
- 공식 문서에서도 Toast의 gravity나 margin 등을 임의로 지정하는 것을 말리는 추세이다.
- 대안으로는 text Toast를 simple Toast로 사용하여 gravity와 margin을 지정하는 방법이 있다.(아래 코드)
text Toast vs simple Toast: text Toast는 Toast.makeText 메소드를 이용하여 만드는
<!--[activity_main.xml]-->
<!--중략-->
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="모양 바꿔 띄우기"
android:onClick="onButton2Clicked"/>
<!--중략-->
<!--[MainActivity.java]-->
<!--중략-->
public void onButton2Clicked(View view) {
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toastborder, (ViewGroup) findViewById(R.id.toast_layout_root)); // XML로 정의된 레이아웃을 메모리에 객체화
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();
}
<!--중략-->
<!--[toastborder.xml]-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/toast_layout_root"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text"
android:padding="20dp"
android:textSize="32sp"
android:background="@drawable/toast"/>
</LinearLayout>
<!--[toast.xml]-->
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="4dp"
android:color="#ff487080"/>
<solid
android:color="#ff354000"/>
<padding
android:left="20dp"
android:top="20dp"
android:right="20dp"
android:bottom="20dp"/>
<corners
android:radius="15dp"/>
</shape>
- 위의 코드는 초기 코드에서 추가된 내용으로, 토스트의 위치와 모양까지 바꾼 simple Toast이다.
- LayoutInflater를 이용하여 xml로 정의된 layout을 메모리에 객체화 하고, Toast 클래스를 이용해 gravity를 지정하였다. Toast 클래스르로 따로 인스턴스를 만드는 것이 바로 simple Toast 방식이다.
- 코드의 순서는 다음과 같다.
[MainActivity.java 에서 toastborder.xml 을 객체화] -> [Toast가 생성될 toastborder.xml 의 TextView에서 background로 toast.xml을 지정] -> [toast.xml이 토스트의 모양과 색상 지정]
스낵바
- 스낵바는 외부 라이브러리로 추가되었기 때문에 스낵바가 들어 있는 Material Library를 프로젝트에 추가해야 함. 현재의 안드로이드 스튜디오 버전은 이를 미리 구비한 것으로 보임.
<!--[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">
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="스낵바 띄우기"
android:onClick="onButton3Clicked"/>
</LinearLayout>
<!--[MainActivity.java]-->
<!--중략-->
public void onButton3Clicked(View view) {
Snackbar.make(view, "스낵바입니다.", Snackbar.LENGTH_LONG).show();
}
<!--중략-->
- 스낵바는 화면 아래쪽에서 올라오기 때문에 아래쪽의 화면 일부분을 가리지만, 토스트와는 다른 방식이기에 사용자에게 선택지를 준다.
알림 대화상자
- 알림 대화상자는 사용자에게 확인을 받거나 선택하게 할 때 사용한다.
<!--[activity_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="버튼을 누르면 대화상자가 뜹니다."
android:textSize="25sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.248" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="띄우기"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="0.223" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!--[MainActivity.java]-->
package com.example.dialog;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
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);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
showMessage();
}
});
}
private void showMessage() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("안내");
builder.setMessage("종료하시겠습니까?");
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String message = "예 버튼이 눌렸습니다.";
textView.setText(message);
}
});
builder.setNeutralButton("취소", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String message = "취소 버튼이 눌렸습니다.";
textView.setText(message);
}
});
builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String message = "아니오 버튼이 눌렸습니다.";
textView.setText(message);
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}
- AlertDialog 클래스는 알림 대화상자를 보여주는 가장 단순한 방법을 제공한다.
- Dialog 클래스가 대화상자의 기본 클래스이지만, Dialog를 직접 인스턴스화 하려는 시도는 지양하는 것이 좋다. 대신하여 AlertDialog나 DatePickerDialog, TimePickerDialog 를 사용하는 것이 추천된다.
- setTitle() 메소드로 제목, setMessage() 메소드로 알림 내용, setIcon() 메소드로 안내 아이콘을 지정한다.
- PositiveButton, NegativeButton, NeutralButton 은 각각 하나씩만 존재 가능하며, 각 위치는 미리 지정되어 있다.
- 버튼의 모양, 위치, 색상을 커스터마이징하는 방법은 아래와 같다.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog alert = builder.create(); // Dialog를 만들어 객체를 가져옴.
alert.show(); // AlertDialog의 버튼은 Dialog가 동적으로 생성될 때 생성되기에 Dialog를 먼저 출력하는 것이 필요하다.
Button btn = alert.getButton(AlertDialog.BUTTON_POSITIVE); // 이후 Dialog에서 버튼을 임의로 가져온다.
<!--이후 btn.setTextColor, btn setBackground 등등...-->