본문 바로가기

Android

Xml - style 구성 / Intent 관리

이번 포스팅에서는 Kotlin 기초를 마무리 한 상태에서 직접 앱을 개발해보며 하나씩 내용 확인을 하도록 하겠습니다.

개발할 앱은 여러 단위 프로젝트를 통해서 만들어 볼 예정입니다.

여러 단위 프로젝트로 포스팅이 모두 완료가 된다면 실제 서비스를 만들어가는 과정을 포스팅하며 정리해보도록 하겠습니다.

 

 

 

우선 이번 포스팅에서는 응급진료기록을 가져오는 부분을 할 건데 세 차례에 걸쳐서 핵심 개념들을 나눠 설명하도록 하겠습니다.

 

1. style 구성을 두어서 xml 내용을 공통적으로 처리한다.

xml을 구성하다보면 공통된 style을 쓸 때가 있습니다.  이 부분을 동일하게 구성하도록 셋팅하는 방법입니다.

 

style.xml 만들기

 

이렇게 리소스 파일을 만드는데 values 폴더안에서 style.xml을 만듭니다.

style.xml에서는 공통적으로 사용하는 속성에 대해서 셋팅하면 되는데, 이번 단위 프로젝트에서는 Texview를 공통적으로 쓸 것이고

textColor, textSize 등 공통적으로 속성을 쓸 것이기 때문에 해당 내용들을 공통 모듈로 만들어보겠습니다.

 

[style.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">36dp</item>
        <item name="android:textStyle">bold</item>
    </style>

    <style name="Value" parent="Title">
        <item name="android:textColor">@color/black</item>
        <item name="android:textSize">20sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:gravity">end</item>
        <item name="android:maxLines">1</item>
        <item name="android:ellipsize">end</item>
        <item name="android:layout_width">0dp</item>
    </style>
</resources>

 

리소스 태그 내 첫 번째 스타일은 TextView를 부모로 갖는 스타일이며 TextView 속성의 textColor, textSize, layout_marginTop, textStyle 이 네 가지에 대해서 정의했습니다.

따라서 다음 style name이 Title인 style로 쓰게되면 다음 내용들이 적용되는 것입니다.

아래 style name이 Value인 style은 parent로 Title을 상속 받았기 때문에 Title인 Style을 그대로 사용할 수 있고

더불어 Value 내에 셋팅한 item들로 적용되어 사용할 수 있습니다.

 

[activity_main.xml]

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

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

    <TextView
        android:id="@+id/name"
        style="@style/Value"
        android:layout_height="wrap_content"
        android:layout_marginEnd="50dp"
        android:text="함성호"
        app:layout_constraintBaseline_toBaselineOf="@+id/txtName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent" />


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

    <TextView
        android:id="@+id/birthDate"
        style="@style/Value"
        android:layout_height="wrap_content"
        android:text="1992.07.04"
        app:layout_constraintBaseline_toBaselineOf="@+id/txtBirthDate"
        app:layout_constraintEnd_toEndOf="@+id/name"
        app:layout_constraintStart_toStartOf="@id/guideline" />

    <TextView
        android:id="@+id/txtBloodType"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="혈액형"
        app:layout_constraintStart_toStartOf="@+id/txtName"
        app:layout_constraintTop_toBottomOf="@+id/txtBirthDate" />

    <TextView
        android:id="@+id/bloodType"
        style="@style/Value"
        android:layout_height="wrap_content"
        android:text="O형"
        app:layout_constraintBaseline_toBaselineOf="@id/txtBloodType"
        app:layout_constraintEnd_toEndOf="@+id/name"
        app:layout_constraintStart_toStartOf="@id/guideline" />

    <TextView
        android:id="@+id/txtPhoneBook"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="연락처"
        app:layout_constraintStart_toStartOf="@+id/txtName"
        app:layout_constraintTop_toBottomOf="@+id/txtBloodType" />

    <TextView
        android:id="@+id/phoneBook"
        style="@style/Value"
        android:layout_height="wrap_content"
        android:text="010-4618-2721"
        app:layout_constraintBaseline_toBaselineOf="@+id/txtPhoneBook"
        app:layout_constraintEnd_toEndOf="@+id/name"
        app:layout_constraintStart_toStartOf="@id/guideline" />

    <TextView
        android:id="@+id/txtEtc"
        style="@style/Title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="주의사항"
        app:layout_constraintStart_toStartOf="@+id/txtName"
        app:layout_constraintTop_toBottomOf="@+id/txtPhoneBook" />

    <TextView
        android:id="@+id/etc"
        style="@style/Value"
        android:layout_height="wrap_content"
        android:text="주의사항 값"
        app:layout_constraintBaseline_toBaselineOf="@+id/txtEtc"
        app:layout_constraintEnd_toEndOf="@+id/name"
        app:layout_constraintStart_toStartOf="@id/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/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="30dp"
        android:layout_marginBottom="50dp"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:srcCompat="@android:drawable/ic_menu_edit" />


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

다음처럼 셋팅하게 되면 style="@style/Title" 또는 style="@style/Value" 로 셋팅하기 때문에 앞서 설정한 내용들이 공통적으로

적용되어 보여지게 됩니다. 

 

결과 사진

 

이렇듯, xml에서 쓰는 공통적인 내용은 res/values에서 공통 모듈로 셋팅할 수 있습니다.


 

 

다음은 리소스 아이디를 통해 찾아서 하는 것이 아니라 ViewBinding을 통해 객체를 수신하는 방법을 설명하겠습니다.

우선 build.gradle(app)에 android { } 블록안에다가 viewBinding { enable = true } 를 적고 동기화를 진행합니다.

 

뷰바인딩 셋팅

 

이렇게 진행하면 findViewById를 통해 아이디를 찾던 것을 ViewBinding을 통해 간단히 찾을 수 있으며,

코드가 간소화되고 효율적이며 ID값을 일일히 기억하지 않아도 자동적으로 찾을 수 있습니다.

또한 ViewBinding은 내부적으로 LayoutInflater를 가지고 있기 때문에 inflate만 진행하면 자동으로 xml에

바인딩 될 수 있고, 바인딩 객체를 만들 때에는 xml의 이름에 따라서 카멜문자로 셋팅됩니다.

 

 

[MainActivity.kt]

package com.example.chapter4

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.chapter4.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    companion object {
        const val TAG = "MainActivity"
    }
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }

        binding.floatingActionButton.setOnClickListener {
            var intent: Intent = Intent(this, InputActivity::class.java).apply {
                putExtra("IntentMessage","응급의료정보")
            }
            Log.d(TAG, intent.getStringExtra("IntentMessage").toString())
            startActivity(intent)
        }
    }
}

 

다음 코드에서 확인이 가능하듯, ActivityMainBinding은 activity_main.xml을 토대로 바인딩하기에 

이름이 이렇게 되는 것이고, 내부적으로 LayoutInflater가 존재하므로 inflate가 진행되게 됩니다.

또한 setContentView에는 binding에 root를 넣어주면 됩니다.

 

내부에 설정한 위젯 접근은 binding.객체ID 로 접근하면 되는데, binding.floatingActionButton 처럼 진행하면 됩니다.

다음 플로팅 버튼을 선택했을경우, 다른 액티비티로 Intent를 통해 이동하는 것을 하고자 하므로 다음처럼 정의했습니다.

 binding.floatingActionButton.setOnClickListener {
       var intent: Intent = Intent(this, InputActivity::class.java).apply {
           putExtra("IntentMessage","응급의료정보")
       }
       Log.d(TAG, intent.getStringExtra("IntentMessage").toString()
       startActivity(intent)
}

 

Intent 내 첫번째 인자는 현재 액티비티이고 다음 인자는 이동할 액티비티 입니다.

::class.java로 접근하는 것이 조금 생소할 수 있으니 익혀두면 좋겠습니다.

더불어 apply는 확장함수로 객체 자체에 값을 셋팅하는 것이기 때문에 Intent에다가 putExtra로 메시지를 정의해 보냅니다.

다음 내용을 받는 InputActivity에서도 값이 String이니까 intent.getStringExtra로 보낸 메시지를 확인할 수 있습니다.

 

 

 

[InputActivity.kt]

package com.example.chapter4

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.chapter4.databinding.InputActivityBinding

class InputActivity : AppCompatActivity() {
    companion object {
        const val TAG = "InputActivity"
    }

    private lateinit var binding: InputActivityBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = InputActivityBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Log.d(TAG, intent.getStringExtra("IntentMessage").toString())
    }
}

 

 

이 결과는 아래와 같습니다.

플로팅 버튼을 선택했을 경우 찍히는 로그로 확인한 결과입니다.

 

결과 로그

 

 

 

Intent에는 명시적/암시적이 있고 그 내용도 다양하며 사용처가 많으므로 추후에 다시 정리해보도록 하겠습니다.

복습 차원에서 Intent 관련 Document도 참조하겠습니다.     감사합니다.

 

https://developer.android.com/reference/android/content/Intent

반응형