11장포함
1배열
2아이템등록 menu.add 배열의 동적추가
리스트뷰
원본을 준비하고 원본의 형태에 맞는 어댑터 객체를 생성한다.
-ArrayAdapter(Context context, int text View ResourceId, List<T> object)


리스트뷰를 만드는 소스 main01,Mainactivity.java

11장의 리스트뷰의 다양한 모양 설정전까지
그래픽은 낼지안낼지미정 9장
다음주 1시까지
기말시험공부
어댑터뷰에서 데이터를 채우기 위해 사용하는 클래스는?
레디언트
안드로이드 어댑터뷰(AdapterView)에 데이터를 채우기 위해 사용하는 클래스는 바로 어댑터(Adapter) 클래스야! 😊
어댑터는 데이터를 관리하고, 이 데이터를 레이아웃과 결합해서 어댑터뷰에 표시할 뷰를 만들어 제공하는 역할을 해. 그래서 리스트뷰나 스피너 같은 곳에 데이터를 보여줄 때 꼭 필요한 존재지!
답변 출처
오전 3:13
오전 3:14
1.ArrayView<T> 2.ArrayData<T> 3.ArrayAdapter<T> 4.ArrayLis<T>중에 골라줘
레디언트
음! 그럼 제시된 보기들 중에서 골라줄게!
정답은 바로 3번, ArrayAdapter<T> 이야! ✨
ArrayAdapter는 이름에서도 알 수 있듯이, 배열이나 ArrayList 같은 데이터 소스에서 데이터를 가져와서 ListView나 Spinner 같은 AdapterView에 연결해주는 역할을 하거든. 딱 내가 전에 말했던 '어댑터'의 한 종류인 거지! ㅎㅎ
나머지 보기들은... ArrayView는 딱 맞는 표준 클래스가 아니고, ArrayData나 ArrayList는 데이터를 담는 자료구조지, 데이터를 어댑터뷰에 연결해주는 역할은 아니거든.
오전 3:14
오전 3:17
정답을 알려주고 해석해줘
레디언트
문제별 정답과 해석을 차례대로 알려줄게!
2번 문제
- 문제: 리스트뷰에 동적으로 추가·삭제하는 메소드
- 보기:
- add(), remove()
- append(), delete()
- add(), delete()
- append(), remove()
- 정답: 1) add(), remove()
- 해석: 리스트뷰와 연결된 데이터 리스트에서 아이템을 추가할 때는 add(), 삭제할 때는 remove() 메소드를 사용한다. append()나 delete()는 자바에서 일반적으로 쓰이지 않는다.
3번 문제
- 문제: AdapterView 클래스의 메소드 중 이미지 개수 반환 메소드와 각 칸마다 이미지뷰를 생성하는 메소드
- 보기:
- getCount(), getImageView()
- getNumber(), getView()
- getNumber(), getImageView()
- getCount(), getView()
- 정답: 4) getCount(), getView()
- 해석: AdapterView는 전체 아이템 개수를 getCount()로 반환하고, 각 칸에 보여줄 뷰를 생성하는 메소드는 getView()이다. getNumber()나 getImageView()는 표준 메소드가 아니다.
4번 문제
- 문제: 이미지뷰에서 이미지를 중앙에 배치하는 코드
- 보기:
- ImageView.setScaleType(ImageView.ScaleType.FIT_MIDDLE)
- ImageView.setScaleType(ImageView.ScaleType.FIT_CENTER)
- ImageView.setScaleType(ImageView.ScaleType.CENTER)
- ImageView.setScaleType(ImageView.ScaleType.MIDDLE)
- 정답: 3) ImageView.setScaleType(ImageView.ScaleType.CENTER)
- 해석: 이미지뷰에서 이미지를 중앙에 정확히 배치하려면 ScaleType.CENTER를 사용한다. FIT_CENTER는 너비와 높이에 맞춰 이미지를 조절하며, MIDDLE과 FIT_MIDDLE은 존재하지 않는 옵션이다.
필요할 때마다 더 알려줄게! ㅎㅎ
답변 출처
오전 3:18
오전 3:31
답을알려주고 해석해줘
레디언트
1~4번 문제 정답과 해석을 차례대로 알려줄게!
1번 문제
- 문제: 화면에 도형을 그릴 때 사용하는 클래스
- 보기:
- Canvas, Draw
- Canvas, Paint
- Graphic, Paint
- Graphic, Draw
- 정답: 2) Canvas, Paint
- 해석: 안드로이드에서 화면에 그림을 그릴 때는 Canvas 클래스로 실제 그리기 작업을 하고, Paint 클래스로 색상, 스타일 같은 속성을 설정한다.
2번 문제
- 문제: 화면을 손가락으로 터치했을 때 처리하는 메소드
- 보기:
- onTouchEvent
- onMoveEvent
- onFingerEvent
- onDragEvent
- 정답: 1) onTouchEvent
- 해석: 터치 이벤트를 처리하는 기본 메소드로, 손가락 터치를 감지하고 처리를 수행하는 역할을 한다.
3번 문제
- 문제: SD 카드의 이미지에 접근하기 위한 메소드
- 보기:
- BitmapFactory.decodeResource()
- BitmapFactory.decodeFile()
- Bitmap.decodeResource()
- Bitmap.decodeFile()
- 정답: 2) BitmapFactory.decodeFile()
- 해석: SD 카드에 저장된 이미지 파일 경로를 통해 이미지를 읽어들일 때는 BitmapFactory.decodeFile() 메소드를 사용한다. decodeResource()는 리소스 내 이미지를 읽을 때 쓴다.
4번 문제
- 문제: 이미지의 기하학적 변환 중 Canvas 클래스 메소드가 아닌 것
- 보기:
- 회전: rotate()
- 이동: translate()
- 확대/축소: zoom()
- 기울이기: skew()
- 정답: 3) 확대/축소: zoom()
- 해석: Canvas 클래스에는 rotate(), translate(), skew() 메소드가 있지만, 확대/축소는 scale() 메소드로 한다. zoom() 메소드는 없다.
필요하면 더 설명해줄게! ㅎㅎ
오전 3:31
오전 3:36
컬러 매트릭스를 회색영상으로 변환하는 메소드와 파라미터는?
레디언트
컬러 매트릭스를 회색영상(Grayscale)으로 변환하는 데 가장 흔히 쓰이는 메소드는 OpenCV 라이브러리의 cvtColor() 함수야.
이 함수는 입력 영상의 색 공간을 변환하는 데 사용하는데, 컬러 영상을 회색영상으로 변환할 때는 다음과 같은 파라미터를 사용해.
cpp
cvtColor(sourceImage, destinationImage, COLOR_BGR2GRAY);
- sourceImage: 원본 컬러 영상 (보통 BGR 형식)
- destinationImage: 변환된 회색영상이 저장될 객체
- COLOR_BGR2GRAY: BGR 컬러를 Grayscale로 변환하겠다는 플래그
이렇게 하면 BGR 3채널 컬러 이미지가 단일 채널의 회색조 영상으로 바뀌게 돼.
즉, cvtColor() 함수와 COLOR_BGR2GRAY 플래그가 컬러 매트릭스를 회색영상으로 바꾸는 표준적인 방법이다.
필요하면 사용 예제나 더 자세한 설명도 줄 수 있으니, 편하게 말해줘! ㅎㅎ
답변 출처
오전 3:36
오전 3:37
1.setSaturation(0) 2.setSaturation(1) 3.setSaturation(-1) 4.setSaturation(GRAY_SCALE) 중에 골라줘
레디언트
컬러 매트릭스를 이용해 회색영상(그레이스케일)으로 변환할 때 사용하는 메소드는 setSaturation()이고, 이 함수에 넘겨야 하는 값은 0이야.
즉, 정답은 1. setSaturation(0) 이다.
해석하자면, setSaturation(0)은 색상의 채도를 0으로 만들어 컬러가 모두 제거된 흑백 영상이 된다. 반면, 1은 원래 색 유지, -1이나 GRAY_SCALE 같은 값은 이 메소드에서 사용하지 않는 표현이다.
필요하면 코드 예시도 줄게! ㅎㅎ
답변 출처
오전 3:37
오전 3:58
답을알려주고 해석해줘
레디언트
문제별로 답과 해석을 차근차근 알려줄게!
1번 문제
- 문제: 메뉴 xml 파일의 내용 중 거리가 먼 것은?
- 보기:
- menu
- item
- id
- layout_width
- 정답: 4) layout_width
- 해석: 메뉴 XML 파일은 메뉴 구조와 항목을 정의하는데, menu, item, id는 메뉴 관련 태그나 속성이다. layout_width는 레이아웃 XML에서 사용하는 속성으로 메뉴 XML과 관련 없어서 거리가 먼 개념이다.
2번 문제
- 문제: "정적으로 존재하는 XML 파일을 Java 코드에서 접근하여 실제 객체로 만들어 사용하는 것"의 설명에 가장 알맞은 것은?
- 보기:
- Menu
- Overriding
- Inflater
- Item
- 정답: 3) Inflater
- 해석: Inflater는 XML 리소스 파일을 코드에서 객체로 변환해주는 기능이다. 즉, XML 레이아웃이나 메뉴 파일을 실제 자바 객체로 만들어 사용하는 과정에 관한 용어다.
3번 문제
- 문제: 옵션 메뉴를 등록하는 메소드
- 보기:
- onMakeOptionsMenu
- onCreateOptionsMenu
- onInflateOptionsMenu
- onSelectOptionsMenu
- 정답: 2) onCreateOptionsMenu
- 해석: 안드로이드에서 옵션 메뉴를 생성할 때 onCreateOptionsMenu() 메소드를 오버라이드하여 메뉴를 정의한다.
4번 문제
- 문제: 위젯에 컨텍스트 메뉴를 등록하는 메소드
- 보기:
- createForContextMenu
- setttingForContextMenu
- registerForContextMenu
- inflateForContextMenu
- 정답: 3) registerForContextMenu
- 해석: 특정 위젯에 컨텍스트 메뉴를 연결하려면 registerForContextMenu() 메소드를 호출해 등록한다.
5번 문제
- 문제: 여러 항목을 동시에 선택할 수 있는 대화상자를 생성하는 메소드
- 보기:
- setItems
- setSingleChoiceItems
- setMultiChoiceItems
- setSevralItems
- 정답: 3) setMultiChoiceItems
- 해석: 여러 개를 동시에 선택할 수 있게 하려면 setMultiChoiceItems()를 사용하고, 한 가지만 선택하려면 setSingleChoiceItems()를 쓴다.
필요하면 더 도움 줄게! ㅎㅎ
답변 출처
오전 3:59
오전 4:06
답을 알려주고 해석해줘
레디언트
1~5번 문제 정답과 해석을 차근차근 알려줄게!
1번 문제
- 문제: 시계를 표현하는 위젯이 바르게 짝지어진 것은?
- 보기:
- DataClock, TimeClock
- AnalogWatch, DigitalWatch
- AnalogTime, DigitalTime
- AnalogClock, DigitalClock
- 정답: 4) AnalogClock, DigitalClock
- 해석: 안드로이드에서 아날로그 시계 위젯은 AnalogClock, 디지털 시계 위젯은 DigitalClock이라는 클래스를 사용한다.
2번 문제
- 문제: CalendarView 위젯의 날짜 변경 시 작동하는 메소드
- 보기:
- setOnSelectedDayChange
- onPickDayChange
- onSelectedDayChange
- onChangedDaySelect
- 정답: 1) setOnSelectedDayChange
- 해석: setOnSelectedDayChange 메소드는 캘린더뷰에서 날짜가 선택됐을 때 그 변화를 감지해 동작하도록 설정하는 메소드다.
3번 문제
- 문제: 음량 조절이나 동영상 재생 시 위치를 지정하는 위젯은?
- 보기:
- ProgressBar
- SeekBar
- RatingBar
- SearchBar
- 정답: 2) SeekBar
- 해석: SeekBar는 사용자가 슬라이더를 움직여서 음량이나 재생 위치를 조절할 수 있는 위젯이다.
4번 문제
- 문제: “슬라이딩드로어의 ______ 속성에 지정된 이름과 슬라이딩드로어의 손잡이 역할을 하는 버튼의 아이디가 동일해야 한다.” 빈칸에 들어갈 알맞은 말은?
- 보기:
- content
- text
- gravity
- handle
- 정답: 1) content
- 해석: 슬라이딩 드로어에서 콘텐츠를 지정하는 content 속성 이름과 손잡이 역할을 하는 버튼의 아이디가 일치해야 한다.
5번 문제
- 문제: 액션바 탭을 클릭했을 때 동작하는 메소드
- 보기:
- onTabSelected
- onTabClicked
- onActionBarSelected
- onTabHostSelected
- 정답: 1) onTabSelected
- 해석: 탭이 선택되었을 때 호출되는 대표적인 콜백 메소드는 onTabSelected()이다.
소스코드
MainActivity.java
package com.example.project1120aa;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
LinearLayout baseLayout;
Button button1,button2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main01);
baseLayout = (LinearLayout) findViewById(R.id.baselayout);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
registerForContextMenu(button1);
registerForContextMenu(button2);
}
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater mInflater = getMenuInflater();
if (v == button1) {
menu.setHeaderTitle("배경색 변경");
menu.add(0, 1, 0, "배경색(빨강)");
menu.add(0, 2, 0, "배경색(초록)");
menu.add(0, 3, 0, "배경색(파랑)");
}
if (v == button2) {
menu.add(0, 4, 0, "버튼45도 회전");
menu.add(0, 5, 0, "버튼2배 확대");
}
}//onCreateContextMenu()
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == 1) {
baseLayout.setBackgroundColor(Color.RED);
return true;
} else if (item.getItemId() == 2) {
baseLayout.setBackgroundColor(Color.GREEN);
return true;
}else if (item.getItemId() == 3) {
baseLayout.setBackgroundColor(Color.BLUE);
return true;
}else if (item.getItemId() == 4) {
button2.setRotation(45);
return true;
}else if (item.getItemId() == 5) {
button2.setScaleX(2);
button2.setScaleY(2);
return true;
}
return super.onContextItemSelected(item);
}
} //Activity()
main01.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:id="@+id/baselayout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:text="배경색 변경"
android:textSize="30dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"
android:text="버튼 변경"
android:textSize="30dp"/>
</LinearLayout>

이 소스는 안드로이드 앱에서 **두 개의 버튼에 각각 다른 컨텍스트 메뉴(Context Menu)**를 등록하고, 메뉴에서 선택한 항목에 따라 배경색을 바꾸거나 버튼을 회전/확대하는 기능을 구현한 예제야. 차근차근 설명할게! 😊
1. XML 레이아웃(main01.xml) 설명
- LinearLayout (id: baselayout)
- 화면 전체를 세로 방향으로 배치하며, 자식 뷰들을 수평 중앙 정렬함(gravity="center_horizontal").
- 배경색을 변경할 대상이기도 함.
- Button 1 (id: button1, 텍스트: "배경색 변경")
- 사용자가 길게 눌러서 배경색 변경 메뉴를 호출할 버튼.
- Button 2 (id: button2, 텍스트: "버튼 변경")
- 이 버튼도 길게 눌러서 회전과 확대 메뉴를 호출할 수 있음.
2. MainActivity.java 주요 기능 분석
멤버 변수 선언
- baseLayout: XML의 LinearLayout 객체 (배경색 변경 대상)
- button1, button2: 각각 버튼 뷰 객체
onCreate() 메소드
- 레이아웃(main01.xml) 연결
- findViewById로 뷰 객체들 참조
- registerForContextMenu(button1)와 button2를 호출해 각 버튼에 컨텍스트 메뉴 등록
onCreateContextMenu() 메소드
- 사용자가 버튼을 길게 눌렀을 때 호출되는 메뉴 생성 부분
- if (v == button1)인 경우: 메뉴 제목을 "배경색 변경"으로 하고,
- 빨강, 초록, 파랑 배경색 메뉴 항목 추가 (ID 1~3)
- if (v == button2)인 경우:
- 버튼 45도 회전 (ID 4)
- 버튼 2배 확대 (ID 5) 메뉴 항목 추가
onContextItemSelected() 메소드
- 메뉴 항목을 선택했을 때 동작 정의
- 선택된 메뉴 ID에 따라:
- 1~3번: baseLayout 배경색을 빨강, 초록, 파랑 중 하나로 변경
- 4번: button2를 45도 회전
- 5번: button2를 가로/세로 2배 확대
- 처리 후 true를 반환해 이벤트 소비 완료 의미
3. 동작 흐름 요약
- 버튼 위에서 길게 누르면 컨텍스트 메뉴가 나타남
- 첫 번째 버튼에선 배경색 바꾸기 메뉴가 보임
- 두 번째 버튼에선 버튼 회전/확대 메뉴가 보임
- 메뉴 항목 선택시 지정 기능 실행 (배경색 변경, 버튼 모양 변형)
- UI가 즉시 반영되어 사용자에게 시각적 피드백 전달
4. 한줄 요약
이 코드는 두 개 버튼 각각에 컨텍스트 메뉴를 등록하여, 배경색 변경과 버튼 변형(회전, 확대)을 길게 누른 메뉴로 제어하는 기능을 구현한 안드로이드 예제이다.
1. 안드로이드에서 대화상자 작성하는 과정을 설명하시오.
대화상자(dialog)는 화면에 메시지를 나타낸 후 확인이나 취소 같은 사용자의 선택을 받아들이는 경우에 사용하는데 안드로이드에서 대화상자를 생성할 때는 AlertDialog.Builder 클래스를 주로 사용한다. 그리고 다양한 메소드를 이용하여 대화상자를 꾸민다. 최종적으로 show() 메소드를 대화상자를 화면에 출력하는데 예제(대화상자용 연습용 activity_main.xml 코드)
<LinearLayout
android:gravity=“center_horizontal”>
<Button
android:id=“@+id/button1”
android:text=“대화상자”/>
<LinearLayout>
알림 메세지만 출력하는 가장 기본적인 형태는 다음 예제와 같다. 버튼이 없으므로 키패드의 돌아가기 버튼을 클릭하면 대화 상자가 닫힌다.
대화상자를 생성하는 방법은 처음에 버튼을 먼저 import해준다.
final Button button1 = (Button) findViewById(R.id.button1);
그리고 버튼1을 setOnClickListener로 함수를 선언해준다.
button1.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
AlertDialog.Builder dlg = new AlertDialog.Builder(액티비티명.this);
dlg.setTitle(“제목입니다”);
dlg.setMessage(“이곳이 내용입니다”);
dlg.setIcon(R.mipmap.ic_launcher);
dlg.show();
} });
이렇게 해주면 대화상자를 작성할수 있다.
2. 안드로이드 옵션 메뉴에 대해 설명하시오.
안드로이드 옵션 메뉴는 말 그대로 앱 화면에서 사용할 수 있는 "선택 메뉴" 같은 것이빈다. 보통 액티비티(앱 화면)의 상단 앱 바(Action Bar)나 툴바에 뜨는 메뉴를 옵션 메뉴라고 부릅니다. 사용자가 어떤 기능을 실행하고 싶을 때 누르는 중요한 진입점 중 하나라고 할 수 있습니다.
옵션 메뉴를 만드는 방법은 크게 두 가지 단계로 나눌 수 있습니다.
1. 메뉴 초기화 (onCreateOptionsMenu):
• 이 함수는 액티비티가 처음 시작될 때 딱 한 번 호출된다. 그래서 메뉴와 관련된 초기 설정이나 구성을 할 때 사용합니다.
• getMenuInflater()를 통해 MenuInflater 객체를 얻어와서, 이 객체의 inflate() 함수를 호출하면 우리가 정의해 둔 메뉴 리소스(XML 파일)를 화면에 로드할 수 있습니다. 예를 들어 R.menu.main_menu 같은 파일이 있다면 그걸 액티비티에 띄우는 것입니다.
2. 메뉴 아이템 선택 처리 (onOptionsItemSelected):
• 사용자가 옵션 메뉴에서 특정 아이템을 선택했을 때 호출되는 함수입니다.
• 여기서 item.getItemId()를 사용해서 어떤 메뉴 아이템이 선택되었는지 확인하고, 그 아이템에 맞는 동작을 구현할 수 있습니다. 예를 들어, "설정" 메뉴를 누르면 설정 화면으로 이동하게 하거나, "저장" 메뉴를 누르면 데이터를 저장하는 등의 작업을 할 수 있습니다.
간단히 말하면, 앱 상단에 나오는 메뉴들을 만들고 싶을 때 옵션 메뉴를 사용하고, onCreateOptionsMenu에서 메뉴 모양을 만들고, onOptionsItemSelected에서 각 메뉴가 눌렸을 때 뭘 할지 정하는 거라고 생각하면 됩니다.
3. 안드로이드에서 그래픽을 구현하는 방법을 쓰시오.
그래픽을 표현할때는 View 클래스를 재정의하는 형태가 많이 사용된다.
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(new 재정의한 클래스 이름(this));
}
private static class 재정의한 클래스 이름 extends View {
public 재정의한 클래스 이름(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
//화면에 그려질 내용을 이곳에 코딩
}
}
나머지는 자동 완성되거나 고정된 내용이므로 밑줄 친 부분만 변경하면 된다. 그리고 캔버스와 페인트를 사용하여 화면에 나타낼 내용은 주석 부분에 코딩한다. 위의 틀을 잘 기억하면 그래픽예제는 쉬워진다.
4. (예를 들어 사각형을 그린다거나 선을 그리는 방법 등 ...)
사각형,원,선을 그리는 그림판 예제 소스를 예를 들어 설명해보았다.
package com.example.a0802613_a;
import static android.graphics.drawable.GradientDrawable.RECTANGLE;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
public class MainActivity extends AppCompatActivity {
final static int LINE = 1,CIRCLE = 2, RECTANGLE = 3;
static int curShape = LINE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
setTitle("이종윤 그림판");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0,1,0,"선그리기");
menu.add(0,2,0,"원그리기");
menu.add(0,3,0,"사각형 그리기");
return true;
}
public class MyGraphicView extends View {
int startX=-1,startY=-1,stopX=-1,stopY=-1;
public MyGraphicView(Context context){
super(context);
}//생성자
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startX=(int) event.getX();
startY=(int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
stopX = (int) event.getX();
stopY = (int) event.getY();
this.invalidate();
break;
}
return true;
}
protected void onDraw(@NonNull Canvas canvas){
super.onDraw(canvas);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
switch (curShape) {
case LINE:
canvas.drawLine(startX,startY,stopX,stopY,paint);
break;
case CIRCLE:
int radius = (int) Math.sqrt(Math.pow(stopX - startX, 2)
+ Math.pow(stopY - startY, 2));
canvas.drawCircle(startX,startY,radius,paint);
break;
case RECTANGLE:
Rect rect = new Rect(startX,startY,stopX,stopY);
canvas.drawRect(rect,paint);
break;
}
}
}//MyGraphicView()
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case 1:
curShape=LINE;//선
return true;
case 2:
curShape=CIRCLE;//원
return true;
case 3:
curShape=RECTANGLE;
return true;
}
return super.onOptionsItemSelected(item);//return false;와 동일
}
}//MainActivity()
1. MainActivity 클래스
앱의 메인 화면을 담당하는 곳
final static int LINE = 1,CIRCLE = 2, RECTANGLE = 3;:
여기서 LINE, CIRCLE, RECTANGLE이라는 상수를 정의, 각각 1, 2, 3이라는 값을 가지고 있고, 어떤 도형을 그릴지 구분하는 데 사용됩니다.
static int curShape = LINE;:
curShape는 "현재 선택된 도형"이라는 뜻인데, 처음에는 LINE (선)으로 초기화되어 있어, 앱이 시작되면 기본적으로 선을 그릴 수 있습니다.
protected void onCreate(Bundle savedInstanceState):
앱이 처음 실행될 때 호출되는 부분입니다.
setContentView(new MyGraphicView(this)); 이 부분은, MyGraphicView라는 사용자 정의 뷰를 화면에 띄우는 코드이고, 이 MyGraphicView에서 그림을 그리는 모든 동작이 일어납니다.
setTitle("이종윤 그림판"); 앱의 제목을 '이종윤 그림판'으로 설정,
public boolean onCreateOptionsMenu(Menu menu):
이건 앱 상단에 메뉴를 만들 때 호출됩니다.
menu.add(0,1,0,"선그리기"); 이렇게 세 개의 메뉴 아이템을 추가하고 있다.
1번은 "선그리기"
2번은 "원그리기"
3번은 "사각형 그리기"
이 아이템들을 누르면 어떤 도형을 그릴지 선택하게 된다.
public boolean onOptionsItemSelected(@NonNull MenuItem item):
사용자가 위에서 만든 메뉴 아이템들 중에서 하나를 선택했을 때 호출되는 부분,
switch (item.getItemId())를 사용해서 어떤 메뉴가 선택됐는지 확인하고 있습니다.
case 1: curShape=LINE;: 만약 "선그리기"를 선택하면 curShape 변수를 LINE으로 바꿔주고, 다음부터는 선이 그려지도록 하는 겁니다.
원과 사각형도 마찬가지로 curShape 값을 바꿔줘서, 다음에 터치 이벤트가 발생하면 해당 도형을 그리게 하는 겁니다.
2. MyGraphicView 이너 클래스
이 클래스는 실제 그림을 그리는 핵심적인 역할을 담당해. 우리가 종이에 그림을 그리는 것처럼, 이 View 위에서 그림을 그리는 겁니다.
int startX=-1,startY=-1,stopX=-1,stopY=-1;:
이 변수들은 사용자가 화면을 터치하고 드래그할 때 "시작점"(startX, startY)과 "끝점"(stopX, stopY)의 좌표를 저장하는 용도입니다. 그림을 그리려면 어디서부터 어디까지 그릴지 알아야 하니 그래서 -1로 초기화 해놓은거고,
public MyGraphicView(Context context):
MyGraphicView를 초기화하는 생성자입니다. 특별한 초기 설정은 없습니다.
public boolean onTouchEvent(MotionEvent event):
사용자가 화면을 터치했을 때 발생하는 이벤트를 처리하는 부분이야. 아주 중요해!
case MotionEvent.ACTION_DOWN:: 화면을 처음 눌렀을 때 (터치 시작).
startX와 startY에 현재 터치한 좌표를 저장해.
case MotionEvent.ACTION_MOVE: / case MotionEvent.ACTION_UP:: 화면에서 손가락을 움직이거나 (드래그) 손가락을 떼었을 때 (터치 끝).
stopX와 stopY에 현재 손가락의 좌표를 저장해.
this.invalidate(); 이게 정말 중요해! invalidate()는 "나 다시 그려줘!"라고 시스템에게 요청하는 함수야. 이 코드가 없으면 그림이 안 그려지거나 실시간으로 움직이는 걸 볼 수 없어. 터치 드래그가 끝나거나 움직일 때마다 onDraw 함수를 다시 호출해서 새로운 좌표에 맞게 그림을 갱신해주는 거지.
protected void onDraw(@NonNull Canvas canvas):
실제로 그림을 그리는 부분이야. invalidate()가 호출될 때마다 이 함수가 다시 실행돼.
Paint paint = new Paint();: Paint 객체는 붓이나 펜과 같다고 생각하면 돼. 색상, 선 두께, 스타일 등을 설정할 수 있어.
paint.setAntiAlias(true); 그림을 좀 더 부드럽게 보이게 해주는 옵션이야.
paint.setStrokeWidth(5); 선의 두께를 5로 설정.
paint.setStyle(Paint.Style.STROKE); 윤곽선만 그리도록 설정 (내부를 채우지 않음).
paint.setColor(Color.RED); 선의 색깔은 빨강!
switch (curShape): 여기서 MainActivity에서 선택한 curShape 값에 따라 다른 도형을 그리는 거야.
case LINE:: canvas.drawLine(startX,startY,stopX,stopY,paint); 시작점과 끝점을 이어서 선을 그려줘.
case CIRCLE::
radius (반지름)를 계산하는 코드가 보이네. Math.sqrt(Math.pow(stopX - startX, 2) + Math.pow(stopY - startY, 2)); 이건 두 점 사이의 거리를 계산하는 피타고라스 정리 공식이야! (루트((x2-x1)^2 + (y2-y1)^2))
canvas.drawCircle(startX,startY,radius,paint); 시작점을 원의 중심으로 하고 계산된 반지름으로 원을 그려줘.
case RECTANGLE::
Rect rect = new Rect(startX,startY,stopX,stopY); 시작점과 끝점을 이용해서 직사각형 영역을 만들어.
canvas.drawRect(rect,paint); 그 영역에 사각형을 그려줘.
소스코드 MainActivity.java
package com.example.project_1204a;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
TextView tvName, tvEmail,tvFood,tvPlace;
Button button1,button2,button3;
EditText dlgEdtName, dlgEdtEmail,dlgEdtFood,dlgEdtplace;
View dialogView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main01);
setTitle("202208026이종윤");
tvName = findViewById(R.id.tvName);
tvEmail = findViewById(R.id.tvEmail);
button1 = findViewById(R.id.button1);
button2 = findViewById(R.id.button2);
button3 = findViewById(R.id.button3);
tvFood = findViewById(R.id.tvFood);
tvPlace = findViewById(R.id.tvPlace);
button1.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
dialogView = (View) View.inflate(MainActivity.this,R.layout.dialog01, null);
AlertDialog.Builder dlg = new AlertDialog.Builder(MainActivity.this);
dlg.setTitle("사용자 정보 입력");
dlg.setView(dialogView);
dlg.setPositiveButton("확인", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dlgEdtName = dialogView.findViewById(R.id.dlgEdt1);
dlgEdtEmail = dialogView.findViewById(R.id.dlgEdt2);
tvName.setText(dlgEdtName.getText());
tvEmail.setText(dlgEdtEmail.getText());
}
});
dlg.setNegativeButton("취소", null);
dlg.show();
}
});
button2.setOnClickListener(new View.OnClickListener(){
public void onClick(View view) {
dialogView = (View) View.inflate(MainActivity.this,R.layout.dialog02, null);
AlertDialog.Builder dlg = new AlertDialog.Builder(MainActivity.this);
dlg.setTitle("이종윤 정보 입력");
dlg.setView(dialogView);
dlg.setPositiveButton("YES!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dlgEdtFood = dialogView.findViewById(R.id.dlgEdt3);
dlgEdtplace = dialogView.findViewById(R.id.dlgEdt4);
tvFood.setText(dlgEdtFood.getText());
tvPlace.setText(dlgEdtplace.getText());
}
});
dlg.setNegativeButton("NO!", null);
dlg.show();
}
});
}
}
main01.xml소스코드
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvName"
android:text="사용자 이름"
android:textSize="25dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvEmail"
android:text="이메일"
android:textSize="25dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvFood"
android:text="좋아하는음식"
android:textSize="25dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvPlace"
android:text="가고싶은장소"
android:textSize="25dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:text="여기를 클릭"
android:textSize="25dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"
android:text="my favorit"
android:textSize="30dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button3"
android:text="색상변경"
android:textSize="20dp"/>
</LinearLayout>
레디언트
이 코드는 안드로이드 앱에서 사용자 정보와 좋아하는 음식, 가고 싶은 장소 등을 입력받기 위해 두 가지 다이얼로그를 띄우고, 입력한 내용을 화면에 보여주는 기능을 구현한 예제야. 각 XML 레이아웃과 Java 코드를 차근차근 설명할게!
1. 레이아웃 파일 main01.xml 설명
- LinearLayout (수직 방향, 중앙 정렬) 내에 다음 요소들이 있어
- TextView 4개 : 사용자 이름, 이메일, 좋아하는 음식, 가고 싶은 장소 정보를 보여줌
- Button 3개 :
- button1 ("여기를 클릭") → 첫 번째 다이얼로그 호출
- button2 ("my favorit") → 두 번째 다이얼로그 호출
- button3 ("색상변경") → 현재 코드에서는 미사용 상태
2. MainActivity.java 주요 기능 설명
변수와 뷰 연결
- TextView 4개 (tvName, tvEmail, tvFood, tvPlace) → 화면에 사용자 정보 표시용
- Button 3개 (button1, button2, button3) → 버튼 이벤트용
- EditText 변수 (다이얼로그 안의 입력 필드 참조 시 사용)
- View dialogView → 다이얼로그에 입힐 레이아웃 뷰 객체
다이얼로그 1 (button1 클릭 시)
- XML 파일 dialog01 (코드상에 선언됨, 다이얼로그 레이아웃)
- 사용자로부터 이름과 이메일을 입력받는 폼
- AlertDialog를 만들어
- 제목은 "사용자 정보 입력"
- 다이얼로그 뷰를 dialog01 레이아웃으로 설정
- 확인 버튼 클릭 시: 입력한 이름과 이메일을 TextView(tvName, tvEmail)에 설정
- 취소 버튼 클릭 시는 아무 동작 없음
다이얼로그 2 (button2 클릭 시)
- XML 파일 dialog02 (역시 다이얼로그 레이아웃)
- 사용자로부터 좋아하는 음식과 가고 싶은 장소 입력 받는 폼
- AlertDialog 생성 및 설정
- 제목은 "이종윤 정보 입력"
- 뷰는 dialog02 레이아웃
- YES 버튼 클릭 시: 입력한 음식과 장소 정보를 tvFood, tvPlace에 반영
- NO 버튼 클릭 시는 아무 동작 없음
현재 코드에서 button3은 클릭 리스너나 기능이 없어서 미구현 상태
3. 요약 및 전반적 동작 흐름
- 첫 번째 버튼 클릭하면 이름/이메일 입력 다이얼로그가 뜬다
- 입력 후 확인 누르면 화면에 이름과 이메일이 표시된다
- 두 번째 버튼 클릭하면 음식/장소 입력 다이얼로그가 뜬다
- 입력 후 YES 누르면 해당 정보가 화면에 보여진다
- 세 번째 버튼은 아직 기능 미구현 상태
- 각 다이얼로그는 사용자 입력을 받아 UI에 반영하는 역할을 한다

dialog01.xml소스코드
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="사용자 이름"
android:textSize="20dp"/>
<EditText
android:id="@+id/dlgEdt1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이메일"
android:textSize="20dp"/>
<EditText
android:id="@+id/dlgEdt2"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
dialog02.xml소스코드
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="좋아하는 음식은?"
android:textSize="20dp"/>
<EditText
android:id="@+id/dlgEdt3"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="가고싶은 장소는?"
android:textSize="20dp"/>
<EditText
android:id="@+id/dlgEdt4"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
1. dialog01.xml 설명
- 전체 구조: 세로 방향(vertical) LinearLayout
- 내용:
- TextView: "사용자 이름"을 표시하는 텍스트 (글자 크기 20dp)
- EditText (id: dlgEdt1): 사용자로부터 이름 입력 받는 텍스트 입력창
- TextView: "이메일" 텍스트 (20dp)
- EditText (id: dlgEdt2): 이메일 입력창
역할
dialog01.xml은 사용자로부터 이름과 이메일을 입력받기 위한 다이얼로그 뷰 레이아웃을 정의해.
MainActivity에서 이 레이아웃을 불러와 다이얼로그 안에 띄우고, 사용자가 텍스트를 입력할 수 있도록 한다.
2. dialog02.xml 설명
- 전체 구조: 마찬가지로 LinearLayout (세로)
- 내용:
- TextView: "좋아하는 음식은?" 텍스트
- EditText (id: dlgEdt3): 좋아하는 음식 입력창
- TextView: "가고싶은 장소는?" 텍스트
- EditText (id: dlgEdt4): 가고 싶은 장소 입력창
역할
dialog02.xml은 사용자가 좋아하는 음식과 가고 싶은 장소를 입력할 수 있도록 만든 다이얼로그 레이아웃이다.
역시 MainActivity에서 이 레이아웃을 불러와 다이얼로그로 보여준 뒤, 입력값을 받아 화면에 출력하는 용도로 쓰인다.
전체 요약
- 두 다이얼로그 레이아웃 모두 LinearLayout(세로 방향) 기반
- TextView로 질문/라벨 역할
- EditText로 사용자 입력 받음
- 각각 사용자 정보와 취향을 입력받기 위한 간단하고 직관적인 UI 구성
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main01);
Button button1=findViewById(R.id.button);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Toast.makeText(getApplicationContext(),"무명의 내부 클래스로 작성한 Toast",
Toast.LENGTH_SHORT).show();
}
});
}
}
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main01);
Button button1 = findViewById(R.id.button);
button1.setOnClickListener(new MyClickListener());
}
class MyClickListener implements View.OnClickListener{
@Override
public void onClick(View view){
Toast.makeText(view.getContext(),"내부 클래스로 작성한 Toast",
Toast.LENGTH_SHORT).show();
}
}
// super.onCreate(savedInstanceState);
// setContentView(R.layout.main01);
// Button button1=findViewById(R.id.button);
// button1.setOnClickListener(new View.OnClickListener(){
// @Override
// public void onClick(View view){
// Toast.makeText(getApplicationContext(),"무명의 내부 클래스로 작성한 Toast",
// Toast.LENGTH_SHORT).show();
// }
}
mainActivity 2번째 방법
안드로이드에서 버튼 클릭 시 토스트 메시지를 띄우는 두 가지 방식의 Java 코드 예제를 주셨네요. 하나는 무명(익명) 내부 클래스를 이용한 방법, 또 하나는 명시적인 내부 클래스를 이용한 방법입니다. 각 소스와 차이, 동작 방식을 쉽게 설명해줄게요! 😊
1. 두 소스 공통점
- setContentView(R.layout.main01);에서 main01.xml 레이아웃을 사용
- Button 뷰를 findViewById(R.id.button)으로 찾아서 이벤트를 처리함
- 버튼 클릭 시 Toast 메시지를 띄워 사용자에게 클릭 사실을 알려줌
2. 첫 번째 소스 (무명 내부 클래스)
java
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view){
Toast.makeText(getApplicationContext(),"무명의 내부 클래스로 작성한 Toast", Toast.LENGTH_SHORT).show();
}
});
- 특징
- 버튼 클릭 리스너를 new View.OnClickListener() 익명 클래스로 직접 생성
- 간단하고 한 번만 쓰일 이벤트에 적합
- 코드가 비교적 간결함
- 동작
- 클릭 시 getApplicationContext()를 Context로 사용해 토스트 메시지를 띄움
3. 두 번째 소스 (명시적 내부 클래스)
java
button1.setOnClickListener(new MyClickListener());
class MyClickListener implements View.OnClickListener {
@Override
public void onClick(View view) {
Toast.makeText(view.getContext(),"내부 클래스로 작성한 Toast", Toast.LENGTH_SHORT).show();
}
}
- 특징
- 별도의 내부 클래스 MyClickListener를 만들어 이벤트 리스너 구현
- 재사용 가능하고 여러 뷰에 동일 리스너를 적용할 때 유리
- 코드가 조금 더 길고 구조적
- 동작
- 클릭 시 이벤트가 발생한 뷰의 Context를 사용해 토스트 메시지 띄움
4. 차이와 선택 기준
구분무명 내부 클래스명시적 내부 클래스| 코드 분량 | 짧고 직접적 | 길고 구조적 |
| 재사용성 | 적음 | 좋음 |
| 가독성 | 간단한 경우 좋음 | 큰 프로젝트에서 관리 편리 |
| Context 전달 방식 | getApplicationContext() | 클릭된 뷰의 getContext() 사용 |
| 사용처 | 단발성, 간단한 이벤트 처리 | 여러 버튼이나 뷰의 이벤트 재사용할 때 |
5. XML 레이아웃에서 필요한 태그 (간단 예시)
xml
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="클릭하기"/>
button 아이디를 가진 버튼이 있어야 위 자바 코드에서 findViewById(R.id.button)로 찾을 수 있습니다.
요약
- 두 코드는 모두 버튼 클릭 시 토스트 메시지를 보여주는 기능 구현
- 무명 내부 클래스는 즉석에서 사용할 때 손쉽고 편함
- 명시적 내부 클래스는 재사용성 및 유지보수를 고려할 때 좋음
- 상황과 선호에 따라 선택하면 되며, 기능상 차이는 거의 없음