웹_프론트_백엔드/JAVA프레임윅기반_풀스택

2020.04.24

shine94 2020. 4. 24. 09:43

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