1) 데이터 삭제 버튼

데이터 삭제 버튼을 만들자.

위 이미지 버튼 복사해서 필요한 값만 수정한다.

 

 

1-1) activity_main.xml

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/deleteButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:layout_margin="36dp"
    app:layout_constraintBottom_toTopOf="@id/goInputActivityButton"
    app:layout_constraintEnd_toEndOf="parent"
    app:srcCompat="@drawable/ic_baseline_delete_24" />
  1. id 값 deleteButton으로 변경
  2. layout_constraintBottom_toBottomOf layout_constraintBottom_to_topOf 으로 변경 후 constraint 변경
  3. srcCompat 을 delete icon 으로 변경

 


1-2) MainActivity.kt

MainActivity 내부 OnCreate() 안에서

binding.deleteButton.setOnClickListener {
    deleteData()
}

OnCreate() 외부의 데이터 삭제 함수

private fun deleteData() {
    with(getSharedPreferences(USER_INFORMATION, MODE_PRIVATE).edit()) {
        clear() // 파일에 있는 모든 데이터 삭제
        apply() // apply() 코드가 없으면, 마지막에 실행되지 않음
        getDataUiUpdate()
    }

    Toast.makeText(this, "초기화를 완료했습니다.", Toast.LENGTH_SHORT)
}

2) editing 을 하고 나서   getSharedPreferences 에서 잊지 말아야할 것은 바로 apply()

중요. apply() 코드가 없으면, clear() 가 화면에 반영되지 않음

 

 

3) 시연

 

1) saveButton

1-1) activity_input.xml

이전 단원에서 activity_input.xml 을 작성해보았다.

 

activity_main.xml 의 UI 와

activity_input.xml 의 UI 가 유사했으므로

activity_main의 코드를 activity_input 에 복사/붙이기 하고 수정 했었다.

 

activity_main 에서 InputActivity 로 이동하도록 하는 버튼을

저장 버튼으로 바꿔보자.

id 는 saveButton.

 

 

1-2) InputActivity.kt

이제 버튼을 누르면 입력 데이터가 저장되도록 하자.

onCreate() 함수 내부에서는

데이터 저장을 수행하는 함수 한 줄로 코드를 간결히 하자.

binding.saveButton.setOnClickListener {
            saveData()
        }

saveData() 는 onCreate() 함수 외부이자, InputActivity 클래스의 내부에 위치시킨다.

간단히 말하면 코드 간결성을 위해, onCreate() 에서 기능을 빼내서 따로 구현한 것이다.

 

saveData() 함수 내부에서는 아래와 같은 5가지 정보를 저장한다.

  1. 이름 2) 생년월일 3) 혈액형 4) 비상연락처 5) 주의사항
  2.  

이런 정보를 저장하는 방법을 알아보기 위해

SharedPreferences API 에 대해서 공부하자.


1-3) SharedPrereferences ( saveData() 작성 )

SharedPreferences 에 대해 알아보기 위해

안드로이드 공식 문서를 살펴보자.

저장하려는 키-값 컬렉션이 비교적 작은 경우

SharedPreferences API 를 사용해야 한다. 키-값 데이터 저장.

 

 

SharedPreferences 는 하나의 파일로 저장된다.

어떤 파일로 저장이 될 지 지정할 수 있다.

SharedPreferences( “파일이름”, Context.모드 )

 

 

Context.MODE_PRIVATE

이 파일을 생성한 앱에서만 접근할 수 있다.

chapter4 에서만 해당 파일에 접근할 수 있다.

 

 

InputActivity.kt

// 저장을 위해 sharedPreference 를 사용하자.
private fun saveData() {
    val editor = getSharedPreferences("userInformation", Context.MODE_PRIVATE).edit()
    editor.putString("name", binding.nameEditText.text.toString())
    editor.putString("birthDate", binding.birthdateTextView.text.toString())
    editor.putString("bloodType",)
    editor.putString("emergencyContact", binding.emergencyContactEditText.text.toString())
    editor.putString("warning", )
    editor.apply()
    
    // 저장되었습니다. 알림 띄우기
    // 마찬가지로 show()를 붙여주어야 화면에 나타남
    Toast.makeText(this, "저장을 완료했습니다.", Toast.LENGTH_SHORT).show()

}

 

 

1-3-1) commit 과 apply

editor 에서 apply() 함수를 호출할 수도 있고

commit() 함수를 호출할 수도 있다.

 

 

Consider using apply() instead, commit writes its data to persistent storate immediately, whereas apply will handle it in the background.

 

commit 같은 경우는

이 commit 을 가지고 있는 스레드에서

현재 실행 중인 스레드의 동작을 막은 후 저장을 하고

저장을 완료한 뒤에 다시 이전 스레드가 동작할 수 있다.

 

 

스레드는 작업이 이루어지는 하나의 공간

이 데이터를 저장하는 동안, 사용자는 아무 동작도 할 수 없다.

 

 

데이터를 저장하는 동안, 사용자의 동작을 막지 않으려면

현재 사용하고 있는 메인스레드가 아닌

다른 스레드를 열어서 그 스레드에서 처리를 해야한다.

  1. 다른 스레드를 열어주고 commit을 하거나
  2. apply 함수를 호출한다.

 

apply 는 commit 과 다르게

해당 스레드에서 동작이 이루어지는 게 아니고

Async 하게 (비동기적으로) 동작이 이루어진다.

 

 

저장을 할 때, 다른 스레드를 열어서

그 스레드에서 저장을 하기 때문에

지금 사용하고 있는 스레드의 동작을 막지 않으므로

가능한 apply 를 사용하는 것이 좋다.


1-3-2) scope function 을 통한 반복 줄이기

InputActivity.kt

// 저장을 위해 sharedPreference 를 사용하자.
private fun saveData() {
    val editor = getSharedPreferences("userInformation", Context.MODE_PRIVATE).edit()
    editor.putString("name", binding.nameEditText.text.toString())
    editor.putString("birthDate", binding.birthdateTextView.text.toString())
    editor.putString("bloodType",)
    editor.putString("emergencyContact", binding.emergencyContactEditText.text.toString())
    editor.putString("warning", )
    editor.apply()
    
    // 저장되었습니다. 알림 띄우기
    // 마찬가지로 show()를 붙여주어야 화면에 나타남
    Toast.makeText(this, "저장을 완료했습니다.", Toast.LENGTH_SHORT).show()

}

editor 가 계속 반복이 된다.

scope function 을 이용해서 반복을 줄여보자.

 

apply, run 등 많은 scope function 중에서 with 를 사용할 것이다.

InputActivity.kt

// 저장을 위해 sharedPreference 를 사용하자.
private fun saveData() {
    with(getSharedPreferences("userInformation", Context.MODE_PRIVATE).edit()) {
        putString("name", binding.nameEditText.text.toString())
        putString("birthDate", binding.birthdateTextView.text.toString())
        putString("bloodType",getBloodType())
        putString("emergencyContact", binding.emergencyContactEditText.text.toString())
        putString("warning", getWarning())
        apply()
    }

    // 저장되었습니다. 알림 띄우기
    // 마찬가지로 show()를 붙여주어야 화면에 나타남
    Toast.makeText(this, "저장을 완료했습니다.", Toast.LENGTH_SHORT).show()

}

1-3-3) 하드코딩 대신 상수 선언

getSharedPreferences(“userInformation”,… )

key 값인 “userInformation” 을 하드코딩하다보면 실수할 수 있다.

자바에서는 이 key 값들을 하나의 static 변수로 만드는 것이 흔하다.

 

코틀린에서는 이러한 static 변수를 파일에 선언할 수 있다.

Kotlin Class 로 static 변수들을 담는 Constant.kt 를 만들 수 있다.

 

자바에서 상수를 선언할 때

snake rule 을 따르고 capital letter 을 사용하는 것처럼

코틀린에서도 동일하게 작성하면 된다.

 

const val 키워드로 static 변수를 선언하자.

 

Constant.kt

package com.part1.chapter4

const val USER_INFORMATION = "userInformation"
const val NAME = "name"
const val BIRTHDATE = "birthdate"
const val BLOOD_TYPE = "bloodType"
const val EMERGENCY_CONTACT = "emergencyContact"
const val WARNING = "warning"

이제 하드코딩한 문자열 대신 상수값을 인자로 변경하자.

 

 

InputActivity.kt

// 저장을 위해 sharedPreference 를 사용하자.
private fun saveData() {
    with(getSharedPreferences("userInformation", Context.MODE_PRIVATE).edit()) {
        putString(NAME, binding.nameEditText.text.toString())
        putString(BIRTHDATE, binding.birthdateTextView.text.toString())
        putString(BLOOD_TYPE,getBloodType())
        putString(EMERGENCY_CONTACT, binding.emergencyContactEditText.text.toString())
        putString(WARNING, getWarning())
        apply()
    }

    // 저장되었습니다. 알림 띄우기
    // 마찬가지로 show()를 붙여주어야 화면에 나타남
    Toast.makeText(this, "저장을 완료했습니다.", Toast.LENGTH_SHORT).show()

}

1-3-4)

MainActivity.kt

val warning = getString(WARNING, "")

if(warning.isNullOrEmpty()){
    binding.warningTextView.isVisible = false
    binding.warningValueTextView.isVisible = false
} else {
    binding.warningTextView.isVisible = true
    binding.warningValueTextView.isVisible = true
    binding.warningValueTextView.text = warning
}

binding.warningTextView.isVisible

binding.warningValueTextView.isVisible

위 두 부분이 반복이 많다.

 

반복을 줄이기 위해 아래와 같이 코드를 간결화 할 수 있다.

val warning = getString(WARNING, "")

binding.warningTextView.isVisible = warning.isNullOrEmpty().not()
binding.warningValueTextView.isVisible = warning.isNullOrEmpty().not()

if(!warning.isNullOrEmpty()){
    binding.warningValueTextView.text = warning
}

 

 

전체코드

MainActivity.kt

package com.part1.chapter4

import android.content.Context
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.view.isVisible
import com.part1.chapter4.databinding.ActivityInputBinding
import com.part1.chapter4.databinding.ActivityMainBinding
import java.util.zip.Inflater

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Intent
        // 의도: MainActivity 에서 편집 버튼을 누르면
        // InputActivity 로 이동한다.
        binding.goInputActivityButton.setOnClickListener {
            // Intent 가 시작하는 곳의 context 를 알려주어야 함 ( MainActivity 가 가진 context)
            // InputActivity 를 call 하겠다는 의도
            val intent = Intent(this, InputActivity::class.java)

            // 다른 Activity 실행
            startActivity(intent)
        }

    }

    override fun onResume() {
        super.onResume()
        getDataUiUpdate() // onCreate() 가 아닌, onResume() 에서 호출돼야 함.

        // onCreate() 는 액티비티가 최초실행될 때
        // 액티비티 종류된 후 다른 액티비티가 실행될 때는
        // onCreate() 가 아닌 onResume() 이 호출되므로

    }
    // 데이터를 가져와서 UI 업데이트를 함께 했다.
    // 두 가지 기능을 나누어서 하는 것이 좋다.
    // 함수 하나에는 하나의 기능이 있는 것이 좋다.
    private fun getDataUiUpdate() {
        with(getSharedPreferences(USER_INFORMATION, Context.MODE_PRIVATE)) {
            binding.nameValueTextView.text = getString(NAME, "미정")
            binding.birthdateValueTextView.text = getString(BIRTHDATE, "미정")
            binding.bloodtypeValueTextView.text = getString(BLOOD_TYPE, "미정")
            binding.emergencyContactValueTextView.text = getString(EMERGENCY_CONTACT, "미정")
            val warning = getString(WARNING, "")

            binding.warningTextView.isVisible = warning.isNullOrEmpty().not()
            binding.warningValueTextView.isVisible = warning.isNullOrEmpty().not()

            if(!warning.isNullOrEmpty()){
                binding.warningValueTextView.text = warning
            }
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <!-- 이름 -->
    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="이름"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="36dp"
         />

    <TextView
        android:id="@+id/nameValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="김주연 "
        android:maxLines="1"
        android:ellipsize="end"
        style="@style/Value"
        android:layout_marginEnd="36dp"
        app:layout_constraintBaseline_toBaselineOf="@+id/nameTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="0000-00-00"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <TextView
        android:id="@+id/bloodtypeValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="A"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/bloodtypeTextView"
        app:layout_constraintEnd_toEndOf="@+id/birthdateValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 비상연락처 -->
    <TextView
        android:id="@+id/emergencyContactTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비상 연락처"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/bloodtypeTextView"
        app:layout_constraintTop_toBottomOf="@+id/bloodtypeTextView" />

    <TextView
        android:id="@+id/emergencyContactValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="010-0000-0000"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/emergencyContactTextView"
        app:layout_constraintEnd_toEndOf="@+id/bloodtypeValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <TextView
        android:id="@+id/warningValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Value"
        android:maxLines="4"
        app:layout_constraintBaseline_toBaselineOf="@id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/emergencyContactValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />


    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 : Guideline -->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/goInputActivityButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:layout_margin="36dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_baseline_edit_24" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

InputActivity.kt

package com.part1.chapter4

import android.app.DatePickerDialog
import android.app.DatePickerDialog.OnDateSetListener
import android.content.Context
import android.os.Bundle
import android.os.PersistableBundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.part1.chapter4.R.layout.activity_input
import com.part1.chapter4.databinding.ActivityInputBinding

class InputActivity : AppCompatActivity() {
    private lateinit var binding: ActivityInputBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityInputBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 스피너 설정
        binding.bloodTypeSpinner.adapter = ArrayAdapter.createFromResource(
            this,
            R.array.blood_types,
            android.R.layout.simple_list_item_1
        )

        // 캘린더 설정
        binding.birthdateLayer.setOnClickListener {
            val listener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
                binding.birthdateTextView.text = "$year-${month.inc()}-$dayOfMonth"
            }

            DatePickerDialog(
                this,
                listener,
                2000,
                1,
                1
            ).show()
        }

        // 체크박스 설정
        binding.warningCheckBox.setOnCheckedChangeListener { _, isChecked ->
            binding.warningEditText.isVisible = isChecked
        }

        // 초기 선택 여부 설정
        binding.warningEditText.isVisible = binding.warningCheckBox.isChecked

        // 저장 버튼 설정
        binding.saveButton.setOnClickListener {
            saveData()
            finish() // 액티비티 종료
        }
    }

    // 저장을 위해 sharedPreference 를 사용하자.
    private fun saveData() {
        with(getSharedPreferences("userInformation", Context.MODE_PRIVATE).edit()) {
            putString(NAME, binding.nameEditText.text.toString())
            putString(BIRTHDATE, binding.birthdateTextView.text.toString())
            putString(BLOOD_TYPE,getBloodType())
            putString(EMERGENCY_CONTACT, binding.emergencyContactEditText.text.toString())
            putString(WARNING, getWarning())
            apply()
        }

        // 저장되었습니다. 알림 띄우기
        // 마찬가지로 show()를 붙여주어야 화면에 나타남
        Toast.makeText(this, "저장을 완료했습니다.", Toast.LENGTH_SHORT).show()

    }

    // 혈액형 정보 받아오기
    private fun getBloodType() : String {
        val bloodAlphabet = binding.bloodTypeSpinner.selectedItem.toString()
        val bloodSign = if(binding.bloodTypePlus.isChecked) "+" else "-"
        return "$bloodSign$bloodAlphabet"
    }

    // 주의사항 받아오기
    private fun getWarning() : String {
        return if(binding.warningCheckBox.isChecked) binding.warningEditText.text.toString() else ""
    }

}

 

 

 

activity_input.xml

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".InputActivity">



    <!-- 이름 -->
    <TextView
        android:id="@+id/nameTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="36dp"
        android:text="이름"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/nameEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="36dp"
        android:inputType="text"
        app:layout_constraintBaseline_toBaselineOf="@+id/nameTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:paddingEnd="8dp"
        android:text="0000-00-00"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toStartOf="@id/birthdateImageView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 달력 이미지 -->
    <ImageButton
        android:id="@+id/birthdateImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_edit_calendar_24"
        app:layout_constraintBottom_toBottomOf="@id/birthdateTextView"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/birthdateTextView" />


    <!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <!-- Rh 타입 선택하는 RadioGroup 과 RadioButton -->
    <RadioGroup
        android:id="@+id/bloodTypeRadioGroup"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/bloodtypeTextView"
        app:layout_constraintStart_toStartOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView">

        <RadioButton
            android:id="@+id/bloodTypePlus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh+" />

        <RadioButton
            android:id="@+id/bloodTypeMinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh-" />

    </RadioGroup>

    <!-- 실제 혈액형 선택하는 Spinner -->
    <Spinner
        android:id="@+id/bloodTypeSpinner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="@id/bloodtypeTextView"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintStart_toEndOf="@+id/bloodTypeRadioGroup"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView" />


    <!-- 비상연락처 -->
    <TextView
        android:id="@+id/emergencyContactTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비상 연락처"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/bloodtypeTextView" />

    <EditText
        android:id="@+id/emergencyContactEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="010-0000-0000"
        android:inputType="phone"
        app:layout_constraintBaseline_toBaselineOf="@id/emergencyContactTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <EditText
        android:id="@+id/warningEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine"
        app:layout_constraintTop_toBottomOf="@id/warningCheckBox" />

    <!-- 주의사항을 보여줄지 여부를 선택하는 CheckBox -->
    <CheckBox
        android:id="@+id/warningCheckBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="end|center_vertical"
        android:text="주의사항 노출"
        app:layout_constraintBottom_toBottomOf="@+id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@+id/warningEditText"
        app:layout_constraintTop_toTopOf="@+id/warningTextView" />


    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 : Guideline -->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="36dp"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_baseline_save_24" />

    <androidx.constraintlayout.helper.widget.Layer
        android:id="@+id/birthdateLayer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="birthdateValueTextView,birthdateImageView"
        tools:ignore="MissingConstraints" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Title" parent="Widget.AppCompat.TextView">
        <item name="android:textColor">@color/brown</item>
        <item name="android:textSize">24sp</item>
        <item name="android:layout_marginTop">36sp</item>
        <item name="android:textStyle">bold</item>


    </style>

    <style name="Value">
        <item name="android:textColor">@color/black</item>
        <item name="android:textSize">20sp</item>
        <item name="android:gravity">end</item>

    </style>

</resources>

 

목표

이번 소단원에서는, 이전 소단원 에서 구현하지 못한

  1. Spinner ( A / B / AB / O ) 를 통해 선택된 혈액형 표시하기
  2. Calendar 연결
  3. CheckBox 를 통해 주의사항의 Visibility 관리

이렇게 위 세 가지 UI 를 구현해보도록 할 것이다.


1) Spinner 에 adapter 연결

1-1) Spinner 와 adapter

Spinner 는

삼각형 버튼을 누르면, 리스트로 데이터가 나오고

그 데이터를 선택하면, 선택한 값을 노출시키는 역할이다.

 

개발하면서 정말 자주 마주하는 문제 중 하나가

반복을 정말 싫어한다는 것이다.

 

만약 Spinner를 xml 로 그려야한다면

xml 코드로 리스트 모양을 하나하나 그려야한다.

 

이는 있을 수 없는 일이다.

리스트형 데이터를 UI로 연결해주는 역할을 해주는 것이 바로 adapter 이다.

 

adapter 를 통해서 bloodTypeSpinner 에

A, B, AB, O 이 4가지를 리스트로 넣어주고,

그 중 하나를 선택했을 때

Spinner 에게 얘를 선택했어-라는 것을 알려주는 코드를 작성해볼 것이다.

 


1-2) InputActivity.kt

InputActivity.kt

class InputActivity : AppCompatActivity() {
    private lateinit var binding: ActivityInputBinding
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        binding = ActivityInputBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.bloodTypeSpinner.adapter = ArrayAdapter.createFromResource(
            /* context = */
            this,

        )
    }

ViewBinding 을 한 후

bloodTypeSpinner 에 adapter 를 연결하려고 한다.

 

우리는 ArrayAdapter 의 createFromResource 를 연결할 것인데,

이의 인자를 살펴보면

 

context

textArrayResId

textViewResID

이렇게 3가지를 인자로 한다.

 



두 번째 인자인 textArrayResId 를 위해 

arrays.xml 리소스 파일을 생성해보자.


1-2) arrays.xml 리소스 파일

New > Android Resource File > name: arrays

리소스 파일을 추가해보자.

 

 

RadioButton 에서 <item>을 통해 요소를 넣어주었던 것 처럼

string-array 에서도 <item>을 통해 요소를 넣어준다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="blood_types">
        <item>A</item>
        <item>B</item>
        <item>O</item>
        <item>AB</item>
    </string-array>
</resources>

1-3) InputActivity.kt 에서 adapter 연결 완료

다시 InputActivity.kt 의

ArrayAdaptor 의 createFromResource 의 인자를 채우러 가보자.

textViewResID 는 이미 안드로이드에서 만들어서 제공하는

간단한 리스트인 simple_list_item_1 을 사용하자.

binding.bloodTypeSpinner.adapter = ArrayAdapter.createFromResource(
    this,
    R.array.blood_types,
    android.R.layout.simple_list_item_1
)

simple_list_item_1 를 살펴보기 위해

글자 위에 커서를 올리고, command 를 누른 채로 클릭 을 해보자.

 

살펴보니 단순한 TextView 이다.

여기에서 우리가 선택한 text 를 넣을 것이다.

 

여기까지 완료하면 아래와 같이

Spinner 에 요소가 들어가있는 것을 확인할 수 있다.

 

 


1-4) Spinner 공간 확보

현재 Spinner 에서 혈액형을 선택했을 때

옆에 혈액형이 표시되지 않는다.

따라서 Spinner 공간을 확보하기 위해

activity_input.xml 파일을 수정해보자.

  • 1-4-1) RadioGroup 에서gravity 를 지우고
  • End_toStartOf 를 지정하지 않고 지운다.
  • layout_width 를 wrap_content 로 변경하고
    <!-- Rh 타입 선택하는 RadioGroup 과 RadioButton -->
    <RadioGroup
        android:id="@+id/bloodTypeRadioGroup"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/bloodtypeTextView"
        app:layout_constraintStart_toStartOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView">
  • 1-4-2) Spinner 에서

Spinner 의 공간을 최대한 활용하기 위해서

layout_width 를 0dp 로 변경하고

왼쪽 constraint 를 최대한 왼쪽으로 맞추자.

 

<!-- 실제 혈액형 선택하는 Spinner -->
<Spinner
    android:id="@+id/bloodTypeSpinner"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="@id/bloodtypeTextView"
    app:layout_constraintEnd_toEndOf="@id/nameEditText"
    app:layout_constraintStart_toEndOf="@+id/bloodTypeRadioGroup"
    app:layout_constraintTop_toTopOf="@id/bloodtypeTextView" />

 

 

결과

Spinner 에서 혈액형 선택 시, 오른쪽에 표시된다.

 

 


2) Calendar 연결

2-1) layer 로 두 요소 묶기

날짜 또는 버튼 이미지를 선택했을 때

캘린더를 띄워볼 것이다.

 

날짜나 버튼이미지 어느 부분이든 클릭해도 되도록

이 두 개를 묶는 layer 를 만들어보자.

 

Palette 에서 command ( 또는 ctrl ) 을 누른 채로

두 요소를 클릭하여 선택하자.

 

 

선택된 상태에서 마우스 우클릭 > Add helpers > Layer 로 층을 추가한다.

 

 

activity_input.xml

<androidx.constraintlayout.helper.widget.Layer
    android:id="@+id/birthdateLayer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:constraint_referenced_ids="birthdateValueTextView,birthdateImageView"
    tools:ignore="MissingConstraints" />

2-2) birthdateLayer 에 ClickListener 추가

 

InputActivity.kt

binding.birthdateLayer.setOnClickListener{
            val listener = OnDateSetListener { _, year, month, dayOfMonth ->
                binding.birthdateTextView.text = "$year-$month-$dayOfMonth"
            }

            DatePickerDialog(
                this,
                listener,
                2000,
                1,
                1
            ).show()
        }

content : this

listener : 사용자가 선택한 날짜를 받아주는 역할

초기날짜 설정 : 2000년 1월 1일

 

 

DatePickerDialog 에서 show() 를 하지 않으면

DatePickerDialog 를 만들어놓기만 한 것이고 보이지 않는다.

 

 

실행해보면,

내가 선택한 날짜는 1998-2-6 인데

보이는 날짜는 1998-1-6 이다.

 

 

안드로이드에서 제공하는 캘린더에 나오는 달(month)은 하나를 더 추가해주어야 날짜가 정확히 나온다.

따라서 아래 코드를 변경하자.

 

변경 전: binding.birthdateTextView.text = "$year-$month-$dayOfMonth"

변경 후: binding.birthdateTextView.text = "$year-${month.inc()}-$dayOfMonth"


3) CheckBox 를 통해 주의사항의 Visibility 관리

// 체크박스
binding.warningCheckBox.setOnCheckedChangeListener{ _, isChecked ->
    binding.warningEditText.isVisible = isChecked

}

체크박스 선택이 되면, 주의사항이 보이고

체크박스가 선택 되지 않으면, 주의사항이 안 보인다.

 

( 주의사항 노출 글자 길이는 다음 단원에서 수정할 것이다. )

 

 

다만, 초반에는 선택 여부에 따라서, 노출 여부가 적용되지 않는다.

 

값이 변경 되었을 때만, 화면에 노출여부를 선택하게 했기 때문이다.

기본적으로 선택되지 않은 것이 기본값이다.

 

처음에 선택이 되었는지 여부에 따라

노출여부를 한 번 더 설정해주어야 한다.

// 체크박스
binding.warningCheckBox.setOnCheckedChangeListener{ _, isChecked ->
    binding.warningEditText.isVisible = isChecked

}
// 초기 선택여부
binding.warningEditText.isVisible = binding.warningCheckBox.isChecked

추가 구현할 기능

현재까지는 선택한 정보가 이전 화면에 보이지 않는다.

이 문제를 해결하기 위해서

사용자가 입력한 값을 intent 를 통해서 데이터를 보낼 수는 있다.

그러나 intent 는

Activity 와 Activity 사이에  데이터를 주고받는 역할밖에 하지 못한다.

어딘가에 데이터를 저장하지 않았기 때문에

앱을 껐다가 켜면, 데이터가 사라진다.

다음 단원에서는 입력한 정보를 저장하고 데이터를 불러오는 것을 할 것이다.


전체코드

InputActivity.kt

package com.part1.chapter4

import android.app.DatePickerDialog
import android.app.DatePickerDialog.OnDateSetListener
import android.os.Bundl
import android.os.PersistableBundle
import android.util.Log
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import com.part1.chapter4.databinding.ActivityInputBinding

class InputActivity : AppCompatActivity() {
    private lateinit var binding: ActivityInputBinding
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        binding = ActivityInputBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // 스피너
        binding.bloodTypeSpinner.adapter = ArrayAdapter.createFromResource(
            this,
            R.array.blood_types,
            android.R.layout.simple_list_item_1
        )

        // 캘린더
        binding.birthdateLayer.setOnClickListener{
            val listener = OnDateSetListener { _, year, month, dayOfMonth ->
                binding.birthdateTextView.text = "$year-${month.inc()}-$dayOfMonth"
            }

            DatePickerDialog(
                this,
                listener,
                2000,
                1,
                1
            ).show()
        }

        // 체크박스
        binding.warningCheckBox.setOnCheckedChangeListener{ _, isChecked ->
            binding.warningEditText.isVisible = isChecked

        }
        // 초기 선택여부
        binding.warningEditText.isVisible = binding.warningCheckBox.isChecked


    }
}

 

 

activity_input.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <!-- 이름 -->
    <TextView
        android:id="@+id/nameTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="36dp"
        android:text="이름"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/nameEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="36dp"
        android:inputType="text"
        app:layout_constraintBaseline_toBaselineOf="@+id/nameTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:paddingEnd="8dp"
        android:text="0000-00-00"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toStartOf="@id/birthdateImageView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 달력 이미지 -->
    <ImageButton
        android:id="@+id/birthdateImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_edit_calendar_24"
        app:layout_constraintBottom_toBottomOf="@id/birthdateTextView"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/birthdateTextView" />


    <!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <!-- Rh 타입 선택하는 RadioGroup 과 RadioButton -->
    <RadioGroup
        android:id="@+id/bloodTypeRadioGroup"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/bloodtypeTextView"
        app:layout_constraintStart_toStartOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView">

        <RadioButton
            android:id="@+id/bloodTypePlus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh+" />

        <RadioButton
            android:id="@+id/bloodTypeMinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh-" />

    </RadioGroup>

    <!-- 실제 혈액형 선택하는 Spinner -->
    <Spinner
        android:id="@+id/bloodTypeSpinner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="@id/bloodtypeTextView"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintStart_toEndOf="@+id/bloodTypeRadioGroup"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView" />


    <!-- 비상연락처 -->
    <TextView
        android:id="@+id/emergencyContactTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비상 연락처"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/bloodtypeTextView" />

    <EditText
        android:id="@+id/emergencyContactEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="010-0000-0000"
        android:inputType="phone"
        app:layout_constraintBaseline_toBaselineOf="@id/emergencyContactTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <EditText
        android:id="@+id/warningEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine"
        app:layout_constraintTop_toBottomOf="@id/warningCheckBox" />

    <!-- 주의사항을 보여줄지 여부를 선택하는 CheckBox -->
    <CheckBox
        android:id="@+id/warningCheckBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="end|center_vertical"
        android:text="주의사항 노출"
        app:layout_constraintBottom_toBottomOf="@+id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@+id/warningEditText"
        app:layout_constraintTop_toTopOf="@+id/warningTextView" />


    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 : Guideline -->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/goInputActivityButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="36dp"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_baseline_edit_24" />

    <androidx.constraintlayout.helper.widget.Layer
        android:id="@+id/birthdateLayer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="birthdateValueTextView,birthdateImageView"
        tools:ignore="MissingConstraints" />


</androidx.constraintlayout.widget.ConstraintLayout>

1) activity_input.xml

InputActivity 의 UI 를 구성해보자.

activity_input.xml 의 요소는

activity_main.xml 과 요소와 유사하므로, 복사/붙이기를 한 이후

value 요소를 TextView 에서

값을 입력할 수 있는 EditText 로 변경하자.

 

inputType 을 지정하자.


1-1) 생년월일 ( ImageButton )

생년월일 입력 시에는, 달력을 띄울 것이므로

ImageButton 뷰를 만들고

src 에 달력 이미지를 넣기 위해

New > File > Vector Asset 을 추가하자.

 

( edit calendar )

( drawable 폴더에 벡터 에셋이 생성된다. )

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="0000-00-00"
        android:paddingEnd="8dp"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toStartOf="@id/birthdateImageView"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 달력 이미지 -->
    <ImageButton
        android:id="@+id/birthdateImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/birthdateTextView"
        app:layout_constraintBottom_toBottomOf="@id/birthdateTextView"
        android:src="@drawable/ic_baseline_edit_calendar_24"
        />

1-2) 혈액형 ( RadioGrop & Spinner )

혈액형은 Rh+/Rh- 중에 선택한 후 ( RadioButton)

A/B/AB/O 를 선택하도록 할 것이다. ( Spinner )

 

Rh 타입은 Radio Button 두 개로 구현할 것인데,

Radio Button 을 담는 Radio Group 을 먼저 만들어야한다.

 

Radio Group은 Linear Layout 을 상속받는다.

Spinner 를 Radio Button 오른쪽에 추가하기 위해

Radio Button 을 왼쪽으로 이동시키자.

 

Palette 에서 Handler 를 통해서 위치를 지정해주자.

변경 전(좌) / 변경 후(우)

 

<!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <!-- Rh 타입 선택하는 RadioGroup 과 RadioButton -->
    <RadioGroup
        android:id="@+id/bloodTypeRadioGroup"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="end"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/bloodtypeTextView"
        app:layout_constraintEnd_toStartOf="@+id/bloodTypeSpinner"
        app:layout_constraintStart_toStartOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView">

        <RadioButton
            android:id="@+id/bloodTypePlus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh+" />

        <RadioButton
            android:id="@+id/bloodTypeMinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh-" />

    </RadioGroup>

    <!-- 실제 혈액형 선택하는 Spinner -->
    <Spinner
        android:id="@+id/bloodTypeSpinner"
        android:layout_width="70dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView"
        app:layout_constraintBottom_toBottomOf="@id/bloodtypeTextView"/>

Spinner 의 layout_width 를 0이 아닌 70으로 설정한 이유는

왼쪽의 Radio Button 과 <간격>을 두기 위함이다.


1-3) 주의사항 ( CheckBox )

주의사항을 보이게 할 수도 있고, 안 보이게 할 수도 있다.

이는 선택사항이므로 CheckBox 를 추가하자.

<!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <EditText
        android:id="@+id/warningEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine"
        app:layout_constraintTop_toBottomOf="@id/warningCheckBox"/>

    <!-- 주의사항을 보여줄지 여부를 선택하는 CheckBox -->
    <CheckBox
        android:id="@+id/warningCheckBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항 노출"
        android:gravity="end|center_vertical"
        app:layout_constraintBottom_toBottomOf="@+id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@+id/warningEditText"
        app:layout_constraintTop_toTopOf="@+id/warningTextView" />

CheckBox 의 gravity 를 잘 살펴보면,

text 인 “주의사항 노출” 에 두 가지 옵션을 주었다.

android:gravity="end|center_vertical"

가로로는 오른쪽 끝으로 붙이기 위해 end 옵션을,

세로로는 가운데 위치하게 하기 위해 center_vertical 옵션을 주었다.


2) 전체코드

 

 

res > layout > activity_input.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <!-- 이름 -->
    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="이름"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="36dp"
        />

    <EditText
        android:id="@+id/nameEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:inputType="text"
        style="@style/Value"
        android:layout_marginEnd="36dp"
        app:layout_constraintBaseline_toBaselineOf="@+id/nameTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="0000-00-00"
        android:paddingEnd="8dp"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toStartOf="@id/birthdateImageView"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 달력 이미지 -->
    <ImageButton
        android:id="@+id/birthdateImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/birthdateTextView"
        app:layout_constraintBottom_toBottomOf="@id/birthdateTextView"
        android:src="@drawable/ic_baseline_edit_calendar_24"
        />


    <!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <!-- Rh 타입 선택하는 RadioGroup 과 RadioButton -->
    <RadioGroup
        android:id="@+id/bloodTypeRadioGroup"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="end"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="@+id/bloodtypeTextView"
        app:layout_constraintEnd_toStartOf="@+id/bloodTypeSpinner"
        app:layout_constraintStart_toStartOf="@+id/guideLine"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView">

        <RadioButton
            android:id="@+id/bloodTypePlus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh+" />

        <RadioButton
            android:id="@+id/bloodTypeMinus"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rh-" />

    </RadioGroup>

    <!-- 실제 혈액형 선택하는 Spinner -->
    <Spinner
        android:id="@+id/bloodTypeSpinner"
        android:layout_width="70dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="@id/nameEditText"
        app:layout_constraintTop_toTopOf="@id/bloodtypeTextView"
        app:layout_constraintBottom_toBottomOf="@id/bloodtypeTextView"/>


    <!-- 비상연락처 -->
    <TextView
        android:id="@+id/emergencyContactTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비상 연락처"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/bloodtypeTextView" />

    <EditText
        android:id="@+id/emergencyContactEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="010-0000-0000"
        android:inputType="phone"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/emergencyContactTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <EditText
        android:id="@+id/warningEditText"
        style="@style/Value"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@id/guideLine"
        app:layout_constraintTop_toBottomOf="@id/warningCheckBox"/>

    <!-- 주의사항을 보여줄지 여부를 선택하는 CheckBox -->
    <CheckBox
        android:id="@+id/warningCheckBox"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항 노출"
        android:gravity="end|center_vertical"
        app:layout_constraintBottom_toBottomOf="@+id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameEditText"
        app:layout_constraintStart_toStartOf="@+id/warningEditText"
        app:layout_constraintTop_toTopOf="@+id/warningTextView" />


    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 : Guideline -->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/goInputActivityButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:layout_margin="36dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_baseline_edit_24" />


</androidx.constraintlayout.widget.ConstraintLayout>

이로써 InputActivity 의 UI 를 1차적으로 완성하였다.

1) FloatingActionButton

응급정보를 입력하기 위한 창으로 이동하는 버튼인

‘FloatingActionButton’ 을 추가해보자.

 

Palette > Buttons > FloatingActionButton

 

Vector Asset 으로 아이콘을 가져오자.

edit 검색해서 “연필 모양” 아이콘을 “흰색” 으로 추가하자.

 

 

사용자가 오른손잡이일 경우

오른손으로 편집버튼을 누를 가능성이 높기 때문에

편의성을 위해 편집버튼을 우측하단에 위치시키자.

 

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:layout_margin="36dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@drawable/ic_baseline_edit_24" />


2) 사전작업

2-1) InputActivity 파일 생성

편집 버튼을 누르면, 다른 액티비티로 이동하도록 해보자.

그 이동할 Activity 를 만들어 볼 것인데,

values 를 입력받을 액티비티이므로

이름을 InputActivity 로 하자.

 

Activity 파일을 만들 상위 폴더 우클릭

New > Kotlin Class/File

(단점: manifest 파일에 자동으로 Activity 선언이 안 됨)


2-2) activity_input.xml 파일 생성

InputActivity.kt 에서 setContentView() 에서 뷰를 셋팅해아하므로

res > layout 에서 activity_input.xml 파일도 추가하자.

 

setContentView(R.layout.activity_input)


2-3) gradle : app 에 viewBinding 설정

app 의 하위 수준에 아래 코드 삽입 후, Sync Now

viewBinding {
        enabled = true
    }

2-4) Activity.kt

binding 변수 선언

뷰를 생성하는 inflater 담기

setContentView

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }
}

3) Intent

Intent

개별 구성요소 (예: 2개의 Activity) 사이의 런타임 바인딩을 제공하는 객체

Activity 와 Activity 사이의 화면전환을 할 수 있도록 하는 역할

그 안에 데이터도 넣을 수 있음

 

 

각 구성요소들이 메시지나 의도를 주고받을 때,

인텐트를 통해서 다른 앱을 실행할 수 있음

 

 

Intent 는 영어 뜻대로

우리가 하고자 하는 “의도” 를 담고 있는 객체

 

사용 예시

intent 를 만들고

그 내부에 정보를 넣고

startActivity로 액티비티를 시작한다.


3-1) MainActivity.kt

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Intent
        // 의도: MainActivity 에서 편집 버튼을 누르면
        //      InputActivity 로 이동한다.
        binding.goInputActivityButton.setOnClickListener {
            // 1) this
            //    Intent 가 시작하는 곳의 context 를 알려주어야 함 
            //    ( MainActivity 가 가진 context)
            
            // 2) InputActivity::class.java
            //    InputActivity 를 call 하겠다는 의도
            
            
            // [1] intent 만들기
            val intent = Intent(this, InputActivity::class.java)

            // [2] intent 에 데이터 넣기
            intent.putExtra("intentMessage", "응급의료정보")

            // [3] 다른 Activity 실행
            startActivity(intent)
        }
    }
}

3-2) 앱 실행 시 오류

오류 발생:

InputActivity 가 manifest 파일에 선언되지 않았다.

 


3-3) manifest 파일에 InputActivity 선언

  • 안드로이드 앱에서 manifest 가 하는 역할이런 걸 가지고 있다.
  • 라는 개략적인 내용을 보여준다.
  • 내가 이런 앱이다.

특히 Activity 같은 중요한 컴포넌트들은

반드시 manifest 파일에 선언이 되어야

앱 실행이 가능하다.

  • 앱 실행 시, 처음으로 실행되는 Activity 지정 : MainActivity
  • <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter>

manifests > AndroidManifest.xml

에서 InputActivity 선언해주자.

<activity android:name=".InputActivity"/>

위 한 줄 추가하면 된다.

이후 다시 앱을 실행해보면, 오류없이 잘 실행되는 것을 확인할 수 있다.


3-4) 처음부터 Activity 를 생성

Kotlin Class 가 아닌

처음부터 Activity 를 실행하면

layout 파일도 함께 생성되며

manifest 파일에 Activity 가 자동 선언된다.

 

 

New > Activity > Empty Activity

 

 


4) 전체코드

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Intent
        // 의도: MainActivity 에서 편집 버튼을 누르면
        // InputActivity 로 이동한다.
        binding.goInputActivityButton.setOnClickListener {
            // Intent 가 시작하는 곳의 context 를 알려주어야 함 ( MainActivity 가 가진 context)
            // InputActivity 를 call 하겠다는 의도
            val intent = Intent(this, InputActivity::class.java)

            // intent 에 데이터 넣기
            intent.putExtra("intentMessage", "응급의료정보")

            // 다른 Activity 실행
            startActivity(intent)
        }
    }
}

 

 

InputActivity.kt

class InputActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)

        // 데이터를 잘 받아오는지 확인하려면
        val message = intent.getStringExtra("intentMessage") ?: "없음"
        Log.d("intentMessage", message)

        setContentView(R.layout.activity_input)
    }
}

다음 소단원에서는 InputActivity UI 를 만들어볼 것이다.

응급 의료 정보 UI 를 만들어보자.

 

아래와 같이 이름, 생년월일, 혈액형, 비상 연락처는

글자색이 갈색,

글자 크기는 20sp,

글자 스타일은 bold,

marginTop 은 36sp 로 스타일을 통일하고 싶다.

 

 

 


1) styles.xml

이럴 때, 리소스 파일에서 values 타입의

styles.xml 파일을 만들면

모든 뷰에 일일이 요소를 추가하지 않고도

스타일을 통일할 수 있다.

 

res > New > Android Resource File

 

File name : styles

Resource type : Values

 

 

title 과 content 를 일관성 있게 만들어보려고 한다.

item name 은 attribute 이름을 그대로 사용하면 된다.

 

command + d ( 윈도우에서는 ctrl + d ) 를 누르면

현재 줄이 아랫 줄로 복사가 된다.

 

res > values > styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Title" parent="Widget.AppCompat.TextView">
        <item name="android:textColor">@color/brown</item>
        <item name="android:textSize">24sp</item>
        <item name="android:layout_marginTop">36sp</item>
        <item name="android:textStyle">bold</item>

    </style>

</resources>

style 의 name 은 “Title” 으로 하였다.

 

 

activity_main.xml 에서는 Title 을 style 로 지정하면 된다.

res > layout > activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Title" parent="Widget.AppCompat.TextView">
        <item name="android:textColor">@color/brown</item>
        <item name="android:textSize">24sp</item>
        <item name="android:layout_marginTop">36sp</item>
        <item name="android:textStyle">bold</item>

    </style>
</resources>

 

 

 

다시, 부분만 설명하자면

<TextView
        ...
        android:textSize="20sp"
        android:textColor="@color/brown"
        android:textStyle="bold"
        android:layout_marginTop="36dp"

 

위 부분을

styles 로 대체할 수 있다.

<TextView
        ...
        style="@style/Title"

2) guideline

만약 value 에 사용자가 길이가 긴 문자열을 입력한다면?

이렇게 되면 Title 과 Value 의 영역이 겹치게 된다.

 

이런 문제를 해결하기 위해서

Guideline 을 사용한다.

Value 의 영역을 제한해준다.

 

guideline 에서는 orientation 을 반드시 지정해주어야 한다.

    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 -->
    <androidx.constraintlayout.widget.Guideline
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />
        
    <TextView
        ....
        app:layout_constraintStart_toStartOf="@id/guideLine" />

 


3)maxLines 와 ellipsize

만약 최대 줄 개수를 지정해주고 싶다면,

maxLines 를 지정해주자.

android:maxLines="1"

 

그리고 내용이 정해진 영역 내에 모두 표시될 수 없다면

‘ … ‘ 으로 표시되도록 하고 싶다면,

ellipsize 을 end 로 설정하자.

android:ellipsize="end"

 

<TextView
...
android:text="김주철 이름을 길게 넣으면 어떻게 될까요?"
android:maxLines="1"
android:ellipsize="end"

4) 전체코드

 

res > layout > activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <!-- 이름 -->
    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="이름"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="36dp"
         />

    <TextView
        android:id="@+id/nameValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="김주연 "
        android:maxLines="1"
        android:ellipsize="end"
        style="@style/Value"
        android:layout_marginEnd="36dp"
        app:layout_constraintBaseline_toBaselineOf="@+id/nameTextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 생년월일 -->
    <TextView
        android:id="@+id/birthdateTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="생년월일"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/nameTextView"
        app:layout_constraintTop_toBottomOf="@+id/nameTextView" />

    <TextView
        android:id="@+id/birthdateValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="0000-00-00"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/birthdateTextView"
        app:layout_constraintEnd_toEndOf="@+id/nameValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine"/>

    <!-- 혈액형 -->
    <TextView
        android:id="@+id/bloodtypeTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/birthdateTextView"
        app:layout_constraintTop_toBottomOf="@+id/birthdateTextView" />

    <TextView
        android:id="@+id/bloodtypeValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="A"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/bloodtypeTextView"
        app:layout_constraintEnd_toEndOf="@+id/birthdateValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 비상연락처 -->
    <TextView
        android:id="@+id/emergencyContactTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="비상 연락처"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/bloodtypeTextView"
        app:layout_constraintTop_toBottomOf="@+id/bloodtypeTextView" />

    <TextView
        android:id="@+id/emergencyContactValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="010-0000-0000"
        style="@style/Value"
        app:layout_constraintBaseline_toBaselineOf="@id/emergencyContactTextView"
        app:layout_constraintEnd_toEndOf="@+id/bloodtypeValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />

    <!-- 주의사항 -->
    <TextView
        android:id="@+id/warningTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Title"
        app:layout_constraintStart_toStartOf="@id/emergencyContactTextView"
        app:layout_constraintTop_toBottomOf="@+id/emergencyContactTextView" />

    <TextView
        android:id="@+id/warningTextViewValueTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="주의사항"
        style="@style/Value"
        android:maxLines="4"
        app:layout_constraintBaseline_toBaselineOf="@id/warningTextView"
        app:layout_constraintEnd_toEndOf="@+id/emergencyContactValueTextView"
        app:layout_constraintStart_toStartOf="@id/guideLine" />


    <!-- value 는 사용자의 입력값에 따라 길이가 변경됨 : Guideline -->
    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.4" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

res > values > styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Title" parent="Widget.AppCompat.TextView">
        <item name="android:textColor">@color/brown</item>
        <item name="android:textSize">24sp</item>
        <item name="android:layout_marginTop">36sp</item>
        <item name="android:textStyle">bold</item>
    </style>


    <style name="Value">
        <item name="android:textColor">@color/black</item>
        <item name="android:textSize">20sp</item>
        <item name="android:gravity">end</item>
    </style>

</resources>

 

 

 

res > values > colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="brown">#E36F0F</color>
</resources>

응급의료정보 앱

 

데이터 저장 및 불러오기

 

 

전화 앱 실행하기

 

 

데이터 삭제하기

 

 

1) 개요

구현기능

  • 다양한 유저정보
    • 이름
    • 생년월일
    • 혈액형
    • 비상연락처
    • 기타
  • 화면 전환
  • 다른 앱 실행
  • 데이터 저장

2) 학습 목표

  • 다양한 위젯을 사용하고, 테마를 이용하여 일관성 있는 UI 를 그릴 수 있다.
    • ConstraintLayout 과 다양한 위젯을 활용
    • Style 을 통한 일관성 있는 UI 구성
    • Adapter 에 대한 이해
    • 간단한 데이터 저장
    • 다른 화면으로 이동
    • 다른 앱 실행
  • UI
    • ConstraintLayout
      • guideLine
    • Sytle
    • Theme
    • ImageView
    • RadioButton
    • CheckBox
    • Spinner
    • DatePickerDialog
  • Kotlin
    • const val
    • with
  • Android

0) 복습

1) 소수점이 정확하지 않은 이유는 뭘까요?

  • Java 에서는 실수를 표현할 때는 부동 소수점 방식을 사용 하는데 이 때, 오차가 생길 수 있다. 근사값을 이용하기 때문이다. 부정확성을 해결하기 위해, BigDecimal 이라는 자료형을 사용하면 된다.
    • 상세한 이유는 이해하지 못하더라도, 소수점이 정확하지 않을 수 있다는 점을 인지하고, 정확한 계산을 필요로 할 때는 다른 자료형을 사용하면 됨
    • https://ko.wikipedia.org/wiki/부동소수점

2) Activity Lifecycle 을 충분히 이해해봅시다.

+ Recent posts