1. CustomViewTest01
터치로 움직이고 중력이 작용하는 로봇 뷰 만들기
목표: 커스텀 뷰를 생성하여 터치한 위치로 이동하고, 가만히 두면 일정 간격으로 아래로 떨어지는 로봇 이미지를 구현하시오.
[세부 조건]
- 커스텀 뷰 구성: View를 상속받고 Runnable을 구현하는 RobotView 클래스를 만들어 XML 레이아웃에 배치한다. (로봇 이미지 자원: R.drawable.robot)
- 초기 위치 설정: 앱이 처음 실행될 때 로봇 이미지는 화면의 정중앙에 위치해야 한다.
- 터치 이벤트 (onTouchEvent): 화면을 터치하면, 로봇 이미지의 중심이 사용자가 터치한 좌표(X, Y)로 즉시 이동해야 한다.
- 스레드 애니메이션 (run): 별도의 스레드를 실행하여 0.5초(500ms)마다 로봇이 10픽셀씩 아래로 이동하게 만든다.
- 경계 처리: 스레드에 의해 로봇이 아래로 떨어질 때, 화면의 가장 아래쪽(바닥)을 벗어나지 않도록 처리한다.
▼결과화면

▼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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<kr.ac.dju.customviewtest01.RobotView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/RobotView">
</kr.ac.dju.customviewtest01.RobotView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
▼RobotView.java
package kr.ac.dju.customviewtest01;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;
import java.util.ResourceBundle;
public class RobotView extends View implements Runnable {
//멤버추가
private Drawable image;
private int viewWidth, viewHeight;
private int imageWidth, imageHeight;
private int x, y;
//생성자
public RobotView(Context context, @Nullable AttributeSet attrs) {
super (context, attrs);
image = ResourcesCompat.getDrawable(getResources(), R.drawable.robot, null);
Thread thread = new Thread(this);
thread.start();
}
//메소드 추가
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
image.setBounds(x,y,x+imageWidth,y+imageHeight);
image.draw(canvas);
}
//화면의 크기가 갱신되었을 때 호출되는 메소드
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
viewWidth = this.getWidth(); //전체화면 가로크기
viewHeight = this.getHeight(); //전체화면 세로
imageWidth = image.getIntrinsicWidth(); //그림의 가로크기
imageHeight = image.getIntrinsicHeight(); //그림의 세로크기
x = viewWidth/2 - imageWidth/2;
y = viewHeight/2 - imageHeight/2;
} //end of onSizeChanged
@Override
public boolean onTouchEvent(MotionEvent event) {
//1. 클릭시 중앙 정렬
x = (int)event.getX()-imageWidth/2;
y = (int)event.getY()-imageHeight/2;
// 2단계: 경계 클램핑
//x = Math.max(0, Math.min(x, viewWidth - imageWidth));
//y =
invalidate(); //onDraw()호출
//return super.onTouchEvent(event);
return true;
}
@Override
public void run(){
while (true){
try{
Thread.sleep(500);
y = Math.min(viewHeight - imageHeight, y + 10);
this.postInvalidate();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
▼MainActivity.java
package kr.ac.dju.customviewtest01;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
}
}
'[Android] 안드로이드' 카테고리의 다른 글
| [ 안드로이드 응용 ] 바운스 볼(공 튀기기) 구현하기 (0) | 2026.04.15 |
|---|---|
| [ 안드로이드 기본 ] 간단한 Thread 테스트 (0) | 2026.04.15 |
| [ 안드로이드 기본 ] 간단한 Handler 테스트 (0) | 2026.04.10 |
| [ 안드로이드 기본 ] 간단한 게임화면 구현 _ ScreenChange (1) | 2026.04.10 |
| [ 안드로이드 기본 ] Toast - setOnClickListener() , LogCat - 로그출력 (0) | 2026.04.10 |