1. a017_lacation 모듈
1) Main3Activity 액티비티, activity_main3 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a017_location">
<!-- 위치 정보 권한 획득 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 인터넷 사용 권한 획득 -->
<uses-permission android:name="android.permission.INTERNET" />
<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=".Main3Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?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"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GeoCoder"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tvLatitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="위도"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etLatitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal"
android:text="37.566767" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tvLongitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="경도"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etLongitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal"
android:text="126.978370" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnGeoCoder1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="GeoCoder" />
<Button
android:id="@+id/btnMap1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="지도보기" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="주소"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etAddress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:text="강남역">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnGeoCoder2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="GeoCoder" />
<Button
android:id="@+id/btnMap2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="지도보기" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="28dp"
android:text="조회한 주소정보 출력"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
</ScrollView>
</LinearLayout>
package com.lec.android.a017_location;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.IOException;
import java.util.List;
/** 지오코딩(GeoCoding) : 주소,지명 => 위도(latitude),경도(longitude) 좌표로 변환하는 구글 서비스
* 위치정보를 얻기위한 권한을 획득 필요, AndroidManifest.xml
* ACCESS_FINE_LOCATION : 현재 나의 위치를 얻기 위해서 필요함
* INTERNET : 구글서버에 접근하기위해서 필요함
*/
public class Main3Activity extends AppCompatActivity {
TextView tvResult;
EditText etLatitude, etLongitude;
EditText etAddress;
Button btnGeoCoder1, btnGeoCoder2;
Button btnMap1, btnMap2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
tvResult = findViewById(R.id.tvResult); // 결과창
btnGeoCoder1 = findViewById(R.id.btnGeoCoder1);
btnGeoCoder2 = findViewById(R.id.btnGeoCoder2);
btnMap1 = findViewById(R.id.btnMap1);
btnMap2 = findViewById(R.id.btnMap2);
etLatitude = findViewById(R.id.etLatitude);
etLongitude = findViewById(R.id.etLongitude);
etAddress = findViewById(R.id.etAddress);
// 지오코딩
final Geocoder geocoder;
geocoder = new Geocoder(this);
btnGeoCoder1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 위도, 경도 입력 후 주소정보 변환
double lat = Double.parseDouble(etLatitude.getText().toString());
double lng = Double.parseDouble(etLongitude.getText().toString());
List<Address> list = null; // 주소 정보를 담을 리스트
try {
list = geocoder.getFromLocation(
lat, // 위도
lng, // 경도
10); // 얻어올 결과값의 최대 개수
} catch (IOException e) {
e.printStackTrace();
Log.e("myapp", "입출력 오류 - 서버에서 주소 변환시 에러 발생");
}
if(list != null) {
if(list.size() == 0) {
tvResult.setText("해당되는 주소 정보가 없습니다.");
} else {
StringBuffer result = new StringBuffer(list.size() + "개의 결과\n");
for (Address addr : list) {
result.append("--------------------------------\n");
result.append(addr.toString() + "\n");
}
tvResult.setText(result);
}
}
}
});
btnGeoCoder2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 지명, 주소
String str = etAddress.getText().toString();
List<Address> list = null; // 주소 정보를 담을 리스트
try {
list = geocoder.getFromLocationName(
str, // 지명이름
10); // 얻어올 결과값의 최대 개수
} catch (IOException e) {
e.printStackTrace();
Log.e("myapp", "입출력 오류 - 서버에서 주소 변환시 에러 발생");
}
if(list != null) {
if(list.size() == 0) {
tvResult.setText("해당되는 주소 정보가 없습니다.");
} else {
StringBuffer result = new StringBuffer(list.size() + "개의 결과\n");
for (Address addr : list) {
result.append("--------------------------------\n");
result.append(addr.getCountryName() + ", "
+ addr.getFeatureName() + ", "
+ addr.getLocality() + ", "
+ addr.getLatitude() + ", "
+ addr.getLongitude());
}
tvResult.setText(result);
}
}
}
});
btnMap1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 위도, 경도 입력 후 지도 버튼 클릭 -> 지도 앱 화면으로 묵시적 인텐드 날리기
double lat = Double.parseDouble(etLatitude.getText().toString());
double lng = Double.parseDouble(etLongitude.getText().toString());
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + lat + "," + lng));
startActivity(intent);
}
});
btnMap2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 지명, 주소
String str = etAddress.getText().toString();
List<Address> list = null; // 주소 정보를 담을 리스트
try {
list = geocoder.getFromLocationName(
str, // 지명이름
10); // 얻어올 결과값의 최대 개수
} catch (IOException e) {
e.printStackTrace();
Log.e("myapp", "입출력 오류 - 서버에서 주소 변환시 에러 발생");
}
if(list != null) {
if(list.size() == 0) {
tvResult.setText("해당되는 주소 정보가 없습니다.");
} else {
// 해당되는 주소의 위치 좌표로 묵시적 인텐트를 날리기(지도앱)
Address addr = list.get(0);
double lat = addr.getLatitude();
double lng = addr.getLongitude();
String uri = String.format("geo:%f, %f:", lat, lng);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
startActivity(intent);
}
}
}
});
} // end onCreate()
} // end Activity
2) Main4Activity 액티비티, activity_main4 레이아웃
[추가] 구글맵 v2.0을 사용하기 위해 필요한 작업
① GoogleMap API Key 받기( https://cloud.google.com/maps-platform/ )
② Android SDK 에서 SDK Tools 에서 Google Play services 가 다운되어 있는지 확인하기
③ build.gradle 파일에 dependencies 에
implementation 'com.google.android.gms:play-services-maps:17.0.0' 추가
④ GoogleMap API Key는 트래픽 당 과금이 되기 때문에
별도의 파일로 따로 만들어서 GitHub에 올라가지 않도록 설정한다
[GitHub를 확인해보면] api.xml이 올라가지 않은 것을 볼 수 있다...!!
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a017_location">
<!-- 위치 정보 권한 획득 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 인터넷 사용 권한 획득 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- GoogleMap 2.0 에 필요한 설정 추가
자신의 패키지명.MAPS_RECEIVE
자신의 패키지명.permission.MAPS_RECEIVE -->
<permission android:name="com.lec.android.017_location.MAPS_RECEIVE" android:protectionLevel="signature" />
<uses-permission android:name="com.lec.android.a017_location.permission.MAPS_RECEIVE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- OpenGL 사용 : GoogleMap 2.0 은 OpenGL 사용 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<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">
<uses-library android:name="com.google.android.maps" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<meta-data android:name="com.google.android.maps.v2.API_KEY"
android:value="@string/api_key" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<activity android:name=".Main4Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main3Activity" />
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?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=".Main4Activity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GoogleMap 2.0"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="위도"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etLatitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal"
android:text="37.566767" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="경도"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="@+id/etLongitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="numberDecimal"
android:text="126.978370" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnMap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="지도이동" />
<Button
android:id="@+id/btnMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="마커" />
<EditText
android:id="@+id/etMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName"
android:text="서울시청" />
</LinearLayout>
<!-- GoogleMap 을 사용하기 위해서는
SupportMapFragment 를 사용한 fragment 필요 -->
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
package com.lec.android.a017_location;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
/** 구글맵 v2.0 서비스 사용하기
* 1. Play Service 라이브러리 추가
* 2. 메니페스트에 권한, 각종 설정추가 :
* 3. 구글맵 API key 발급 받아 메니페스트에 추가
* 4. XML 에 MapFragment 추가 <-- 지도표시용 Fragment
* SupportMapFragment 객체로 사용
* 5. GoogleMap 객체를 사용하여 지도 조작
*
*/
public class Main4Activity extends AppCompatActivity {
// GoogleMap 2.0
GoogleMap map;
SupportMapFragment mapFragment;
MarkerOptions myLocationMarker; // 마커(오버레이 개체)
Button btnMap;
Button btnMarker;
EditText etLatitude;
EditText etLongitude;
EditText etMarker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
btnMap = findViewById(R.id.btnMap);
btnMarker = findViewById(R.id.btnMarker);
etLatitude = findViewById(R.id.etLatitude);
etLongitude = findViewById(R.id.etLongitude);
etMarker = findViewById(R.id.etMarker);
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(new OnMapReadyCallback() {
// 지도가 준비되면 호출되는 콜백
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d("myapp", "지도 준비됨");
map = googleMap;
}
});
MapsInitializer.initialize(this);
// 버튼 누르면 입력된 좌표로 GoogleMap 이동
btnMap.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startLocationService();
}
});
// 입력된 좌표 위에 마커 생성
btnMarker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
double lat = Double.parseDouble(etLatitude.getText().toString());
double lng = Double.parseDouble(etLongitude.getText().toString());
LatLng curPoint = new LatLng(lat, lng);
MarkerOptions markerOptions = new MarkerOptions()
.position(curPoint)
.title(etMarker.getText().toString().trim() + "\n")
.snippet("★" + String.format("%.3f %.3f", lat, lng));
map.addMarker(markerOptions);
}
});
} // end onCreate()
public void startLocationService() {
double lat = Double.parseDouble(etLatitude.getText().toString());
double lng = Double.parseDouble(etLongitude.getText().toString());
LatLng curPoint = new LatLng(lat, lng);
map.animateCamera(CameraUpdateFactory.newLatLngZoom(curPoint, 15));
} // end startLocationService
} // end Activity
2. a018_touch 모듈
1) MainActivity 액티비티, activity_main 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a018_touch">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Touch Event"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TextView
android:id="@+id/tvSummry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="16dp"
android:text="터치이벤트 - 버튼에 손을 대 보세요"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/btnTouch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tvTitle"
android:layout_below="@+id/tvTitle"
android:layout_marginTop="26dp"
android:text="나 버튼임" />
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/btnTouch"
android:layout_below="@+id/btnTouch"
android:layout_marginTop="120dp"
android:text="결과창"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
package com.lec.android.a018_touch;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
TextView tvResult;
Button btnTouch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvResult = (TextView)findViewById(R.id.tvResult);
btnTouch = (Button)findViewById(R.id.btnTouch);
btnTouch.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // 버튼이 눌렸을때
tvResult.setText("ACTION_DOWN : 눌렸습니다.");
break;
case MotionEvent.ACTION_MOVE: // 버튼을 누른 상태에서 움직이고 있을때
tvResult.setText("ACTION_MOVE : 움직이고 있습니다.");
break;
case MotionEvent.ACTION_UP: // 버튼에서 손을 떼었을때
tvResult.setText("ACTION_UP : 손을 떼었습니다.");
break;
}
// 이벤트 처리를 여기서 완료하고
// 다른 곳에 이벤트를 넘기지 않도록
// 리턴값을 true 로 준다. (consume)
return true;
}
});
} // end onCreate()
} // end Activity
2) Main2Activity 액티비티, activity_main2 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a018_touch">
<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=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout1"
android:background="#FF5722"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="화면을 터치하면 로봇이 움직입니다"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<ImageView
android:id="@+id/ivRobot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
package com.lec.android.a018_touch;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class Main2Activity extends AppCompatActivity {
ImageView ivRobot;
LinearLayout ll;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ivRobot = findViewById(R.id.ivRobot);
ll = findViewById(R.id.linearLayout1);
ll.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// 이미지 뷰의 위치 옮기기
ivRobot.setX(event.getX());
ivRobot.setY(event.getY());
} // end switch
return true;
}
});
} // end onCreate()
} // and Activity
3) Main3Activity 액티비티, activity_main3 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a018_touch">
<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=".Main3Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
<?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=".Main2Activity">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MultiTouch"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="결과값" />
</LinearLayout>
package com.lec.android.a018_touch;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.TextView;
public class Main3Activity extends AppCompatActivity {
TextView tvResult;
// 3개까지의 멀티터치를 다루기 위한 배열
int[] id = new int[3];
int[] x = new int[3];
int[] y = new int[3];
String result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
tvResult = findViewById(R.id.tvResult);
} // end onCreate()
// 액티비티에서 발생한 터치 이벤트 처리
@Override
public boolean onTouchEvent(MotionEvent event) {
int pointCount = event.getPointerCount(); // 현재 터치 발생한 포인트 개수를 얻어 온다.
if(pointCount > 3) {pointCount = 3;} // 3개 이상의 포인터들은 3개까지만 처리
// 즉 여러개의 손가락을 올려도 3개까지만 인정한다는 뜻..!!
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: // 한 개 포인터에 대해 DOWN 이 발생했을때
id[0] = event.getPointerId(0); // 터치한 순간에 부여되는 포인트 고유번호
x[0] = (int)(event.getX());
y[0] = (int)(event.getY());
result = "싱글터치 : \n";
result += "(" + x[0] + ", " + y[0] + ")";
break;
case MotionEvent.ACTION_POINTER_DOWN: // 두 개 이상의 포인트에 대한 DOWN 이 발생했을때
result = "멀티터치 : \n";
for(int i = 0; i < pointCount; i++) {
id[i] = event.getPointerId(i);
x[i] = (int)(event.getX(i));
y[i] = (int)(event.getY(i));
result += "id[" + id[i] + "] (" + x[i] + ", " + y[i] + ")\n";
}
break;
case MotionEvent.ACTION_MOVE:
result = "멀티터치 move : \n";
for(int i = 0; i < pointCount; i++) {
id[i] = event.getPointerId(i);
x[i] = (int)(event.getX(i));
y[i] = (int)(event.getY(i));
result += "id[" + id[i] + "] (" + x[i] + ", " + y[i] + ")\n";
}
break;
case MotionEvent.ACTION_UP:
result = "";
break;
} // end switch
tvResult.setText(result);
return super.onTouchEvent(event);
} // end onTouchEvent()
} // end Activity
3. a023_camera 모듈
1) MainActivity 액티비티, activity_main 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a023_camera">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera"
android:required="true"/>
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 앱 간의 파일 공유를 위한 Content Provider -->
<provider
android:authorities="org.techtown.capture.intent.fileprovider"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<!-- 파일 공유 경로 지정 -->
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/external" />
</provider>
</application>
</manifest>
<?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">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Camera Intent"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="사진찍기" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="@mipmap/ic_launcher" />
</LinearLayout>
package com.lec.android.a023_camera;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
/* 오늘날 스마트폰의 카메라 용도
단순 사진 촬영을 넘어, 바코드, 문자 인식, AR (증각현실)등 광범위하게 사용
카메라로 사진찍는 방법 2가지
방법 1. Intent 로 단말기의 앱 실행한후 촬영결과 받아와서 처리하기
방법 2. 앱 화면에 직접 카메라 미리 보기 실행후 직접 사진 촬영하여 처리하기
-------------------------------------------------------------------------
방법 1. Intent 로 단말기의 앱 실행한후 촬영결과 받아와서 처리하기
메니페스트 설정 :
CAMERA, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE
uses-feature 세팅
저장 경로 설정하기 : external-path 리소스 사용
ContentProvider 세팅 : FILE_PROVIDER_PATHS 설정
권한 획득하기 (API23+)
인텐트 생성 MediaStore.ACTION_IMAGE_CAPTURE
인텐트에 저장 경로 세팅 : MediaStore.EXTRA_OUTPUT
-------------------------------------------------------------------------
참고]
안드로이드 7.0 부터는 file:// 로 시작하는 Uri 정보를 다른 앱에서는 접근 불가
반드시 content:// 로 시작하는 내용제공자 를 사용하도록 바뀌었슴!
*/
public class MainActivity extends AppCompatActivity {
String [] permissions = {Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};
final int REQUEST_CODE = 101;
ImageView imageView;
File file; // 촬영한 이미지 파일
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 권한 획득
if(Build.VERSION.SDK_INT >= 23){
if(checkSelfPermission(String.valueOf(permissions)) == PackageManager.PERMISSION_DENIED){
requestPermissions(permissions, REQUEST_CODE); // 권한 요청하기
}
}
imageView = findViewById(R.id.imageView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 촬영
takePicture();
}
});
} // end onCreate()
public void takePicture(){
if(file == null){
file = createFile();
}
// 위 File 객체로부터 Uri 객체 만들기
Uri fileUri = FileProvider.getUriForFile(this,
"org.techtown.capture.intent.fileprovider",
file);
// 사진 촬영 앱 가동 (묵시적 인텐트)
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// 위 액티비티가 가용한지 여부 체크한뒤.
if(intent.resolveActivity(getPackageManager()) != null){
startActivityForResult(intent, 101); // 사진 촬영 앱!
}
}
private File createFile(){
String fileName = "capture.jpg";
File storageDir = Environment.getExternalStorageDirectory();
File outFile = new File (storageDir, fileName);
return outFile;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 사진 촬영 앱의 사진 결과를 받아오게 되면 수행
if(requestCode == 101 && resultCode == RESULT_OK){
// 저장된 사진 이미지 파일을 --> BitMap 객체 --> ImageView 에 띄우기
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8; // 좀 작은 사이즈로 resample 을 위한 samplesize
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
imageView.setImageBitmap(bitmap); // ImageView 에 세팅
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case REQUEST_CODE:
if(grantResults.length <= 0){
Toast.makeText(this, "권한 획득 실패", Toast.LENGTH_SHORT).show();
// onDestroy() 혹은 finish()
return;
}
String result = "";
for(int i = 0; i < grantResults.length; i++){
if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
result += "권한 획득 성공:" + permissions[i] + "\n";
} else {
result += "권한 획득 실패:" + permissions[i] + "\n";
}
}
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
Log.d("myapp", result);
break;
}
}
} // end Activity
[추가] 사진 저장 경로 저장할 xml 파일 만들기
** 폴더만들기
: res > New > Android Resource Directory 클릭 > xml 타입의 폴더 만들기
** 경로 저장할 xml 파일 만들기
: 만든 xml 폴더 선택 후 우클릭 > New > XML Resource File 클릭
> Root element 선택 후 파일 생성
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="sdcard"
path="."/>
</paths>
2) Main2Activity 액티비티, activity_main2 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a023_camera">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<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=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
<!-- 앱 간의 파일 공유를 위한 Content Provider -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="org.techtown.capture.intent.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<!-- 파일 공유 경로 지정 -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/external" />
</provider>
</application>
</manifest>
<?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:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="CameraSurfaceView"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="사진찍기" />
<!-- 카메라 미리보기를 추가할 공간 확보 -->
<FrameLayout
android:id="@+id/previewFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
package com.lec.android.a023_camera;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import java.io.IOException;
/* 카메라 화면 보여주기 --> SurfaceView 사용
1.프리뷰설정
--->
SurfaceView <--> SurfaceHolder <--- 카메라 2.프리뷰 시작
3. 프리뷰표시 3. 프리뷰 디스플레이
SurfaceView 는 SurfaceHolder 에 의해 제어되는 모습
- setPreviewDisplay() 로 미리보기 설정해주어야 함
초기화 작업후 카메라객체의 startPreview() 호출 --> 카메라 영상이 SurfaceView 로 보이게 된다
주의!: Surface 타입은 반드시 SURFACE_TYPE_PUSH_BUFFERS)
SurfaceView 가 SURFACE_TYPE_PUSH_BUFFERS 타입인 경우, 카메라 보여주기 외에 다른 그림 못 그림
그 위에 다른 그림 (아이콤, 마커, 증강현실..) 그리려면 별도의 레이아웃을 위에 포개야 한다
*/
// API29 부터 android.hardware.Camera 는 deprecated 됨.
// 대신 android.hardware.camera2 의 객체 사용 권장
public class Main2Activity extends AppCompatActivity {
String[] permissions = {Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE};
final int REQUEST_CODE = 101;
CameraSurfaceView cameraSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
// 권한 획득 하기
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(String.valueOf(permissions)) == PackageManager.PERMISSION_DENIED) {
requestPermissions(permissions, REQUEST_CODE); // 권한 요청하기
}
}
FrameLayout previewFrame = findViewById(R.id.previewFrame);
cameraSurfaceView = new CameraSurfaceView(this);
previewFrame.addView(cameraSurfaceView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
// 사진 촬영
@Override
public void onClick(View v) {
takePicture();
}
});
} // end onCreate()
// 사진촬영
// 캡처한 이미지 데이터 -- > data
public void takePicture() {
cameraSurfaceView.capture(new Camera.PictureCallback() {
// 사진 찍힐 때 호출되는 콜백
// data 전달받은 이미지 byte 배열
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// byte 배열 -> bitmap 객체로 만들기
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// 미디어 앨범에 추가, MediaStore.Images.Media 사용
String outUriStr = MediaStore.Images.Media.insertImage(
getContentResolver(), // ContentResolver 객체
bitmap, // 캡처하여 만들어진 Bitmap 객체
"Captured Image", // 비트맵 제목
"Captured Image using Camera" // 비트맵 내용
);
if(outUriStr == null) {
Log.d("myapp", "이미지 저장 실패, Image Insert Fail");
return;
} else {
Uri outUrl = Uri.parse(outUriStr);
sendBroadcast(new Intent(new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, outUrl)));
}
camera.startPreview(); // 촬영 후 프리뷰 다시 재개
}
});
}
// SurfaceView 상속 + SurfaceHolder.Callback 구현
private class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera camera = null;
// 생성자에선 SurfaceHolder 객체 참조후 설정
public CameraSurfaceView(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
}
// SurfaceView 가 만들어질때, 카메라 객체를 참조한 후 미리보기 화면으로
// 홀더 객체 설정
@Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
// 카메라 orientation 세팅
setCameraOrientation();
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
}
// SurfaceView 의 화면 크기가 변경될때 호출
// --> 변경되는 시점에 미리보기 시작
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
camera.startPreview();
}
// SurfaceView 가 소멸될때 호출
// --> 미리보기 중지
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
}
// 카메로 orientation 세팅
public void setCameraOrientation() {
if (camera == null) return;
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
int rotation = manager.getDefaultDisplay().getRotation(); // 화면 회전값
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
} // end setCameraOrientation()
// 사진 촬영!
public boolean capture(Camera.PictureCallback handler) {
if (camera == null) return false;
camera.takePicture(null, null, handler);
return true;
}
} // end SurfaceView
} // end Activity
4. a019_graphic 모듈
: XML 레이아웃 사용하지 않고 사용자가 작성한 View 로 액티비티 레이아웃 세팅
1) MainActivity 액티비티
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a019_graphic">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.lec.android.a019_graphic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
// XML 레이아웃 사용하지 않고
// 사용자가 작성한 View 로 액티비티 레이아웃 세팅
MyView v = new MyView(MainActivity.this);
setContentView(v);
} // end onCreate()
}// end Activity
class MyView extends View {
public MyView(Context context) {
super(context);
}
// 화면이 업데이트 될때, '그려주기'
@Override
protected void onDraw(Canvas canvas) { // Canvas : 그림을 그릴 대상 객체
Paint paint = new Paint(); // 화면에 그려줄 도구 세팅
paint.setColor(Color.RED); // 색상 지정
setBackgroundColor(Color.GREEN); // 배경색 지정
// 사각형의 좌상, 우하 좌표
canvas.drawRect(100, 100, 200, 200, paint);
// 원의 중심 x, y, 반지름
canvas.drawCircle(300, 300, 40, paint);
paint.setColor(Color.YELLOW);
paint.setStrokeWidth(10f); // 선의 굵기
// 직선
canvas.drawLine(400, 100, 800, 150, paint);
// Path 자취(?) 만들기
Path path = new Path(); // android.graphic.Path
path.moveTo(20, 100); // 자취 이동
path.lineTo(100, 200); // 직선
path.cubicTo(150, 40, 200, 300, 300, 200); // 베지어 곡선
paint.setColor(Color.CYAN);
canvas.drawPath(path, paint);
}
}
2) Main2Activity 액티비티
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a019_graphic">
<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=".Main2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity" />
</application>
</manifest>
package com.lec.android.a019_graphic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main2);
setContentView(new MyView2(this));
}
}
class MyView2 extends View {
int x = 100, y = 100;
public MyView2(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setTextSize(80);
canvas.drawText("글씨", 300, 300, paint);
paint.setColor(Color.RED);
canvas.drawRect(x - 100, y - 100, x + 100, y + 100, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
x = (int)event.getX();
y = (int)event.getY();
invalidate(); // 화면을 다시 그려주기 --> onDraw() 호출함.
}
return true;
}
}
3) Main3Activity 액티비티
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lec.android.a019_graphic">
<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=".Main3Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Main2Activity" />
<activity android:name=".MainActivity" />
</application>
</manifest>
package com.lec.android.a019_graphic;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
public class Main3Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main3);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(new MyView3(this)); // LinealLayout 에 들어감
setContentView(ll);
}
}
class MyView3 extends View {
Paint paint = new Paint();
Path path = new Path();
public MyView3(Context context) {
super(context);
paint.setStyle(Paint.Style.STROKE); // 실선
paint.setStrokeWidth(10f); // 선 두께
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y); // path 를 그리지 말고, 위치 이동만 함
break;
case MotionEvent.ACTION_MOVE:
path.lineTo(x, y); // path 에 선 그리기
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
}
'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글
2020.04.28 (0) | 2020.04.28 |
---|---|
2020.04.27 (0) | 2020.04.27 |
2020.04.23 (0) | 2020.04.23 |
2020.04.22 (0) | 2020.04.22 |
2020.04.21 (0) | 2020.04.21 |