<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Beautify.log</title>
        <link>https://velog.io/</link>
        <description>tried ? drinkCoffee : keepGoing;</description>
        <lastBuildDate>Wed, 16 Feb 2022 07:01:46 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Beautify.log</title>
            <url>https://images.velog.io/images/htwenty-1/profile/4978884f-e3db-4e24-94e6-73c344d0026d/8C2795D8-A887-436C-9B7D-D4FE09CC1246.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Beautify.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/htwenty-1" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[블로그 이전]]></title>
            <link>https://velog.io/@htwenty-1/%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84</link>
            <guid>https://velog.io/@htwenty-1/%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%9D%B4%EC%A0%84</guid>
            <pubDate>Wed, 16 Feb 2022 07:01:46 GMT</pubDate>
            <description><![CDATA[<p>티스토리로 이전합니다</p>
<p>이 블로그도 계속 사용합니다.</p>
<p><a href="https://beautify-log.tistory.com">https://beautify-log.tistory.com</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : Sqlite]]></title>
            <link>https://velog.io/@htwenty-1/Android-Sqlite</link>
            <guid>https://velog.io/@htwenty-1/Android-Sqlite</guid>
            <pubDate>Thu, 10 Feb 2022 22:38:40 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<h3 id="웹에서의-db">웹에서의 DB</h3>
<p>웹에서는 클라이언트(화면단)가 서버에 어떤 정보를 달라고 요청할 때, 서버는 데이터베이스로부터 그 정보를 꺼내서 클라이언트로 보내줍니다.</p>
<p>Spring으로 예를 들면 DAO를 통해 DB에 접근하게 되는데 이 때 중간다리 역할로 MyBatis 같은 도구를 사용합니다.</p>
<p>이는 클라이언트, 서버, DB가 각각 독립된 환경임을 가정했을 때 성립할 수 있습니다.</p>
<h3 id="안드로이드의-db">안드로이드의 DB</h3>
<p>물론 안드로이드에서도 독립된 DB로부터 데이터를 받아와서 화면단에 표현해 줄 수 있습니다.</p>
<p>그렇지만 굳이 외부에 있는 DB에 접근해서 정보를 가져올 필요가 없을 때, 다시 말해서 내부적으로만 데이터 교환이 이루어지는 경우가 있다고 가정한다면 외부에서 데이터를 가져오는 것은 다소 비효율적일 수 있습니다.</p>
<p>그래서 기기 내부에서만 사용할 수 있는 DB 시스템을 제공하는데, 안드로이드에서는 이 서비스를 Sqlite라는 이름으로 제공합니다.</p>
<br>

<h2 id="sqlite-사용하기">Sqlite 사용하기</h2>
<hr>
<h3 id="dbhelper-작성하기">DBHelper 작성하기</h3>
<p>우선 DBHelper가 필요합니다. 이는 클래스이며 다음과 같이 작성합니다.</p>
<pre><code class="language-kotlin">class DBHelper(context: Context?, 
               name: String?, 
               factory: SQLiteDatabase.CursorFactory?, 
               version: Int)
              : SQLiteOpenHelper(context, name, factory, version)</code></pre>
<p>이 클래스는 멤버변수로 <code>context</code>, <code>name</code>, <code>factory</code>, <code>version</code>을 갖고 <code>SQLiteOpenHelper</code> 클래스를 상속 받습니다.</p>
<p>내부에는 기본적으로 <code>onCreate</code>와 <code>onUpgrade</code>가 오버라이드 되어야 합니다.</p>
<pre><code class="language-kotlin">class DBHelper(context: Context?, 
               name: String?, 
               factory: SQLiteDatabase.CursorFactory?, 
               version: Int)
              : SQLiteOpenHelper(context, name, factory, version) {
    override fun onCreate(db: SQLiteDatabase?) {
        // 테이블 생성
        var sql : String = &quot; CREATE TABLE IF NOT EXISTS TEST( &quot; +
                           &quot;    SEQ INTEGER PRIMARY KEY AUTOINCREMENT, &quot; +
                           &quot;    TXT TEXT) &quot;

        db?.execSQL(sql)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        var sql : String = &quot; DROP TABLE IF EXISTS TEST &quot;
        db?.execSQL(sql)
        onCreate(db)
    }
}</code></pre>
<p>내부에는 SQL 쿼리문이 들어가며 <code>execSQL</code>을 통해 쿼리문을 실행시켜줍니다.</p>
<p>CRUD를 구성하여 보았습니다.</p>
<pre><code class="language-kotlin">import android.annotation.SuppressLint
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper

class DBHelper(context: Context?, name: String?, factory: SQLiteDatabase.CursorFactory?, version: Int)
              : SQLiteOpenHelper(context, name, factory, version) {

    override fun onCreate(db: SQLiteDatabase?) {
        // 테이블 생성
        var sql : String = &quot; CREATE TABLE IF NOT EXISTS TEST( &quot; +
                           &quot;    SEQ INTEGER PRIMARY KEY AUTOINCREMENT, &quot; +
                           &quot;    TXT TEXT) &quot;

        db?.execSQL(sql)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        var sql : String = &quot; DROP TABLE IF EXISTS TEST &quot;
        db?.execSQL(sql)
        onCreate(db)
    }

    // CRUD
    fun insert(db:SQLiteDatabase, txt:String) {
        val sql = &quot; INSERT INTO TEST(TXT) &quot; +
                  &quot; VALUES(&#39;${txt}&#39;) &quot;
        db.execSQL(sql)
    }

    @SuppressLint(&quot;Range&quot;)
    fun read(db:SQLiteDatabase, txt: String) : String? {
        val sql = &quot; SELECT TXT FROM TEST &quot; +
                  &quot; WHERE TXT = &#39;$txt&#39; &quot;

        var res = db.rawQuery(sql, null)

        var str:String? = &quot;&quot;
        while(res.moveToNext()) {
            str += res.getString(res.getColumnIndex(&quot;SEQ&quot;)) + &quot; &quot; + &quot;&quot; + res.getString(res.getColumnIndex(&quot;TXT&quot;))
        }

        return str
    }

    fun update(db:SQLiteDatabase, txt:String, wantToEdit:String) {
        val sql = &quot; UPDATE TEST &quot; +
                  &quot; SET TXT = &#39;$wantToEdit&#39;&quot; +
                  &quot; WHERE TXT = &#39;$txt&#39; &quot;
        db.execSQL(sql)
    }

    fun delete(db:SQLiteDatabase, txt:String) {
        val sql = &quot; DELETE FROM TEST &quot; +
                  &quot; WHERE TXT = &#39;$txt&#39; &quot;
        db.execSQL(sql)
    }
}</code></pre>
<h3 id="mainactivity에서-crud-사용">MainActivity에서 CRUD 사용</h3>
<pre><code class="language-kotlin">package com.example.sample36

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // db에 넣어주기
        var dbHelper = DBHelper(this, &quot;testdb.db&quot;, null, 1)

        val insertBtn = findViewById&lt;Button&gt;(R.id.insertBtn)
        val editInsert = findViewById&lt;EditText&gt;(R.id.editInsert)
        val wantToEdit = findViewById&lt;EditText&gt;(R.id.wantToEdit)

        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        val readBtn = findViewById&lt;Button&gt;(R.id.readBtn)
        val updateBtn = findViewById&lt;Button&gt;(R.id.updateBtn)
        val deleteBtn = findViewById&lt;Button&gt;(R.id.delBtn)

        val database = dbHelper.writableDatabase
        val db = dbHelper.readableDatabase

        // CREATE
        insertBtn.setOnClickListener {
            val txt = editInsert.text
            dbHelper.insert(database, txt.toString())
        }

        // READ
        readBtn.setOnClickListener {
            val txt = arrayOf(editInsert.text)
            val res:String? = dbHelper.read(db, txt.toString())
            textView.text = res
        }

        // UPDATE
        updateBtn.setOnClickListener {
            val txt = editInsert.text
            val wantEdit = wantToEdit.text
            dbHelper.update(database, txt.toString(), wantEdit.toString())
        }

        // DELETE
        deleteBtn.setOnClickListener {
            val txt = editInsert.text
            dbHelper.delete(database, txt.toString())
        }

    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : 장면 전환 시 데이터 주고받기]]></title>
            <link>https://velog.io/@htwenty-1/Android-%EC%9E%A5%EB%A9%B4-%EC%A0%84%ED%99%98-%EC%8B%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A3%BC%EA%B3%A0%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@htwenty-1/Android-%EC%9E%A5%EB%A9%B4-%EC%A0%84%ED%99%98-%EC%8B%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A3%BC%EA%B3%A0%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Thu, 10 Feb 2022 21:51:12 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<h3 id="접근">접근</h3>
<p>예를 들어서 어떤 화면에서 값을 입력받아 버튼을 누르면 다른 화면으로 이동해서 컨텐츠를 보여줘야 하는 경우가 있습니다.</p>
<p>Fragment를 사용하지 않고 아예 다른 화면으로 넘어가서 이전 화면에서 입력받은 정보를 불러와 처리해야 한다면 가장 기본적으로 DB에 입력받은 데이터를 저장하고 다른 화면에서 DB에 들어간 정보를 다시 불러와서 처리해주는 방식을 떠올릴 수 있을 것입니다.</p>
<p>그러나 간단한 숫자나 문자열 등을 DB에 저장해서 다시 이를 불러오는 작업은 그렇게 효율적이라는 생각은 들지 않는 것 같습니다.</p>
<p>Spring에서 <code>Model</code>이라는 객체를 사용하여 <code>addAttribute</code>로 전달해줄 값을 설정해주고 이를 불러올 곳에서 <code>getAttribute</code>로 값을 불러와 사용했습니다.</p>
<p>마찬가지로 안드로이드에서는 <code>getSharedPreferences</code>를 사용할 수 있습니다. 그러나 <code>getSharedPreferences</code>는 기본 자료형의 형태만 전달할 수 있다는 단점이 있습니다.</p>
<p>다시 말해서 <code>object</code> 형태는 전달해 줄 수 없다는 뜻인데, <code>object</code>를 전달해주기 위해서 <code>Parcelable</code>를 사용할 수 있습니다.</p>
<p>또는 값을 서로 전달하여 받는 방식 이외에 싱글턴이라는 공동 공유공간을 만들어서 값을 끌어올 수도 있습니다.</p>
<p>그러면 지금부터 각각을 어떻게 사용할 수 있는지 살펴보겠습니다.</p>
<br>

<h2 id="getsharedpreferences"><code>getSharedPreferences</code></h2>
<hr>
<h3 id="메인-레이아웃-구성">메인 레이아웃 구성</h3>
<p>장면 전환을 위해 레이아웃을 두개 만들 것입니다. 우선 메인 레이아웃을 다음과 같이 구성하였습니다</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;EditText
            android:id=&quot;@+id/editText&quot;
            android:layout_width=&quot;496dp&quot;
            android:layout_height=&quot;54dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintVertical_bias=&quot;0.158&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/write&quot;
            android:text=&quot;Preference 쓰기&quot;
            android:layout_width=&quot;495dp&quot;
            android:layout_height=&quot;54dp&quot; 
            app:layout_constraintTop_toBottomOf=&quot;@+id/editText&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot; 
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintHorizontal_bias=&quot;0.504&quot;
            app:layout_constraintVertical_bias=&quot;0.098&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/move&quot;
            android:text=&quot;다음 화면으로 이동&quot;
            android:layout_width=&quot;495dp&quot;
            android:layout_height=&quot;54dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/editText&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot; 
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintHorizontal_bias=&quot;0.504&quot;
            app:layout_constraintVertical_bias=&quot;0.242&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="서브-레이아웃-구성">서브 레이아웃 구성</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.SecondActivity&quot;&gt;

    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:text=&quot;TextView&quot;
            android:layout_width=&quot;395dp&quot;
            android:layout_height=&quot;127dp&quot;
            android:textSize=&quot;30dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.283&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/read&quot;
            android:text=&quot;Preference 읽기&quot;
            android:layout_width=&quot;431dp&quot;
            android:layout_height=&quot;80dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.502&quot;
            app:layout_constraintVertical_bias=&quot;0.255&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="mainactivity"><code>MainActivity</code></h3>
<p>레이아웃을 구성하였으니 이제 버튼을 클릭했을 때 다음 화면으로 넘겨줄 정보를 입력받고 다음화면으로 넘겨서 그 정보를 가져와 보겠습니다.</p>
<p>메인 화면에서는 두개의 버튼을 준비했습니다. 넘겨줄 정보를 저장해주고 다음 페이지로 넘기는 작업을 해보겠습니다.</p>
<pre><code class="language-kotlin">import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val write = findViewById&lt;Button&gt;(R.id.write)
        val move = findViewById&lt;Button&gt;(R.id.move)

        val edit = findViewById&lt;EditText&gt;(R.id.editText)</code></pre>
<p>우선 컴포넌트들을 아이디 값으로 불러옵니다.</p>
<pre><code class="language-kotlin">        write.setOnClickListener {
            val pref = getSharedPreferences(&quot;pref&quot;, MODE_PRIVATE)
            val editor = pref.edit()        // 초기화
            editor.putString(&quot;myData&quot;, edit.text.toString())
            editor.apply()
            edit.setText(&quot;&quot;)
        }</code></pre>
<p>변수 <code>write</code>로 지정된 버튼을 클릭했을 때 이벤트 리스너입니다.</p>
<p><code>pref</code> 변수에는 <code>getSharedPreferences</code>를 넣어주었습니다. 이 넘겨줄 정보의 이름이 <code>&quot;pref&quot;</code>이며 <code>MODE_PRIVATE</code>로 지정하여 새로운 값을 넣어줄 때마다 덮어쓰기 하게 해주었습니다.</p>
<p><code>editor</code> 변수에는 <code>pref</code>를 초기화 하기 위한 것이 들어있습니다.</p>
<p><code>putString</code>을 통해 <code>&quot;myData&quot;</code>라는 이름으로 사용자 입력 컴포넌트에 있는 값을 문자열로 넣어줍니다.</p>
<p><code>apply()</code>를 통해 적용해주고 작업이 완료되면 빈칸으로 세팅합니다.</p>
<pre><code class="language-kotlin">        move.setOnClickListener {
            val i = Intent(this, SecondActivity::class.java)
            startActivity(i)
        }

    }
}</code></pre>
<p>다음 페이지로 이동하는 버튼을 눌렀을 때 <code>SecondActivity</code>로 넘겨줍니다.</p>
<blockquote>
<p><strong>Activity는 앱 안의 단일 화면을 나타냅니다. Activity의 새 인스턴스를 시작하려면 Intent를 startActivity()로 전달하면 됩니다. Intent는 시작할 액티비티를 설명하고 모든 필수 데이터를 담습니다.</strong>
- 안드로이드 개발자 문서</p>
</blockquote>
<p>다시 말해서 <code>Intent</code>를 통해 이 페이지에서 다른 페이지로 넘겨줄 것임을 명시해주고 <code>startActivity</code>로 전달하여 다음 페이지로 이동하게 해주었습니다.
<br></p>
<h2 id="parcelable"><code>Parcelable</code></h2>
<hr>
<h3 id="메인-화면-레이아웃-구성">메인 화면 레이아웃 구성</h3>
<p><code>Parcelable</code>을 살펴보기 위해 메인 레이아웃과 서브 레이아웃을 만들어주겠습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;EditText
            android:id=&quot;@+id/editName&quot;
            android:layout_width=&quot;392dp&quot;
            android:layout_height=&quot;55dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.193&quot;
    /&gt;
    &lt;EditText
            android:id=&quot;@+id/editCount&quot;
            android:layout_width=&quot;392dp&quot;
            android:layout_height=&quot;55dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.279&quot;
    /&gt;
    &lt;EditText
            android:id=&quot;@+id/editLevel&quot;
            android:layout_width=&quot;392dp&quot;
            android:layout_height=&quot;55dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.369&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/move&quot;
            android:text=&quot;Button&quot;
            android:layout_width=&quot;393dp&quot;
            android:layout_height=&quot;53dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.525&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.497&quot;
    /&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="서브-레이아웃-구성-1">서브 레이아웃 구성</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.SecondActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:text=&quot;TextView&quot;
            android:textSize=&quot;30dp&quot;
            android:layout_width=&quot;413dp&quot;
            android:layout_height=&quot;130dp&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.502&quot;
            app:layout_constraintVertical_bias=&quot;0.187&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/read&quot;
            android:text=&quot;읽기&quot;
            android:layout_width=&quot;271dp&quot;
            android:layout_height=&quot;57dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            app:layout_constraintVertical_bias=&quot;0.239&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="dto-구성">DTO 구성</h3>
<p><code>object</code> 전달 연습을 위해 DTO를 하나 만들어주겠습니다.</p>
<pre><code class="language-kotlin">package dto

import android.os.Parcel
import android.os.Parcelable

class Student(var name: String?, var count:Int, var level: String?) : Parcelable {

    constructor(parcel: Parcel):this(parcel.readString(), parcel.readInt(), parcel.readString()) {}


    override fun writeToParcel(parcel: Parcel?, p1: Int) {
        parcel?.writeString(name)
        parcel?.writeInt(count)
        parcel?.writeString(level)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator&lt;Student&gt; {
        override fun createFromParcel(parcel: Parcel): Student {
            return Student(parcel)
        }

        override fun newArray(size: Int): Array&lt;Student?&gt; {
            return arrayOfNulls(size)
        }
    }


}</code></pre>
<p>우리는 장면 전환 시 객체를 전달해줄 것이기 때문에 전달해줄 형태의 객체는 <code>Parcelable</code>을 상속받아야 합니다.</p>
<p><code>Parcelable</code>을 상속받았기 때문에 <code>writeToParcel</code>과 <code>describeContents</code>의 오버라이드가 필요합니다.</p>
<p>또한 <code>companion object</code>의 형태로 <code>CREATOR</code>가 구현되어야 합니다.</p>
<h3 id="mainactivity-1">MainActivity</h3>
<p>역시 버튼 클릭시 이벤트를 발생시켜보겠습니다.</p>
<pre><code class="language-kotlin">import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import dto.Student

// preference는 기본자료형만 보낼 수 있어서...
// intent를 사용하면 객체를 전달해줄 수 있다!
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editName = findViewById&lt;EditText&gt;(R.id.editName)
        val editCount = findViewById&lt;EditText&gt;(R.id.editCount)
        val editLevel = findViewById&lt;EditText&gt;(R.id.editLevel)

        val move = findViewById&lt;Button&gt;(R.id.move)

        move.setOnClickListener {
            var student = Student(editName.text.toString(), editCount.text.toString().toInt(), editLevel.text.toString())
            val nextIntent = Intent(this, SecondActivity::class.java)
            nextIntent.putExtra(&quot;student&quot;, student)
            startActivity(nextIntent)
        }

    }
}</code></pre>
<p>버튼을 클릭했을 때 객체를 생성하여 생성에 필요한 것들을 넣어주었습니다.</p>
<p>그리고 다음 페이지로 넘어가기 위해 <code>Intent</code>를 사용하였습니다.</p>
<p>이 때 <code>putExtra</code>를 사용하여 <code>&quot;student&quot;</code>라는 이름으로 <code>student</code> 변수에 저장된 객체를 넘겨줍니다.</p>
<h3 id="subactivity">SubActivity</h3>
<p>메인 페이지에서 다음 화면으로 넘어왔을 때 처리해 줄 것들입니다.</p>
<pre><code class="language-kotlin">import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import dto.Student

class SecondActivity : AppCompatActivity() {
    @SuppressLint(&quot;SetTextI18n&quot;)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        val read = findViewById&lt;Button&gt;(R.id.read)
        read.setOnClickListener {
            val student = intent.getParcelableExtra&lt;Student&gt;(&quot;student&quot;)
            if (student != null) {
                textView.text = &quot;${student.name} ${student.count} ${student.level}&quot;
            }
        }
    }
}</code></pre>
<p><code>read</code> 버튼 클릭 시 <code>getParcelableExtra</code>로 메인 화면에서 전달해 준 <code>&quot;student&quot;</code>를 받아옵니다.</p>
<p><code>null</code>이 아닌 경우 텍스트뷰에 받아온 정보를 뿌려줍니다.</p>
<br>

<h2 id="singleton"><code>Singleton</code></h2>
<hr>
<p>싱글톤은 전역변수를 선언하지 않더라도 싱글톤 객체 하나만을 생성하여 어디서든 참조할 수 있게 해줍니다.</p>
<h3 id="메인-레이아웃">메인 레이아웃</h3>
<p>화면 이동간 싱글톤을 통해 메인 레이아웃에서 입력한 텍스트를 서브 레이아웃에서 받아올 것입니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;EditText
            android:id=&quot;@+id/editText&quot;
            android:layout_width=&quot;428dp&quot;
            android:layout_height=&quot;72dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:text=&quot;Name&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintVertical_bias=&quot;0.382&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/move&quot;
            android:text=&quot;Button&quot;
            android:layout_width=&quot;264dp&quot;
            android:layout_height=&quot;52dp&quot; 
            app:layout_constraintTop_toBottomOf=&quot;@+id/editText&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintVertical_bias=&quot;0.25&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="서브-레이아웃">서브 레이아웃</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.SubActivity&quot;&gt;

    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:text=&quot;TextView&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;334dp&quot;
            android:layout_height=&quot;84dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="싱글톤-생성">싱글톤 생성</h3>
<pre><code class="language-kotlin">class Singleton {

    companion object {

        var chicken:String? = null
    }
}</code></pre>
<p>싱글톤은 반드시 <code>companion object</code>가 선언되어야 합니다.</p>
<p>이 싱글톤 객체는 어디서든 참조할 수 있게 됩니다. 초기값을 <code>null</code>로 지정하였습니다.</p>
<h3 id="mainactivity-2">MainActivity</h3>
<pre><code class="language-kotlin">import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editText = findViewById&lt;EditText&gt;(R.id.editText)
        val move = findViewById&lt;Button&gt;(R.id.move)

        move.setOnClickListener {
            // 싱글턴 호출 및 적용
            Singleton.chicken = editText.text.toString()

            // 이동
            val intent = Intent(this, SubActivity::class.java)
            startActivity(intent)
        }

    }
}</code></pre>
<p>싱글톤을 호출할 때는 <code>Singleton.</code>으로 할 수 있으며 내부에 선언된 변수를 붙여주면 됩니다.</p>
<h3 id="subactivity-1">SubActivity</h3>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView

class SubActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sub)

        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        textView.text = Singleton.chicken.toString()
    }
}</code></pre>
<p>싱글톤에 있는 정보를 가져올 때도 <code>Singleton.</code>으로 불러올 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : JSON 파일 파싱하기]]></title>
            <link>https://velog.io/@htwenty-1/Android-JSON-%ED%8C%8C%EC%9D%BC-%ED%8C%8C%EC%8B%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@htwenty-1/Android-JSON-%ED%8C%8C%EC%9D%BC-%ED%8C%8C%EC%8B%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 10 Feb 2022 11:19:40 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<h3 id="json이란">JSON이란?</h3>
<p>JSON은 JavaScript Object Notation의 약자로 자바스크립트의 객체 문법을 사용해 데이터를 전달하거나 받기 위해 사용하는 것입니다.</p>
<p>&quot;키 - 값&quot;의 구조로 되어 있으며 RESTful API로 데이터를 전송하는데 큰 역할을 합니다.</p>
<br> 

<h2 id="json-파일-parsing">JSON 파일 Parsing</h2>
<hr>
<h3 id="json-파일-준비">JSON 파일 준비</h3>
<p><code>main</code> 디렉터리 하위에 <code>assets</code> 디렉터리를 만들어줍니다.</p>
<pre><code class="language-json">[
  {
    &quot;id&quot;: &quot;kotlin&quot;,
    &quot;language&quot;: &quot;코틀린&quot;
  },
  {
    &quot;id&quot;: &quot;java&quot;,
    &quot;language&quot;: &quot;자바&quot;
  },
  {
    &quot;id&quot;: &quot;swift&quot;,
    &quot;language&quot;: &quot;스위프트&quot;
  }
]</code></pre>
<h3 id="json-파일-읽어오기">JSON 파일 읽어오기</h3>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import org.json.JSONArray

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // JSON 파일에 접근해서 문자열을 가져와보자!
        val jsonString = assets.open(&quot;data.json&quot;).reader().readText()
        Log.d(&quot;JSON STR&quot;, jsonString)</code></pre>
<p>우선은 문자열을 가져오는 방법입니다.
<code>assets</code> 디렉터리로 접근해서 <code>open</code>을 사용하여 파일을 열어줍니다. 이것을 <code>reader</code>로 읽어주는데 이 때 텍스트형식으로 읽어오라는 것입니다.</p>
<pre><code class="language-kotlin">        // JSON 파일에 접근해서 배열 형식으로 가져와보자!
        val jsonArray = JSONArray(jsonString)
        Log.d(&quot;json str&quot;, jsonArray.toString())
</code></pre>
<p><code>JSONArray</code>를 사용하면 배열 형식으로 가져올 수도 있습니다.</p>
<pre><code class="language-kotlin">        // JSON 파일에 접근해서 key값으로 value를 뽑아보자!

        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        for (i in 0 until jsonArray.length()) {
            val jsonObject = jsonArray.getJSONObject(i)

            textView.append(&quot;\n--------------------------\n&quot;)     // 경계선

            val id = jsonObject.getString(&quot;id&quot;)
            val language = jsonObject.getString(&quot;language&quot;)

            textView.append(
                &quot;&quot;&quot;
                    $id
                &quot;&quot;&quot;.trimIndent()
            )

            textView.append(
                &quot;&quot;&quot;
                    $language
                &quot;&quot;&quot;.trimIndent()
            )


        }
    }
}</code></pre>
<p>마지막으로 <code>key</code> 값을 가지로 <code>value</code>를 얻어서 텍스트뷰에 뿌려주겠습니다.</p>
<p>위에서 만든 배열을 돌며 값을 꺼내와보겠습니다.</p>
<p><code>jsonArray</code> 즉 배열로 만들어진 것을 가지고 <code>getJSONObject()</code>를 사용해주었습니다.</p>
<p><code>getJSONObject()</code>를 사용하면 <code>index</code>에 대한 <code>value</code> 값을 리턴해줍니다.</p>
<p>이 때 <code>index</code>를 <code>key</code>라고 생각하면 이해하는데 도움이 될 것 같습니다.</p>
<p>이는 객체상태이므로 문자열을 얻어와서 텍스트뷰에 뿌리기 위해서는 <code>getString</code> 메서드가 필요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: 파일 입출력]]></title>
            <link>https://velog.io/@htwenty-1/Android-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5</link>
            <guid>https://velog.io/@htwenty-1/Android-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5</guid>
            <pubDate>Thu, 10 Feb 2022 11:08:24 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<h3 id="파일-입출력이란">파일 입출력이란?</h3>
<p>파일 입출력은 말 그대로 디바이스에 파일로 저장하고 그 파일을 뷰에 출력해주는 일련의 과정을 말합니다.</p>
<br>

<h2 id="파일-입출력-구현을-위한-레이아웃">파일 입출력 구현을 위한 레이아웃</h2>
<hr>
<h3 id="레이아웃">레이아웃</h3>
<p>우선 화면단에서 파일 입출력을 보여주기 위해 레이아웃을 만들어줍니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;EditText
            android:id=&quot;@+id/editText&quot;
            android:layout_width=&quot;494dp&quot;
            android:layout_height=&quot;48dp&quot;
            android:inputType=&quot;textPersonName&quot;
            android:ems=&quot;10&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.172&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/read&quot;
            android:text=&quot;읽기&quot;
            android:layout_width=&quot;323dp&quot;
            android:layout_height=&quot;49dp&quot;
            app:layout_constraintBottom_toTopOf=&quot;@+id/write&quot;
            android:layout_marginBottom=&quot;48dp&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/editText&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            app:layout_constraintVertical_bias=&quot;1.0&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/write&quot;
            android:text=&quot;쓰기&quot;
            android:layout_width=&quot;323dp&quot;
            android:layout_height=&quot;49dp&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintBottom_toTopOf=&quot;@+id/clear&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            android:layout_marginBottom=&quot;52dp&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/clear&quot;
            android:text=&quot;CLEAR&quot;
            android:layout_width=&quot;323dp&quot;
            android:layout_height=&quot;49dp&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            android:layout_marginBottom=&quot;360dp&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<br>

<h2 id="버튼-클릭-시-파일-읽고-쓰기-뷰에-출력">버튼 클릭 시 파일 읽고 쓰기, 뷰에 출력</h2>
<hr>
<p>코드를 뜯어가며 하나씩 살펴보겠습니다.</p>
<pre><code class="language-kotlin">import android.os.Bundle
import android.provider.ContactsContract.Intents.Insert.NOTES
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.io.*
import java.lang.Exception

class MainActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val read = findViewById&lt;Button&gt;(R.id.read)
        val write = findViewById&lt;Button&gt;(R.id.write)
        val clear = findViewById&lt;Button&gt;(R.id.clear)

        read.setOnClickListener(this)
        write.setOnClickListener(this)
        clear.setOnClickListener(this)
    }</code></pre>
<p>우선은 뷰에 있는 버튼 세개를 가져옵니다. 각각의 버튼은 클릭 이벤트 리스너가 걸립니다.</p>
<pre><code class="language-kotlin">    override fun onClick(view: View?) {
        val edit = findViewById&lt;EditText&gt;(R.id.editText)

        if(view?.id == R.id.read) {
            var reader:BufferedReader? = null

            try {
                val `in`: InputStream? = openFileInput(NOTES)

                if (`in` != null) {
                    reader = BufferedReader(InputStreamReader(`in`))
                    var str: String?
                    val buf = StringBuffer()

                    // 파일 읽기
                    while (reader.readLine().also { str = it } != null) {
                        println(&quot;$str&quot;)
                        buf.append(&quot;&quot;&quot;$str&quot;&quot;&quot;)  // 실제로 값을 읽는 위치
                    }

                    edit.setText(buf.toString())
                }
            } catch (e:FileNotFoundException) {
                // e.printStackTrace()
                println(e.message)
                println(&quot;파일을 찾을 수 없음&quot;)
            } catch (e:Exception) {
                e.printStackTrace()
                Toast.makeText(this, &quot;exception: $e&quot;, Toast.LENGTH_SHORT).show()
            } finally {
                if(reader != null)
                    try { reader.close() }
                    catch (e:Exception) { e.printStackTrace() }
            }</code></pre>
<p>메인 클래스가 <code>View.OnClickListener</code>를 상속받으므로 <code>onClick</code> 함수가 구현되어야 합니다.</p>
<p><code>view</code>를 매개변수로 받아서 이 변수의 아이디가 위에서 선언한 버튼인 경우에 대해 조건식을 세워줍니다.</p>
<p>우선 읽기입니다.</p>
<p><code>BufferedReader</code>를 준비해줍니다. 그 다음으로 <code>InputStream</code>을 `<code>in</code>`으로 잡아주었습니다. 백틱을 붙여준 이유는 예약어를 변수명으로 사용하기 위함입니다.</p>
<p><code>InputStream</code>은 입력된 데이터를 빨아들이는 것으로 보면 됩니다.</p>
<p>이 때 파일을 스트림으로 읽기 위해 <code>openFileInput</code>을 사용하였습니다. <code>NOTES</code>는 파일 이름입니다.</p>
<p>읽어들인 파일이 <code>null</code>이 아닐 때 <code>BufferedReader</code>로 파일을 읽어주고 읽은 내용을 저장할 변수 <code>str</code>을 준비합니다.</p>
<p>그리고 문자열의 추가/변경을 위해 <code>StringBuffer</code>도 준비해줍니다.</p>
<p>줄단위로 문장을 읽으면서 <code>str</code>에 <code>while</code>루프를 돌며 문장을 추가해주는데, 이것이 <code>null</code>이 아닐 때, 즉 문장이 입력 되어있을 때</p>
<p><code>StringBuffer</code>에 값을 추가해줍니다.</p>
<p>저장된 값을 텍스트입력창에 뿌려줍니다.</p>
<p>기본적으로 파일 입출력은 예외발생 사항이 있을 수 있기 때문에 <code>try catch</code> 처리를 해주는 것이 좋습니다.</p>
<pre><code class="language-kotlin">        } else if (view?.id == R.id.write) {
            var out:OutputStreamWriter? = null

            try {
                // MODE_PRIVATE : 덮어쓰기, MODE_APPEND : 이어쓰기
                out = OutputStreamWriter(openFileOutput(NOTES, MODE_PRIVATE))
                out.write(edit.text.toString())     // 실제로 값을 써줌

                Toast.makeText(this, &quot;데이터 저장&quot;, Toast.LENGTH_SHORT).show()
            } catch (e:Exception) {
                e.printStackTrace()
            } finally {
                if (out != null) try {
                    out.close()
                } catch (e:IOException) { e.printStackTrace() }
            }

        } else if (view?.id == R.id.clear) {
            edit.setText(&quot;&quot;)
        }
    }
}</code></pre>
<p><code>write</code> 버튼을 눌렀을 때 처리할 작업입니다.
스트림으로 파일을 써내려갈 <code>OutputStreamWriter</code>를 준비해줍니다.</p>
<p>그리고 파일을 읽어서 써주기 위해 <code>openFileOutput</code>을 사용하고 매개변수로 파일 이름과 <code>MODE_PRIVATE</code>이라는 덮어쓰기 기능을 넣어줍니다.</p>
<p>데이터가 저장되었다면 토스트를 띄워 데이터 저장에 성공했음을 알려줍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : DatePicker와 TimePicker]]></title>
            <link>https://velog.io/@htwenty-1/Android-DatePicker%EC%99%80-TimePicker</link>
            <guid>https://velog.io/@htwenty-1/Android-DatePicker%EC%99%80-TimePicker</guid>
            <pubDate>Wed, 09 Feb 2022 22:53:01 GMT</pubDate>
            <description><![CDATA[<h2 id="datepicker">DatePicker</h2>
<hr>
<h3 id="개요">개요</h3>
<p>날짜를 선택할 수 있게 해주는 컴포넌트 입니다.</p>
<p>html에서</p>
<pre><code class="language-html">&lt;input type=&quot;date&quot; /&gt;</code></pre>
<p><code>type</code> 속성이 <code>date</code>인 태그는 </p>
<p><img src="https://images.velog.io/images/htwenty-1/post/2548ce2f-d5a6-417b-b7e7-ec8ac21f7c1a/image.png" alt=""></p>
<p>이와 같이 날짜를 선택할 수 있게 해줍니다.</p>
<p>안드로이드에서는 위와 같이 달력에서 날짜를 선택하게 해주는 <code>calendar</code> 형식과 목록에서 직접 날짜를 선택할 수 있게 해주는 <code>spinner</code> 형식을 제공합니다.</p>
<h3 id="calendar-타입의-datepicker"><code>calendar</code> 타입의 DatePicker</h3>
<p><code>calendar</code> 타입의 DatePicker는 아래와 같이 달력형식에서 날짜를 선택할 수 있게 해줍니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/7f21a865-c1a4-42eb-81b5-fc82772974ca/image.png" alt=""></p>
<p>코드를 보면</p>
<pre><code class="language-xml">&lt;DatePicker
    android:id=&quot;@+id/datePicker&quot;
    android:layout_width=&quot;320dp&quot;
    android:layout_height=&quot;430dp&quot;
    android:calendarViewShown=&quot;false&quot;
    android:datePickerMode=&quot;calendar&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/button&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
/&gt;</code></pre>
<p><code>datePickerMode</code>가 <code>calendar</code>로 설정되어있음을 알 수 있습니다!</p>
<h3 id="spinner-타입의-datepicker"><code>spinner</code> 타입의 DatePicker</h3>
<p>DatePicker를 스피너 타입으로 주었을 때는 스피너를 통해 사용자가 직접 날짜를 입력할 수 있게 해줍니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/c999f0b6-af64-4710-86eb-c2d9fe0eb757/image.png" alt=""></p>
<p>이렇게 스피너로부터 날짜를 입력받을 수 있습니다.</p>
<p>이 때는 </p>
<pre><code class="language-xml">&lt;DatePicker
    android:id=&quot;@+id/datePicker&quot;
    android:layout_width=&quot;320dp&quot;
    android:layout_height=&quot;430dp&quot;
    android:calendarViewShown=&quot;false&quot;
    android:datePickerMode=&quot;spinner&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/button&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
/&gt;</code></pre>
<p>이와 같이 <code>android:datePickerMode</code>를 <code>spinner</code>로 주면 됩니다.</p>
<h3 id="값-얻어오기">값 얻어오기</h3>
<p>DatePicker의 타입이 캘린더 타입이든 스피너 타입이든 값을 얻어오는 방법은 동일합니다.</p>
<p><code>Calendar</code>라는 객체를 생성하고 거기에서 <code>getInstance</code>라는 메서드를 통해 값을 얻어옵니다.</p>
<p>다음과 같이 뷰가 구성되어 있다고 할 때</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;388dp&quot;
            android:layout_height=&quot;94dp&quot;
            android:text=&quot;날짜 읽어오기&quot;
            android:textSize=&quot;25sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.116&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/button&quot;
            android:text=&quot;Button&quot;
            android:layout_width=&quot;188dp&quot;
            android:layout_height=&quot;60dp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.105&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;/&gt;

    &lt;DatePicker
            android:id=&quot;@+id/datePicker&quot;
            android:layout_width=&quot;320dp&quot;
            android:layout_height=&quot;430dp&quot;
            android:calendarViewShown=&quot;false&quot;
            android:datePickerMode=&quot;spinner&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/button&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>값을 얻어오고 버튼을 통해 텍스트뷰에 값을 넘겨줘보겠습니다.</p>
<pre><code class="language-kotlin">import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.DatePicker
import android.widget.TextView
import java.util.*

class MainActivity : AppCompatActivity(), View.OnClickListener {
    @SuppressLint(&quot;SetTextI18n&quot;)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val calendar = Calendar.getInstance()
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH)
        val dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH)</code></pre>
<p>우선 초기값으로 오늘 날짜를 보여주기 위해 <code>Calendar</code> 객체의 <code>getInstance</code> 메서드를 통해서 값을 얻어옵니다.
이 때, 연월일은 각각 <code>Calendar.YEAR</code>, <code>Calendar.MONTH</code>, <code>Calendar.DAY_OF_MONTH</code>라고 하는 값을 전달해서 <code>get</code>으로 얻어옵니다.</p>
<pre><code class="language-kotlin">        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        val button = findViewById&lt;Button&gt;(R.id.button)

        textView.text =
                        &quot;&quot;&quot;
                        초기 설정된 날짜 [년도/월/일]
                        $year/${month+1}/$dayOfMonth
                        &quot;&quot;&quot;.trimIndent()

        button.setOnClickListener(this)

    }</code></pre>
<p>텍스트뷰와 버튼을 아이디로 가져온 후 텍스트뷰의 초기값을 오늘 날짜로 지정해줍니다.</p>
<p>메인 클래스에서 <code>View.OnClickListener</code>의 상속을 받았으므로 <code>setOnClickListener</code>로 버튼 클릭시 발생하는 이벤트를 지정해줍니다.</p>
<pre><code class="language-kotlin">    @SuppressLint(&quot;SetTextI18n&quot;)
    override fun onClick(view: View?) {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        val datePicker = findViewById&lt;DatePicker&gt;(R.id.datePicker)

        if(view?.id == R.id.button) {
            textView.text = &quot;초기 설정된 날짜 [년도/월/일] : \n&quot; + datePicker.year.toString() + &quot;/&quot; +
                    (datePicker.month + 1).toString() + &quot;/&quot; + datePicker.dayOfMonth.toString()
        }
    }
}</code></pre>
<p><code>onClick</code> 함수를 오버라이드 해주었습니다.</p>
<p>파라미터로 받아온 뷰(버튼)이 클릭되었을 때 텍스트뷰를 사용자가 지정한 날짜로 바꿔줍니다.</p>
<br>

<h2 id="timepicker">TimePicker</h2>
<hr>
<h3 id="개요-1">개요</h3>
<p>시간을  선택할 수 있게 해주는 컴포넌트입니다.</p>
<p>마찬가지로 html에서는</p>
<pre><code class="language-html">&lt;input type=&quot;time&quot; /&gt;</code></pre>
<p><code>&lt;input&gt;</code>의 타입을 <code>time</code>으로 주면 시간을 입력받을 수 있습니다.</p>
<p>안드로이드에서는 DatePicker와 마찬가지로 스피너를 제공하며 시계UI에서 시간을 입력받기 위해서는 모드를 <code>clock</code>으로 주면 됩니다.</p>
<h3 id="clock-타입의-timepicker"><code>clock</code> 타입의 TimePicker</h3>
<p>시계 모양의 UI를 통해 시간값을 입력하게 할 수 있습니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/6eb6e4de-0df6-4e3e-b1bb-ace69cb67ada/image.png" alt=""></p>
<p>코드를 보면</p>
<pre><code class="language-xml">&lt;TimePicker
    android:id=&quot;@+id/timePicker&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:timePickerMode=&quot;clock&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    app:layout_constraintHorizontal_bias=&quot;0.0&quot;
    app:layout_constraintVertical_bias=&quot;0.275&quot;
/&gt;</code></pre>
<p><code>timePickerMode</code>가 <code>clock</code>으로 설정되어 있습니다.</p>
<h3 id="spinner-타입의-timepicker"><code>spinner</code> 타입의 TimePicker</h3>
<p>DatePicker와 마찬가지로 목록에서 직접 시간을 선택할 수 있게 해주는 <code>spinner</code> 타입도 제공합니다.</p>
<p>코드에서 <code>timePickerMode</code>를 <code>spinner</code>로 바꿔주면</p>
<pre><code class="language-xml">&lt;TimePicker
    android:id=&quot;@+id/timePicker&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
    android:timePickerMode=&quot;spinner&quot;
    app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;
    app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    app:layout_constraintStart_toStartOf=&quot;parent&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    app:layout_constraintHorizontal_bias=&quot;0.0&quot;
    app:layout_constraintVertical_bias=&quot;0.275&quot;
/&gt;</code></pre>
<p><img src="https://images.velog.io/images/htwenty-1/post/2b33103a-0da5-49e6-85f0-03f9444b40fa/image.png" alt=""></p>
<p>이렇게 스피너에서 값을 입력받을 수 있습니다.</p>
<h3 id="값-얻어오기-1">값 얻어오기</h3>
<p>DatePicker에서 값을 얻어오는 방법과 유사합니다.</p>
<p>주의사항은 이벤트 리스너를 사용할 때 TimePicker 값의 변화를 실시간으로 조회하길 원한다면 <code>TimePicker.OnTimeChangedListener</code>를 상속받아야 한다는 것입니다.</p>
<p>여기서는 버튼클릭에 대한 이벤트가 아닌 값이 바뀔 때마다 조회해서 텍스트뷰에 뿌려주는 연습을 해보겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import android.widget.TimePicker
import java.util.*

class MainActivity : AppCompatActivity(), TimePicker.OnTimeChangedListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var cal = Calendar.getInstance()
        val hour = cal.get(Calendar.HOUR_OF_DAY)
        val minute = cal.get(Calendar.MINUTE)</code></pre>
<p>텍스트뷰의 초기값(현재시간) 설정을 위해 현재시간을 가져와 보겠습니다.</p>
<p><code>Calendar</code> 객체의 <code>getInstance</code> 메서드를 받아옵니다.</p>
<p>각각 시, 분을 <code>get</code> 메서드로 얻어오는데 매개변수로 각각 <code>Calendar.HOUR_OF_DAY</code>, <code>Calendar.MINUTE</code>을 사용했습니다.</p>
<pre><code class="language-kotlin">        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        val timePicker = findViewById&lt;TimePicker&gt;(R.id.timePicker)

        textView.text = &quot;현재 설정된 시간 : \n 시:분 | $hour : $minute&quot;
        timePicker.setOnTimeChangedListener(this)
    }</code></pre>
<p>텍스트뷰와 타임피커를 아이디로 가져오고 초기값을 우선 현재 시간으로 지정해줍니다.</p>
<p>그다음 타임피커의 값이 바뀔 때마다 그 값을 조회해서 텍스트뷰에 뿌려주기 위해 타임피커에 이벤트 리스너를 지정해줍니다.</p>
<pre><code class="language-kotlin">    override fun onTimeChanged(view: TimePicker?, hourOfDay: Int, minute: Int) {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        textView.text = &quot;현재 설정된 시간 : \n 시:분 | $hourOfDay : $minute&quot;
    }
}</code></pre>
<p>타임피커의 값이 바뀔 때마다 텍스트뷰에 값을 뿌려줄 함수를 오버라이드하여 구현합니다.</p>
<p><code>TimePicker</code>에서는 원래 &quot;초&quot;단위를 입력받을 수 없습니다. UI에서 보면 아시겠지만 초를 입력하는 곳은 없습니다.</p>
<p>그래서 초를 얻어오기 위해서는 별도의 변수를 선언해서 초를 얻어와야 합니다.</p>
<p>오버라이드한 함수에 단위까지 출력하게 해주기 위해서는 <code>val second:Int = Calendar.SECOND</code>를 별도로 선언해서 텍스트뷰에 집어넣어주면 됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: ImageButton]]></title>
            <link>https://velog.io/@htwenty-1/Android-ImageButton</link>
            <guid>https://velog.io/@htwenty-1/Android-ImageButton</guid>
            <pubDate>Mon, 07 Feb 2022 14:02:30 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<p><code>&lt;Button&gt;</code> 태그로 만들어지는 버튼은 그냥 보기에 다소 투박해 보입니다..</p>
<p>멋있게 커스텀된 버튼을 사용하기 위해서는 버튼을 이미지로 제작하여 그 이미지를 버튼화할 수 있습니다.</p>
<p>이 때 사용하는 것이 <code>&lt;ImageButton&gt;</code>입니다.</p>
<br>

<h2 id="activity_mainxml에-이미지-버튼-넣기"><code>activity_main.xml</code>에 이미지 버튼 넣기</h2>
<hr>
<p>이미지버튼을 다음과 같이 넣어줍니다.</p>
<p>이 때, <code>&lt;ImageButton&gt;</code>의 <code>app:srcCompat</code> 속성에 이미지의 경로가 들어갑니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            android:textSize=&quot;35sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.283&quot;
    /&gt;
    &lt;ImageButton
            android:id=&quot;@+id/imageButton&quot;
            app:srcCompat=&quot;@drawable/button&quot;
            android:layout_width=&quot;362dp&quot;
            android:layout_height=&quot;148dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.489&quot;
            app:layout_constraintVertical_bias=&quot;0.622&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<br>

<h2 id="mainactivity에서-이벤트-추가하기"><code>MainActivity</code>에서 이벤트 추가하기</h2>
<hr>
<p>버튼 클릭시 이벤트를 추가해주겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AlertDialog

class MainActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imgBtn = findViewById&lt;ImageButton&gt;(R.id.imageButton)</code></pre>
<p>우선 이미지 버튼을 <code>findViewById</code>로 불러옵니다.</p>
<pre><code class="language-kotlin">        // xml에 onClick을 쓰지 않아도 됨
        imgBtn.setOnClickListener(this)

    }</code></pre>
<p>기존에는 xml에서 <code>onClick</code>을 추가해주었지만 여기에서는 <code>setOnClickListener</code>를 사용하여 xml에 <code>onClick</code>을 쓰지 않고 여기에서 바로 사용할 수 있게 해주었습니다.</p>
<p>이 때 온클릭 이벤트는 이미지 버튼의 이벤트이므로 <code>this</code>를 매개변수로 주었습니다.</p>
<pre><code class="language-kotlin">    override fun onClick(v: View?) {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        when(v?.id) {
            R.id.imageButton -&gt; {
                val builder = AlertDialog.Builder(this)
                builder.setTitle(&quot;button is clicked&quot;)
                builder.setMessage(&quot;Image Button Clicked!!&quot;)
                builder.show()
                textView.text = &quot;Image Button Clicked!!!&quot;
            }
        }

    }
}</code></pre>
<p><code>View.OnClickListener</code>를 상속받아 <code>onClick</code>을 오버라이드 하였습니다.</p>
<p>뷰의 아이디가 이미지 버튼일 때 <code>AlertDialog</code>를 띄워줍니다.</p>
<p>또한 텍스트뷰의 내용도 바꿔줍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: SeekBar와 RatingBar]]></title>
            <link>https://velog.io/@htwenty-1/Android-SeekBar%EC%99%80-RatingBar</link>
            <guid>https://velog.io/@htwenty-1/Android-SeekBar%EC%99%80-RatingBar</guid>
            <pubDate>Mon, 07 Feb 2022 13:30:51 GMT</pubDate>
            <description><![CDATA[<h2 id="seekbar"><code>SeekBar</code></h2>
<hr>
<h3 id="개요">개요</h3>
<blockquote>
</blockquote>
<p><strong>A SeekBar is an extension of ProgressBar that adds a draggable thumb. The user can touch the thumb and drag left or right to set the current progress level or use the arrow keys. Placing focusable widgets to the left or right of a SeekBar is discouraged.</strong>
- 안드로이드 개발자 문서</p>
<p><code>SeekBar</code>는 손가락을 왼쪽이나 오른쪽으로 드래그해서 진행상황 등을 나타낼 수 있는 도구입니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/8569630e-c552-48a5-a712-f2f6c5d4387e/image.png" alt=""></p>
<p>이런 모양으로 생겼죠..</p>
<p>HTML에서는 <code>&lt;input&gt;</code>에서 <code>range</code>타입을 주어 비슷한 것을 만들 수 있었습니다.</p>
<pre><code class="language-html">&lt;div class=&quot;slidecontainer&quot;&gt;
  &lt;input type=&quot;range&quot; min=&quot;1&quot; max=&quot;100&quot; value=&quot;50&quot; class=&quot;slider&quot; id=&quot;myRange&quot;&gt;
&lt;/div&gt;</code></pre>
<p>이 포스팅에서는 <code>SeekBar</code>의 움직임에 따라 텍스트뷰에 숫자가 반영되도록 만들어보겠습니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/73ced882-4e6a-43ea-b831-250a22858390/image.png" alt=""></p>
<p>대략 이런 형태가 될 것입니다.</p>
<h3 id="activity_mainxml에-넣어주기"><code>activity_main.xml</code>에 넣어주기</h3>
<p>우선 바의 움직임에 따라 텍스트뷰에 숫자를 쏴서 보여주기 위해 텍스트뷰도 함께 넣어주겠습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;0&quot;
            android:textSize=&quot;35sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.374&quot;
    /&gt;
    &lt;SeekBar
            android:id=&quot;@+id/seekBar&quot;
            android:layout_width=&quot;496dp&quot;
            android:layout_height=&quot;34dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="mainactivity-설정해주기"><code>MainActivity</code> 설정해주기</h3>
<p>레이아웃을 잡아주었다면 이제 bar를 움직일 때 텍스트뷰에 변화를 줘보겠습니다.</p>
<pre><code class="language-kotlin">import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import androidx.annotation.RequiresApi

class MainActivity : AppCompatActivity() {

    @RequiresApi(Build.VERSION_CODES.O)     // 버전차이 때문에 seekBar.min 사용 할 수 없어서 추가
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val seekBar = findViewById&lt;SeekBar&gt;(R.id.seekBar)
        val textView = findViewById&lt;View&gt;(R.id.textView) as TextView

        seekBar.min = 1
        seekBar.max = 1000
</code></pre>
<p>우선 <code>seekBar</code>와 <code>textView</code>를 <code>findViewById</code>로 불러와줍니다.</p>
<p>그리고 <code>seekBar</code>의 최대, 최소값을 지정합니다. 이 때 최소값을 나타내는 <code>min</code>은 현재 사용중인 버전에서 호환되지 않는다고 하여 상단에 어노테이션(<code>@RequiresApi(Build.VERSION_CODES.O)</code>)을 붙여줬습니다.</p>
<pre><code class="language-kotlin">        seekBar.setOnSeekBarChangeListener(object:SeekBar.OnSeekBarChangeListener{
            override fun onProgressChanged(p0: SeekBar?, progress: Int, p2: Boolean) {
                textView.text = &quot;$progress&quot;
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {

            }

            override fun onStopTrackingTouch(p0: SeekBar?) {

            }
        })

    }
}</code></pre>
<p>그리고 <code>seekBar</code>의 상태변화를 감지하는 이벤트 리스너인 <code>setOnSeekBarChangeListener</code>를 사용합니다. 이 때 <code>SeekBar.OnSeekBarChangeListener</code> 인터페이스를 상속받는 <code>object</code>는 세개의 퍼블릭 메서드를 오버라이드 받아야합니다.</p>
<p>각각의 메서드는 다음과 같이 정의됩니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/acb58b13-6141-4f0f-b368-3cec352259b2/image.png" alt=""></p>
<br>

<h2 id="ratingbar"><code>RatingBar</code></h2>
<hr>
<h3 id="개요-1">개요</h3>
<p><code>RatingBar</code> 별점을 매길 때 흔히 사용합니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/56b27120-90b5-4e77-954e-65beff579022/image.png" alt=""></p>
<p>별을 손으로 탭하면 <code>.5</code> 단위로 숫자가 올라갑니다. 이를 텍스트뷰에 반영시키는 것을 구현해보겠습니다.</p>
<h3 id="activity_mainxml에-ratingbar-넣어주기"><code>activity_main.xml</code>에 <code>RatingBar</code> 넣어주기</h3>
<p>앞에서 언급한 것처럼 <code>RatingBar</code>의 결과를 텍스트뷰에 표시해줄 것입니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;

    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;0.0&quot;
            android:textSize=&quot;30sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.388&quot;
    /&gt;

    &lt;RatingBar
            android:id=&quot;@+id/ratingBar&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="mainactivity에서-텍스트뷰에-별점-반영하게-하기"><code>MainActivity</code>에서 텍스트뷰에 별점 반영하게 하기</h3>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.RatingBar
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val ratingBar = findViewById&lt;RatingBar&gt;(R.id.ratingBar)
        val textView = findViewById&lt;View&gt;(R.id.textView) as TextView
</code></pre>
<p>마찬가지로 <code>RatingBar</code>와 <code>TextView</code>를 <code>findViewById</code>로 불러옵니다.</p>
<pre><code class="language-kotlin">        ratingBar.setOnRatingBarChangeListener { ratingBar, rating, fromUser -&gt;
            textView.text = &quot;$rating&quot;
        }
    }
}</code></pre>
<p><code>setOnRatingBarChangeListener</code>로 <code>RatingBar</code>의 변화를 감지합니다. </p>
<p>각각의 파라미터는 다음과 같이 정의됩니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/7efb0151-1d0d-4837-9152-97619077d136/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : Fragment]]></title>
            <link>https://velog.io/@htwenty-1/Android-Fragment</link>
            <guid>https://velog.io/@htwenty-1/Android-Fragment</guid>
            <pubDate>Mon, 07 Feb 2022 13:19:47 GMT</pubDate>
            <description><![CDATA[<h2 id="fragment란">Fragment란?</h2>
<hr>
<p>웹에서 SPA라는 개념을 들어보셨을겁니다. Single Page Application의 약자인데, 페이지가 이동할 때마다 새로운 페이지를 불러오지 않고 현재의 페이지를 동적으로 다시 작성하는 기술을 말합니다.</p>
<p>Fragment도 이와 유사합니다. 단어의 의미는 조각이라는 뜻이지요.</p>
<p>예를 들어 상단에 버튼 세개가 그 아래에 뷰가 있다고 가정할 때, 누르는 버튼에 따라 각각 다른 페이지를 보여주는 것입니다.</p>
<p>우리가 자주 사용하는 카카오톡, 인스타그램 등 다양한 애플리케이션이 프레그먼트를 지원합니다.</p>
<p>그럼 우선 상단에 버튼을 주고 버튼의 조작에 따라 다른 뷰를 보여주는 앱을 구성해보겠습니다.</p>
<br>

<h2 id="상단에-버튼을-주고-조작에-따라-다른-뷰-표시하기">상단에 버튼을 주고 조작에 따라 다른 뷰 표시하기</h2>
<hr>
<h3 id="button-메뉴-만들어주기"><code>Button</code> 메뉴 만들어주기</h3>
<p>우선 layout 디렉터리에 <code>activity_fragment_menu.xml</code>을 만들어주고 아래와 같이 버튼 세개를 작성해줍니다. 이 때 레이아웃은 <code>LinearLayout</code>임에 주의합시다.</p>
<pre><code class="language-xml">&lt;!-- activity_fragment_menu.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!-- LinearLayout의 orientation은 default가 horizontal임 --&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
              android:orientation=&quot;horizontal&quot;
              android:layout_width=&quot;match_parent&quot;
              android:layout_height=&quot;match_parent&quot;&gt;


    &lt;Button
            android:id=&quot;@+id/button1&quot;
            android:text=&quot;First&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_weight=&quot;1&quot;
            android:onClick=&quot;onClick&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/button2&quot;
            android:text=&quot;Second&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_weight=&quot;1&quot;
            android:onClick=&quot;onClick&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/button3&quot;
            android:text=&quot;Third&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:layout_weight=&quot;1&quot;
            android:onClick=&quot;onClick&quot;
    /&gt;
&lt;/LinearLayout&gt;</code></pre>
<h3 id="각-뷰에-보여-줄-페이지-작성하기">각 뷰에 보여 줄 페이지 작성하기</h3>
<p>버튼을 조작할 때마다 뷰에 보여줄 컴포넌트를 작성합니다.
버튼이 세개 있으므로 세개의 컴포넌트를 만들어주어야 합니다.</p>
<p>각각의 파일명은 <code>activity_fragment_one</code>처럼 뒤에 숫자가 영어로 붙는 방식으로 해주겠습니다.</p>
<h4 id="activity_fragment_onexml"><code>activity_fragment_one.xml</code></h4>
<pre><code class="language-xml">&lt;!-- activity_fragment_one.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#ee9900&quot;
&gt;

    &lt;TextView
            android:text=&quot;First Fragment&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h4 id="activity_fragment_twoxml"><code>activity_fragment_two.xml</code></h4>
<pre><code class="language-xml">&lt;!-- activity_fragment_two.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#0099ff&quot;
&gt;

    &lt;TextView
            android:text=&quot;Second Fragment&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h4 id="activity_fragment_threexml"><code>activity_fragment_three.xml</code></h4>
<pre><code class="language-xml">&lt;!-- activity_fragment_three.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#9900ff&quot;
&gt;

    &lt;TextView
            android:text=&quot;Third Fragment&quot;
            android:textColor=&quot;#ffffff&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="activity_mainxml에서-framelayout-지정하기"><code>activity_main.xml</code>에서 <code>FrameLayout</code> 지정하기</h3>
<p>버튼의 조작에 따라 다른 페이지를 보여줄 뷰를 설정해야 합니다. 이를 <code>FrameLayout</code>으로 지정할 것입니다.</p>
<p>그리고 상단에 위에서 만든 버튼 세개를 넣어주기 위해 <code>&lt;fragment&gt;</code>를 추가해주었습니다.</p>
<p><strong>이 때 <code>&lt;fragment&gt;</code>의 속성에서 <code>android:name</code>에는 클래스를 기반으로 각 메뉴가 앱 초기화 시점에서 생성될 수 있도록 해줄 코틀린 패키지가 들어갑니다.</strong></p>
<pre><code class="language-xml">&lt;!-- activity_main.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;

    &lt;fragment
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:id=&quot;@+id/fragmentMenu&quot;
            android:name=&quot;com.example.sample23.FragmentMenu&quot;
            tools:layout=&quot;@layout/activity_fragment_menu&quot;
            tools:ignore=&quot;MissingConstraints&quot;
    /&gt;

    &lt;FrameLayout
            android:id=&quot;@+id/content&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;805dp&quot;
            tools:ignore=&quot;MissingConstraints&quot;
            android:layout_marginTop=&quot;20dp&quot; app:layout_constraintTop_toBottomOf=&quot;@+id/fragmentMenu&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="kotlin-패키지-파일-작성">Kotlin 패키지 파일 작성</h3>
<p>버튼을 앱 초기화시 생성해주기 위해 필요합니다.</p>
<h4 id="fragmentmenu"><code>FragmentMenu</code></h4>
<pre><code class="language-kotlin">import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class FragmentMenu : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

        return inflater.inflate(R.layout.activity_fragment_menu, container, false)
    }
}</code></pre>
<p>이 함수는 <code>MainActivity</code>의 <code>onCreate</code>와 유사합니다.
<code>activity_fragment_menu.xml</code>에서 만든 버튼 세개를 뷰로 생성해주는 것입니다.</p>
<p>각각의 파라미터는 다음과 같습니다.</p>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>정의</th>
</tr>
</thead>
<tbody><tr>
<td><code>inflater</code></td>
<td>프레그먼트의 모든 뷰를 확장시킬 수 있는 <code>LayoutInflater</code> 객체</td>
</tr>
<tr>
<td><code>container</code></td>
<td>프레그먼트의 UI를 연결할 상위 view</td>
</tr>
<tr>
<td><code>savedInstanceState</code></td>
<td><code>null</code>이 아닌 경우 프레그먼트는 이전에 저장된 상태에서 재생성됨.</td>
</tr>
</tbody></table>
<h4 id="fragmentone--fragmentthree">FragmentOne ~ FragmentThree</h4>
<p>각각은 별도의 파일이며 <code>Fragment</code>를 상속받아 만들어줍니다.</p>
<pre><code class="language-kotlin">class FragmentOne : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.activity_fragment_fragment1, container, false)
    }
}

class FragmentTwo : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.activity_fragment_fragment2, container, false)
    }
}

class FragmentThree : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.activity_fragment_fragment3, container, false)
    }
}</code></pre>
<h4 id="mainactivity"><code>MainActivity</code></h4>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment

class MainActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)</code></pre>
<pre><code class="language-kotlin">        val fm = supportFragmentManager
        val fragmentTransaction = fm.beginTransaction()
        fragmentTransaction.add(R.id.content, FragmentOne())
        fragmentTransaction.commit()
    }</code></pre>
<p>여기에서 <code>supportFragmentManager</code>를 사용합니다.</p>
<blockquote>
<p><strong><code>FragmentManager</code>는 앱 프래그먼트에서 작업을 추가, 삭제 또는 교체하고 백 스택에 추가하는 등의 작업을 실행하는 클래스입니다.</strong></p>
</blockquote>
<p>여기에서 <code>supportFragmentManager</code>는 <code>FragmentManager</code>에 접근하기 위한 도구입니다. 프래그먼트의 모든 요소를 제어할 수 있습니다.</p>
<p><code>beginTransaction()</code>을 통해 트랜젝션하여 프래그먼트를 편집할 것임을 알려줍니다.</p>
<p>여기에 <code>add</code>를 사용하여 텍스트뷰로 작성한 내용을 <code>FragmentOne</code>이라는 객체에 넣어 앱을 처음 실행했을 때 보여줄 것입니다.</p>
<pre><code class="language-kotlin">    // fragment_menu에서 사용할 onClick 멤버구현
    override fun onClick(v: View?) {
        Log.d(&quot;button&quot;, &quot;clicked&quot;)

        var fr:Fragment? = null

        if(v?.id == R.id.button1) {
            fr = FragmentOne()
        } else if (v?.id == R.id.button2) {
            fr = FragmentTwo()
        } else if (v?.id == R.id.button3) {
            fr = FragmentThree()
        }

        val fm = supportFragmentManager
        val fragmentTransaction = fm.beginTransaction()

        // fragment 교체
        fragmentTransaction.replace(R.id.content, fr!!)
        fragmentTransaction.commit()
    }
}</code></pre>
<p>각 뷰에는 <code>onClick</code>이 적용되어 있습니다. 이 함수는 <code>View.OnClickListener</code>를 클래스에 상속시켜주어야 멤버함수로 오버라이드하여 구현할 수 있습니다.</p>
<p>프래그먼트를 변수 <code>fr</code>로 잡아주고 버튼의 아이디에 따라 보여줄 뷰(<code>fr</code>)를 지정해줍니다.</p>
<p><code>replace</code> 메서드로 <code>fr</code> 값에 따라 어떤 컨텐츠를 보여줄 지 선언해주고 커밋합니다.</p>
<br>

<h2 id="navbar로-fragment-사용하기"><code>navBar</code>로 <code>Fragment</code> 사용하기</h2>
<hr>
<p>이제부터 사용할 것은 <code>navBar</code>라는 개념입니다. 많은 애플리케이션에서 하단에 <code>navBar</code>를 위치시켜 사용자의 편의성을 도모하고 있습니다.</p>
<p>하단 <code>navBar</code>를 만들어서 <code>Fragment</code>를 적용해보겠습니다.</p>
<h3 id="의존성-추가">의존성 추가</h3>
<p>우선 <code>navBar</code>를 사용하기 위해 의존성을 추가해줘야 합니다.</p>
<p><code>app</code> 디렉터리에 있는 <code>gradle.build</code>를 열고 다음과 같이 추가해줍니다.</p>
<pre><code>plugins {
    // navBar 사용하기 위해 플러그인 추가
    id &#39;kotlin-android-extensions&#39;
}

...

dependencies {
    // navBar 사용하기 위해 의존성 추가
    implementation &#39;com.google.android.material:material:1.4.0&#39;
}</code></pre><h3 id="navbar-구성-만들어주기"><code>navBar</code> 구성 만들어주기</h3>
<p><code>navBar</code>에는 이전 예시와 마찬가지로 세개의 메뉴를 넣어줄 것입니다.</p>
<pre><code class="language-xml">&lt;!-- bottom_navi_menu.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    &lt;item
        android:id=&quot;@+id/person&quot;
        android:title=&quot;Person&quot;
        android:icon=&quot;@drawable/ic_person_foreground&quot;
    /&gt;
    &lt;item
        android:id=&quot;@+id/home&quot;
        android:title=&quot;Home&quot;
        android:icon=&quot;@drawable/ic_home_foreground&quot;
    /&gt;
    &lt;item
        android:id=&quot;@+id/setting&quot;
        android:title=&quot;Setting&quot;
        android:icon=&quot;@drawable/ic_setting_foreground&quot;
    /&gt;
&lt;/menu&gt;</code></pre>
<p>여기에서 <code>icon</code>은 다음과 같이 만들어줍니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/9100d825-5a4a-4173-859b-47398db04671/image.png" alt=""></p>
<p>res 디렉터리의 drawable 디렉터리에서 새로 만들기 -&gt; Image Asset을 클릭해줍니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/4093ba04-ddfb-4d8e-851d-374ec605d0b9/image.png" alt=""></p>
<p>아이콘 타입을 <code>Launcher Icons(Adaptive and Legacy)</code>로 하고 아래 <code>Asset Type</code>을 <code>Clip Art</code>로 잡아준 다음 <code>Clip Art</code>에서 사용하자 하는 아이콘을 선택합니다.</p>
<p>이 때 상단의 <code>Name</code>을 알맞게 바꿔줍니다.</p>
<p>그 다음 창에서 완료를 누르면 <code>drawable</code> 디렉터리에 새로운 <code>xml</code> 파일들이 생겨납니다.</p>
<p>우리는 <code>foreground</code>로 되어있는 것을 사용할 것이므로 <code>navBar</code> 아이템을 담당하는 xml 파일의 <code>icon</code>은 <code>foreground</code>로 지정해줍니다.</p>
<h3 id="activity_mainxml에-framelayout과-navbar-만들어주기"><code>activity_main.xml</code>에 <code>FrameLayout</code>과 <code>navBar</code> 만들어주기</h3>
<p>네비게이션 메뉴 조작에 따라 다른 화면을 보여줄 것이기 때문에 상단메뉴 예시와 마찬가지로 뷰와 네비게이션바를 만들어줍니다. layout 디렉터리에 들어갑니다.</p>
<pre><code class="language-xml">&lt;!-- activity_main.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;

    &lt;FrameLayout
            android:id=&quot;@+id/flFragment&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;0dp&quot;
            app:layout_constraintBottom_toTopOf=&quot;@+id/bottomNaviView&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.5&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
    /&gt;

    &lt;com.google.android.material.bottomnavigation.BottomNavigationView
        android:id=&quot;@+id/bottomNaviView&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;75dp&quot;
        app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
        app:layout_constraintEnd_toEndOf=&quot;parent&quot;
        app:layout_constraintHorizontal_bias=&quot;0.5&quot;
        app:layout_constraintStart_toStartOf=&quot;parent&quot;
        app:menu=&quot;@menu/bottom_navi_menu&quot;
    /&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p><code>BottomNavigationView</code>의 <code>app:menu</code> 속성을 앞에서 우리가 만들어준 <code>bottom_navi_menu</code>로 지정해줍니다.</p>
<h3 id="메뉴-선택-시-보여줄-view-만들기">메뉴 선택 시 보여줄 View 만들기</h3>
<p>Layout 디렉터리에 메뉴 선택시 보여 줄 View를 만들어주겠습니다.</p>
<pre><code class="language-xml">&lt;!-- activity_fragment_one.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#ee9900&quot;
&gt;

    &lt;TextView
            android:text=&quot;First Fragment&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<pre><code class="language-xml">&lt;!-- activity_fragment_two.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#0099ff&quot;
&gt;

    &lt;TextView
            android:text=&quot;Second Fragment&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<pre><code class="language-xml">&lt;!-- activity_fragment_three.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:background=&quot;#9900ff&quot;
&gt;

    &lt;TextView
            android:text=&quot;Third Fragment&quot;
            android:textColor=&quot;#ffffff&quot;
            android:textSize=&quot;30sp&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="각-메뉴를-클래스로-생성하기">각 메뉴를 클래스로 생성하기</h3>
<p>이전 예시에서는 <code>onCreateView</code> 메서드를 오버라이드하여 사용했지만 여기서는 조금 다른 방법으로 시도합니다.</p>
<p>바로 뷰에 보여줄 각 xml 파일을 <code>Fragment</code> 클래스의 생성자로 사용하는 방법입니다.</p>
<p>마찬가지로 각각의 파일입니다.</p>
<pre><code class="language-kotlin">import androidx.fragment.app.Fragment
class FragmentOne : Fragment(R.layout.activity_fragment_one) {}

import androidx.fragment.app.Fragment
class FragmentTwo : Fragment(R.layout.activity_fragment_two) {}

import androidx.fragment.app.Fragment
class FragmentThree : Fragment(R.layout.activity_fragment_three) {}</code></pre>
<h3 id="mainactivity에서-연결하기"><code>MainActivity</code>에서 연결하기</h3>
<p>이제 완성된 것들을 연결시켜주겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)</code></pre>
<pre><code class="language-kotlin">        val firstFragment = FragmentOne()
        val secondFragment = FragmentTwo()
        val thirdFragment = FragmentThree()</code></pre>
<p>메뉴를 누를 때마다 보여줄 바뀔 페이지 객체를 생성합니다.</p>
<pre><code class="language-kotlin">        // 가장 처음 보여주는 화면
        setCurrentFragment(firstFragment)

        bottomNaviView.setOnNavigationItemSelectedListener {
            when (it.itemId) {
                R.id.person -&gt; setCurrentFragment(firstFragment)
                R.id.home -&gt; setCurrentFragment(secondFragment)
                R.id.setting -&gt; setCurrentFragment(thirdFragment)
            }
            true
        }

    }
</code></pre>
<p><code>setCurrentFragment</code>은 가장 처음 보여줄 화면을 설정합니다. 아래에 별도로 작성되어 있습니다.</p>
<p><code>bottomNaviView</code>는 <code>activity_main.xml</code>에서 만들어준 네비게이션바가 들어가는 공간입니다. 이 자리에 <code>ItemSelectedListener</code>로 뷰에 대해 장면전환을 할 수 있도록 해줍니다. 이 때, <code>menuItem</code>으로 <code>it</code>가 들어갑니다.</p>
<p><code>true</code>는 <code>setOnNavigationItemSelectedListener</code>가 동작하게 해줍니다.</p>
<pre><code class="language-kotlin">    fun setCurrentFragment(fragment:Fragment) = supportFragmentManager.beginTransaction().apply {
        replace(R.id.flFragment, fragment)
        commit()
    }
}</code></pre>
<p><code>setCurrentFragment</code> 함수는 장면전환을 도와주는 함수입니다. <code>fragment</code>를 매개변수로 받아서 <code>flFragment</code> 즉 프레임 레이아웃을 매개변수로 받은 <code>fragment</code>로 변환해주고 커밋해주는 함수입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: VideoView와 WebView]]></title>
            <link>https://velog.io/@htwenty-1/Android-VideoView%EC%99%80-WebView</link>
            <guid>https://velog.io/@htwenty-1/Android-VideoView%EC%99%80-WebView</guid>
            <pubDate>Mon, 07 Feb 2022 11:39:33 GMT</pubDate>
            <description><![CDATA[<h2 id="vedioview">VedioView</h2>
<hr>
<h3 id="개요">개요</h3>
<p>비디오뷰는 비디오컨텐츠를 보여주기 위한 컴포넌트입니다.</p>
<blockquote>
</blockquote>
<p><strong>Displays a video file. The VideoView class can load images from various sources (such as resources or content providers), takes care of computing its measurement from the video so that it can be used in any layout manager, and provides various display options such as scaling and tinting.</strong>
- 안드로이드 개발자 문서</p>
<p>우리는 소유한 영상을 화면에 표기해주는 간단한 예제 정도만 보겠습니다.</p>
<h3 id="사용-예시">사용 예시</h3>
<h4 id="activity_mainxml"><code>activity_main.xml</code></h4>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;
&gt;
    &lt;VideoView
            android:id=&quot;@+id/videoView&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
    /&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h4 id="mainactivity">MainActivity</h4>
<p><code>res</code> 디렉터리에 <code>raw</code> 디렉터리를 만들고 영상을 넣어줍니다.</p>
<p>비디오뷰를 아이디로 불러옵니다.</p>
<pre><code class="language-kotlin">import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.MediaController
import android.widget.VideoView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val videoView = findViewById&lt;View&gt;(R.id.videoView) as VideoView</code></pre>
<p><code>setMediaController</code> 메서드는 미디어 컨트롤러(뒤로, 재생, 일시정지 등)을 설정해주기 위한 메서드입니다.</p>
<p>내부에 <code>MediaController</code>를 이 객체에서 사용할 것이기 때문에 <code>this</code>로 잡아줍니다.</p>
<p>그리고 비디오 파일의 <code>URI</code>를 설정해줍니다. 이 때 <code>parse</code>를 사용해 경로를 가져옵니다.</p>
<pre><code class="language-kotlin">        // 미디어 컨트롤러
        videoView.setMediaController(MediaController(this))
        videoView.setVideoURI(Uri.parse(&quot;android.resource://&quot; + packageName + &quot;/&quot; + R.raw.snow))
    }
}</code></pre>
<br>

<h2 id="webview">WebView</h2>
<hr>
<h3 id="개요-1">개요</h3>
<p>웹에서 <code>&lt;iframe&gt;</code>이라는 태그가 있습니다. 웹 문서 전체를 통째로 페이지에 보여줄 수 있는 태그입니다.</p>
<p>안드로이드에서는 이와 비슷한 역할을 하는 <code>WebView</code>라는 태그가 있습니다.</p>
<p>어떻게 사용하는지 살펴보겠습니다.</p>
<h3 id="사용-예시-1">사용 예시</h3>
<h4 id="activity_mainxml에-webview-만들어주기"><code>activity_main.xml</code>에 <code>WebView</code> 만들어주기</h4>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;
&gt;
    &lt;WebView
            android:id=&quot;@+id/webView&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot;
            tools:layout_editor_absoluteY=&quot;1dp&quot;
            tools:layout_editor_absoluteX=&quot;1dp&quot;
    /&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h4 id="mainactivity에서-특정-웹페이지-url로-불러오기"><code>MainActivity</code>에서 특정 웹페이지 url로 불러오기</h4>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView = findViewById&lt;View&gt;(R.id.webView) as WebView

        // url
        webView.loadUrl(&quot;https://m.naver.com&quot;)
    }
}</code></pre>
<h4 id="mainactivity에서-html로-페이지-삽입하기"><code>MainActivity</code>에서 html로 페이지 삽입하기</h4>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView = findViewById&lt;View&gt;(R.id.webView) as WebView

        // html
        val html = &quot;&lt;html&gt;&lt;head&gt;&lt;meta charset=\&quot;UTF-8\&quot;&gt;&lt;/head&gt;&lt;body&gt;Hello World! 안녕하세요!&lt;/body&gt;&lt;/html&gt;&quot;
        webView.loadData(html, &quot;text/html&quot;, &quot;UTF-8&quot;)
    }
}</code></pre>
<h4 id="mainactivity에서-html-문서-넣기"><code>MainActivity</code>에서 html 문서 넣기</h4>
<h5 id="src의-main-디렉터리-내부에-assets-디렉터리-만들기"><code>src</code>의 <code>main</code> 디렉터리 내부에 <code>assets</code> 디렉터리 만들기</h5>
<p><img src="https://images.velog.io/images/htwenty-1/post/46e2ccf7-71d6-4d97-b144-ba509ac055b4/image.png" alt=""></p>
<p>이와 같은 형태로 디렉터리를 만들어줍니다. 폴더에 반드시 노란줄 네개가 그어져 있어야합니다.</p>
<p>인텔리제이에서 지원해주기 때문에 잘 잡힐겁니다.</p>
<h5 id="html-문서-호출하기"><code>html</code> 문서 호출하기</h5>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val webView = findViewById&lt;View&gt;(R.id.webView) as WebView

        // html 문서 호출
        webView.loadUrl(&quot;file:///android_assets/hello.html&quot;)
        webView.settings.javaScriptEnabled = true
        webView.webChromeClient = WebChromeClient()
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: ScrollView와 GridView]]></title>
            <link>https://velog.io/@htwenty-1/Android-ScrollView%EC%99%80-GridView</link>
            <guid>https://velog.io/@htwenty-1/Android-ScrollView%EC%99%80-GridView</guid>
            <pubDate>Mon, 07 Feb 2022 11:00:08 GMT</pubDate>
            <description><![CDATA[<h2 id="scrollview">ScrollView</h2>
<hr>
<h3 id="개요">개요</h3>
<p>어떤 컨텐츠를 화면에 표시할 때 화면보다 컨텐츠가 큰 경우 컨텐츠가 잘려버린다면 서비스를 사용하는데 있어 불편함을 초래할 것입니다.</p>
<p>웹에서는 브라우저에서 스크롤이라는 기능을 자동으로 지원하여 뷰포트보다 크기가 큰 컨텐츠를 보여줄 때 스크롤을 조작하여 모든 컨텐츠를 다 열어볼 수 있습니다.</p>
<p>Android에서는 <code>ScrollView</code>를 통해 스크롤을 사용할 수 있습니다.</p>
<p>단, <code>ScrollView</code>는 하나의 자식태그만 가질 수 있기 때문에 다양한 컴포넌트들을 처리하고자 할 때는 하나로 감싼 다음 적용해주어야 합니다.</p>
<h3 id="scrollview-사용-예시"><code>ScrollView</code> 사용 예시</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;!-- &lt;androidx.constraintlayout.widget.ConstraintLayout&gt; --&gt;
&lt;ScrollView
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;
&gt;
    &lt;TableLayout
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot;
    &gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot; 
                      android:textSize=&quot;50dp&quot; 
                      android:paddingBottom=&quot;100dp&quot; 
            /&gt;
            &lt;TextView android:text=&quot;영어&quot; 
                      android:textSize=&quot;50dp&quot; 
                      android:paddingBottom=&quot;100dp&quot; 
            /&gt;
            &lt;TextView android:text=&quot;수학&quot; 
                      android:textSize=&quot;50dp&quot; 
                      android:paddingBottom=&quot;100dp&quot; 
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
        &lt;TableRow&gt;
            &lt;TextView android:text=&quot;국어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;영어&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
            &lt;TextView android:text=&quot;수학&quot;
                      android:textSize=&quot;50dp&quot;
                      android:paddingBottom=&quot;100dp&quot;
            /&gt;
        &lt;/TableRow&gt;
    &lt;/TableLayout&gt;

&lt;/ScrollView&gt;
&lt;!-- &lt;/ androidx.constraintlayout.widget.ConstraintLayout&gt; --&gt;</code></pre>
<p>위 예시는 스크롤을 보이게 하기 위해 일부러 같은 것을 반복하여 작성한 것입니다.</p>
<p>이렇게 해주면 화면에 스크롤이 나타나게 되고 위아래로 쓸어넘기면서 모든 컨텐츠를 다 볼 수 있습니다.</p>
<p>주의할 점은 <code>ScrollView</code>가 아닌 주석 처리된 <code>ConstraintLayout</code>을 사용하게 되면 화면단에서 스크롤뷰를 지원하지 않으며 본래 스크롤을 넘겼을 때 표시되는 컨텐츠들은 나오지 않고 잘리게 됩니다.</p>
<br>

<h2 id="gridview">GridView</h2>
<hr>
<h3 id="개요-1">개요</h3>
<p>그리드는 row와 column의 집합체입니다. 비교대상으로 table 또한 row와 column의 집합체인데, 둘의 차이점은 컴포넌트가 사용자가 지정한대로 들어가는지 그렇지 않은지 입니다.</p>
<p>그리드는 순서대로 들어갑니다. 테이블은 사용자가 지정한 대로 해당 자리에 값이 들어갑니다.</p>
<h3 id="gridview-사용-예시"><code>GridView</code> 사용 예시</h3>
<p>스피너를 그리드 형태로 배치시켜보겠습니다.</p>
<h4 id="gridview-준비"><code>GridView</code> 준비</h4>
<p>우선 그리드뷰가 준비되어야 합니다. 그리드뷰에서 선택한 내용의 반영여부를 확인하기 위해 텍스트뷰도 준비해줍니다. <code>MainActivity</code>에서 스피너로부터 선택한 결과를 텍스트뷰에 보여줄 것입니다.</p>
<pre><code class="language-xml">&lt;!-- activity_main.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.069&quot;/&gt;
    &lt;GridView
            android:id=&quot;@+id/grid&quot;
            android:numColumns=&quot;auto_fit&quot;
            android:columnWidth=&quot;100dp&quot;
            android:layout_width=&quot;509dp&quot;
            android:layout_height=&quot;732dp&quot;
            tools:ignore=&quot;MissingConstraints&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/textView&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h4 id="스피너-아이템-준비">스피너 아이템 준비</h4>
<p>스피너를 사용할 것이기 때문에 스피너 내부에 들어갈 아이템 요소를 준비해줍니다.</p>
<pre><code class="language-xml">&lt;!-- item_spinner.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;TextView
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        android:id=&quot;@+id/tvItemSpinner&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;45dp&quot;
        android:paddingTop=&quot;10dp&quot;
        android:paddingStart=&quot;30dp&quot;
        android:textColor=&quot;@android:color/black&quot;
        android:textSize=&quot;15sp&quot;
        android:paddingLeft=&quot;30dp&quot;
/&gt;</code></pre>
<h4 id="mainactivity-손보기"><code>MainActivity</code> 손보기</h4>
<p>우선 임의의 배열을 만들어줍시다. 이 배열이 스피너의 아이템이 될 것입니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.GridView
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    var items = arrayOf(
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;, &quot;인천&quot;, &quot;목포&quot;, &quot;여수&quot;, &quot;태백&quot;,
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;, &quot;인천&quot;, &quot;목포&quot;, &quot;여수&quot;, &quot;태백&quot;,
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;, &quot;인천&quot;, &quot;목포&quot;, &quot;여수&quot;, &quot;태백&quot;,
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;, &quot;인천&quot;, &quot;목포&quot;, &quot;여수&quot;, &quot;태백&quot;
    )</code></pre>
<p>그 다음으로 override된 <code>onCreate</code> 함수 내부에 텍스트뷰와 그리드뷰를 아이디값으로 불러와 캐스트 변환 해주었습니다.</p>
<pre><code class="language-kotlin">    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView = findViewById&lt;View&gt;(R.id.textView) as TextView
        val grid = findViewById&lt;View&gt;(R.id.grid) as GridView</code></pre>
<p>위에서 선언한 <code>items</code> 배열을 스피너 아이템에 <code>Adapter</code>로 꽂아주고 이를 그리드에 뿌려줍니다.</p>
<pre><code class="language-kotlin">        grid.adapter = ArrayAdapter(this, R.layout.item_spinner, items)
        /* 또는
        grid.setAdapter(
            ArrayAdapter(this, R.layout.item_spinner, items)
        )
        */</code></pre>
<p>그리드를 클릭했을 때 텍스트뷰를 배열의 인덱스에 맞게 업데이트 시켜줍니다.</p>
<pre><code class="language-kotlin">        grid.setOnItemClickListener { parent, view, position, id -&gt;
            textView.text = items[position]
        }

    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : ListView]]></title>
            <link>https://velog.io/@htwenty-1/Android-ListView</link>
            <guid>https://velog.io/@htwenty-1/Android-ListView</guid>
            <pubDate>Sat, 05 Feb 2022 23:08:16 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<hr>
<p>이번 포스팅에서 살펴볼 내용은 리스트뷰입니다.</p>
<p>리스트뷰가 무엇인지 우선 안드로이드 개발자 문서에서 확인해보겠습니다.</p>
<blockquote>
</blockquote>
<p>Displays a vertically-scrollable collection of views, where each view is positioned immediatelybelow the previous view in the list. For a more modern, flexible, and performant approach to displaying lists, use RecyclerView.
To display a list, you can include a list view in your layout XML file:</p>
<pre><code class="language-xml">&lt;ListView
      android:id=&quot;@+id/list_view&quot;
      android:layout_width=&quot;match_parent&quot;
      android:layout_height=&quot;match_parent&quot; /&gt;</code></pre>
<p>쉽게 말해서 사용자가 정의한 데이터 목록을 아이템 단위로 구성하여 화면에 출력해주는 것입니다.</p>
<br>

<h2 id="listitem과-내부-아이템-작성하기"><code>ListItem</code>과 내부 아이템 작성하기</h2>
<hr>
<p><code>ListItem</code>을 사용하기 위해서 우선 <code>activity_main.xml</code>에 <code>&lt;ListView&gt;</code>를 작성해줍니다.</p>
<p><code>TextView</code>는 리스트뷰에서 선택한 아이템을 출력해주기위해 준비해두었습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            android:textSize=&quot;20sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.022&quot;/&gt;
    &lt;ListView
            android:id=&quot;@+id/listView&quot;
            android:layout_width=&quot;602dp&quot;
            android:layout_height=&quot;828dp&quot;
            tools:ignore=&quot;MissingConstraints&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot; 
            app:layout_constraintHorizontal_bias=&quot;0.505&quot;
            app:layout_constraintVertical_bias=&quot;0.875&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>이제 리스트뷰의 각 아이템에 적용해 줄 컴포넌트를 만들어주겠습니다.</p>
<pre><code class="language-xml">&lt;!-- item_spinner.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;TextView
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:id=&quot;@+id/listItem&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;45dp&quot;
    android:paddingTop=&quot;10dp&quot;
    android:paddingStart=&quot;30dp&quot;
    android:textColor=&quot;@android:color/darker_gray&quot;
    android:textSize=&quot;15sp&quot;
    android:paddingLeft=&quot;30dp&quot;/&gt;</code></pre>
<br>

<h2 id="mainactivity-작성하기"><code>MainActivity</code> 작성하기</h2>
<hr>
<p>이제 <code>ListItem</code>에 들어갈 각 아이템을 정의해주고 아이템을 클릭할 때마다 텍스트뷰의 내용이 바뀌도록 해주겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.ListView
import android.widget.TextView
import androidx.annotation.Dimension

class MainActivity : AppCompatActivity(), AdapterView.OnItemClickListener {

    var items = arrayOf(
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;, &quot;대전&quot;, &quot;울산&quot;, &quot;전주&quot;, &quot;목포&quot;,
        &quot;제주&quot;, &quot;강원&quot;, &quot;태백&quot;, &quot;인천&quot;, &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;,
        &quot;대전&quot;, &quot;울산&quot;, &quot;전주&quot;, &quot;목포&quot;, &quot;제주&quot;, &quot;강원&quot;, &quot;태백&quot;, &quot;인천&quot;,
        &quot;서울&quot;, &quot;부산&quot;, &quot;대구&quot;, &quot;광주&quot;,
        &quot;대전&quot;, &quot;울산&quot;, &quot;전주&quot;, &quot;목포&quot;, &quot;제주&quot;, &quot;강원&quot;, &quot;태백&quot;, &quot;인천&quot;
    )
</code></pre>
<p><code>arrayOf</code>를 사용하여 배열을 만들어줍니다. 배열 안에 랜덤으로 지명을 넣어주었습니다.</p>
<pre><code class="language-kotlin">
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listView = findViewById&lt;View&gt;(R.id.listView) as ListView
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        textView.setTextSize(Dimension.SP, 28.0f)

        // Adapter
        val adapter:ArrayAdapter&lt;*&gt; = ArrayAdapter&lt;Any?&gt;(this, R.layout.item_spinner, items)

        listView.adapter = adapter

        listView.onItemClickListener = this
    }
</code></pre>
<p><code>onCreate</code> 함수에 리스트뷰와 텍스트뷰를 아이디로 하여 접근해주었습니다. 둘 다 <code>main_activity</code>에 있는 컴포넌트들입니다.</p>
<pre><code class="language-kotlin">val listView = findViewById&lt;View&gt;(R.id.listView) as ListView</code></pre>
<p>자료유형이 확실하지 않을 때 이처럼 제네릭을 <code>&lt;View&gt;</code>로만 써줘도 무방합니다. 다만 <code>as</code>를 사용하여 캐스트 변환을 해줄 수도 있습니다.</p>
<pre><code class="language-kotlin">textView.setTextSize(Dimension.SP, 28.0f)</code></pre>
<p>텍스트뷰에 표시되는 글자의 크기를 변경해줍니다.
<code>Dimension.SP</code>가 무엇인지 안드로이드 개발자 문서를 참조해보면</p>
<blockquote>
<p>Denotes that an integer parameter, field or method return value is expected to represent a dimension.</p>
</blockquote>
<p>각각은 <code>DP</code>, <code>PX</code>, <code>SP</code>라는 상수이며 크기를 나타내는 단위입니다.</p>
<p>안드로이드에서는 <code>PX</code>과 같은 절대적인 단위의 사용을 지양하는게 좋습니다.</p>
<p>각각에 대한 참고사항은 <a href="https://stackoverflow.com/questions/2025282/what-is-the-difference-between-px-dip-dp-and-sp">여기</a>를 참조해주세요.</p>
<p>우리가 사용할 SP는 시스템 폰트를 반영하라는 것입니다.</p>
<pre><code class="language-kotlin">
    override fun onItemClick(p0: AdapterView&lt;*&gt;?, p1: View?, pos: Int, p3: Long) {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        textView.text = items[pos]
    }

}</code></pre>
<p>그 다음으로 <code>onItemClick</code> 함수를 오버라이드 해주었습니다. 각각의 파라미터가 나타내는 것은 다음과 같습니다.</p>
<table>
<thead>
<tr>
<th><code>parameter</code></th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>p0: AdapterView&lt;*&gt;?</code></td>
<td>클릭이 발생한 <code>AdapterView</code></td>
</tr>
<tr>
<td><code>p1: View?</code></td>
<td><code>AdapterView 내에서 클릭한 보기(어댑터에서 제공하는 보기)</code></td>
</tr>
<tr>
<td><code>pos: Int</code></td>
<td><code>Adapter</code>에서 <code>View</code>의 위치</td>
</tr>
<tr>
<td><code>p3: Long</code></td>
<td>클릭된 아이템의 <code>row id</code></td>
</tr>
</tbody></table>
<p>텍스트뷰에는 <code>items</code> 배열의 <code>pos</code>에 해당하는 값을 넣어줍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: 배경에 이미지 넣기]]></title>
            <link>https://velog.io/@htwenty-1/Android-%EB%B0%B0%EA%B2%BD%EC%97%90-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%84%A3%EA%B8%B0</link>
            <guid>https://velog.io/@htwenty-1/Android-%EB%B0%B0%EA%B2%BD%EC%97%90-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%84%A3%EA%B8%B0</guid>
            <pubDate>Sat, 05 Feb 2022 21:39:59 GMT</pubDate>
            <description><![CDATA[<p>이미지를 넣을 때 <code>ImageView</code>라는 태그를 사용합니다.</p>
<p>쉽게 생각해보면 배경 이미지를 넣을 때 <code>ImageView</code>를 사용해서 이미지를 넣어주고 뷰포트 너비와 높이만큼 늘려주면 될 것이라고 생각할 수 있습니다.</p>
<p>물론 틀렸다고 말할 수는 없지만 옳은 방법은 아닙니다.</p>
<pre><code class="language-xml">&lt;!-- 잘못된 예시 --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;&gt;
    &lt;Button
            android:text=&quot;Button&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot; 
            android:id=&quot;@+id/button&quot;
            tools:ignore=&quot;MissingConstraints&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot; 
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

    &lt;!-- 배경 이미지를 넣기 위해 이미지를 불러옴 --&gt;
    &lt;ImageView
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot; 
        app:srcCompat=&quot;@drawable/rose&quot; 
        android:id=&quot;@+id/imageView&quot;
        tools:layout_editor_absoluteY=&quot;0dp&quot; 
        tools:layout_editor_absoluteX=&quot;0dp&quot; 
        tools:ignore=&quot;MissingConstraints&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>배경 이미지를 넣기 위해 이미지를 불러오는 방법은 잘못된 방법이므로, 다른 방법을 생각해보아야 합니다.</p>
<p>바로 레이아웃에 배경 속성을 지정해주는 방법입니다.</p>
<pre><code class="language-xml">&lt;!-- 잘못된 예시 --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    tools:context=&quot;.MainActivity&quot;
    android:background=&quot;@drawable/rose&quot;&gt;
    &lt;Button
            android:text=&quot;Button&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot; 
            android:id=&quot;@+id/button&quot;
            tools:ignore=&quot;MissingConstraints&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot; 
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>레이아웃 마지막 속성에 <code>android:background=&quot;@drawable/rose&quot;</code>을 추가해 주었습니다.</p>
<p>이렇게 배경에 이미지를 추가하고자 할 때는 이미지뷰를 사용하지 않고 레이아웃에 속성을 부여하여 사용합니다.</p>
<p>이 이미지는 drawable 디렉터리에 있는 rose라는 이미지입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: 컨텍스트 메뉴와 스피너]]></title>
            <link>https://velog.io/@htwenty-1/Android-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%A9%94%EB%89%B4%EC%99%80-%EC%8A%A4%ED%94%BC%EB%84%88</link>
            <guid>https://velog.io/@htwenty-1/Android-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%A9%94%EB%89%B4%EC%99%80-%EC%8A%A4%ED%94%BC%EB%84%88</guid>
            <pubDate>Sat, 05 Feb 2022 21:06:17 GMT</pubDate>
            <description><![CDATA[<h2 id="컨텍스트-메뉴란">컨텍스트 메뉴란?</h2>
<hr>
<h3 id="주요-개념">주요 개념</h3>
<blockquote>
</blockquote>
<p>컨텍스트 메뉴(context menu) 또는 상황에 맞는 메뉴는 그래픽 사용자 인터페이스 안에서 어떠한 항목을 클릭할 때 뜨는 팝업 메뉴로, 메뉴를 호출한 동작, 응용 프로그램의 실행, 선택된 항목의 상황에 따라 다양한 선택 사항을 나열하여 보여준다. 바로 가기 메뉴라고도 한다.
위키백과</p>
<p>가령 바탕화면에서 오른쪽 마우스를 눌렀을 때 바탕화면과 디스플레이에 관한 메뉴를 보여줍니다.
이를 컨텍스트 메뉴라고 합니다. </p>
<h3 id="컨텍스트-메뉴-구성-작성하기">컨텍스트 메뉴 구성 작성하기</h3>
<p>우선 컨텍스트 메뉴를 만들어주기 위해 <code>res</code>디렉터리에 <code>menu</code>라는 디렉터리를 만들어주고, 내부에 <code>context_menu_main.xml</code> 파일을 만들어줍시다.</p>
<p>그 파일에 아래와 같이 메뉴 아이템들을 만들어줍니다.</p>
<pre><code class="language-xml">&lt;!-- Context Menu --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
    &lt;item
        android:id=&quot;@+id/text_color&quot;
        android:title=&quot;글자색 변경&quot;
    /&gt;
    &lt;item
        android:id=&quot;@+id/text_back_color&quot;
        android:title=&quot;배경색 변경&quot;
    /&gt;
    &lt;item
       android:id=&quot;@+id/text_basic&quot;
       android:title=&quot;초기화&quot;
    /&gt;
&lt;/menu&gt;</code></pre>
<p>컨텍스트 메뉴를 클릭할 때마다 메인 화면에서 보이는 텍스트뷰에 효과를 줄 것입니다. 그래서 텍스트뷰의 속성을 아래와 같이 작성해줍니다.</p>
<pre><code class="language-xml">&lt;!-- activity_main.xml --&gt;
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Context Menu 보기&quot;
            android:textSize=&quot;30sp&quot;
            android:textColor=&quot;@color/black&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="컨텍스트-메뉴-적용하기">컨텍스트 메뉴 적용하기</h3>
<p>xml 파일로 컨텍스트 메뉴를 구성하였다면, 이제 화면단에서 사용할 수 있도록 해주어야 합니다.</p>
<p><code>MainActivity</code>를 열어서 컨텍스트 메뉴를 적용해주겠습니다. 그 전에 각 컴포넌트에 좀 더 쉽게 접근할 수 있도록 <code>build.gradle</code>에 다음과 같이 추가해주겠습니다.</p>
<pre><code class="language-gradle">android {
    buildFeatures {
        viewBinding true
    }
}</code></pre>
<p>자 이제 메인 액티비티에 <code>ActivityMainBinding</code>을 선언해 주겠습니다.</p>
<pre><code class="language-kotlin">import com.example.sample13.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
    }
}
</code></pre>
<p>그 다음으로 컨텍스트 메뉴를 생성하는 함수를 오버라이드 해줍니다.</p>
<p>그리고 내부에 <code>menuInflater.inflate(R.menu.context_menu_main, menu)</code>를 넣어줍니다.</p>
<p>여기에서 <code>menuInflater</code>에 대해 자세히 알아보겠습니다.</p>
<blockquote>
</blockquote>
<p>This class is used to instantiate menu XML files into Menu objects.
For performance reasons, menu inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use MenuInflater with an XmlPullParser over a plain XML file at runtime; it only works with an XmlPullParser returned from a compiled resource (R. something file.)
 안드로이드 개발자 문서</p>
<p> 클래스로 규정되어 있으며 이 클래스는 메뉴 XML 파일을 메뉴 객체로 인스턴스화 하는데 사용됩니다.
 성능상의 이유로 메뉴 인플레이션은 빌드 시 수행되는 XML 파일 사전 처리에 크게 의존합니다....</p>
<pre><code class="language-kotlin">import com.example.sample13.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

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

    // 생성한 컨텍스트 메뉴 적용
    override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
        menuInflater.inflate(R.menu.context_menu_main, menu)
    }

}
</code></pre>
<p> 다시 말해서 우리가 작성한 <code>context_menu_main.xml</code> 파일을 메뉴 객체로 만들어 주기 위해 사용되는 것입니다.</p>
<p> 여기에 딸려 있는 인터페이스인 <code>inflate</code>를 구현해주며, 다음과 같은 추상 메서드가 상속됩니다.</p>
<pre><code class="language-java">void inflate(int menuRes, Menu menu)    // 메뉴xml 경로와 menu 객체</code></pre>
<p>그 다음으로 <code>onContextItemSelected</code>를 오버라이드하여 메뉴를 선택했을 때 바꿔 줄 내용을 선언해주겠습니다.</p>
<pre><code class="language-kotlin">import com.example.sample13.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

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

    // 생성한 컨텍스트 메뉴 적용
    override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
        menuInflater.inflate(R.menu.context_menu_main, menu)
    }

    override fun onContextItemSelected(item: MenuItem): Boolean {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        when(item.itemId) {
            R.id.text_color -&gt; {
                textView.text = &quot;글자색 변경&quot;
                textView.setTextColor(Color.parseColor(&quot;#ff0000&quot;))
            }
            R.id.text_back_color -&gt; {
                textView.text = &quot;배경색 변경&quot;
                textView.setBackgroundColor(Color.parseColor(&quot;#0000ff&quot;))
                textView.setTextColor(Color.parseColor(&quot;#ffffff&quot;))
            }
            R.id.text_basic -&gt; {
                textView.text = &quot;초기화&quot;
                textView.setTextColor(Color.parseColor(&quot;#000000&quot;))
                textView.setBackgroundColor(Color.parseColor(&quot;#ffffff&quot;))
            }
        }

        return super.onContextItemSelected(item)
    }

}
</code></pre>
<p>글자색과 배경색을 바꿔주기 위해 <code>setter</code>를 사용했습니다.</p>
<p>메뉴가 생성되었으므로 이제 초기화될 때 텍스트뷰에 이를 적용시키기 위해서 <code>onCreate</code> 함수에 <code>registerForContextMenu</code> 메서드를 통해 텍스트뷰를 매개변수로 받아 처리하게 해줍니다.</p>
<pre><code class="language-kotlin">import com.example.sample13.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        registerForContextMenu(binding.textView)
    }

    // 생성한 컨텍스트 메뉴 적용
    override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
        menuInflater.inflate(R.menu.context_menu_main, menu)
    }

    override fun onContextItemSelected(item: MenuItem): Boolean {
        val textView = findViewById&lt;TextView&gt;(R.id.textView)
        when(item.itemId) {
            R.id.text_color -&gt; {
                textView.text = &quot;글자색 변경&quot;
                textView.setTextColor(Color.parseColor(&quot;#ff0000&quot;))
            }
            R.id.text_back_color -&gt; {
                textView.text = &quot;배경색 변경&quot;
                textView.setBackgroundColor(Color.parseColor(&quot;#0000ff&quot;))
                textView.setTextColor(Color.parseColor(&quot;#ffffff&quot;))
            }
            R.id.text_basic -&gt; {
                textView.text = &quot;초기화&quot;
                textView.setTextColor(Color.parseColor(&quot;#000000&quot;))
                textView.setBackgroundColor(Color.parseColor(&quot;#ffffff&quot;))
            }
        }

        return super.onContextItemSelected(item)
    }

}
</code></pre>
<br>

<h2 id="스피너">스피너</h2>
<hr>
<h3 id="html의-select">HTML의 <code>&lt;select&gt;</code></h3>
<p>html에서 <code>&lt;select&gt;</code>라는 태그에 <code>&lt;option&gt;</code>을 넣어 드랍다운 목록을 만들어주었습니다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&gt;
    &lt;title&gt;Fruits&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form method=&quot;get&quot;&gt;
      &lt;select&gt;
        &lt;option value=&quot;apple&quot;&gt;사과&lt;/option&gt;
        &lt;option value=&quot;pear&quot;&gt;배&lt;/option&gt;
        &lt;option value=&quot;grape&quot;&gt;포도&lt;/option&gt;
      &lt;/select&gt;
    &lt;/form&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>이 태그는 오직 문자열만 사용할 수 있다는 단점이 있기 때문에 활용성이 그렇게 높지는 않습니다.</p>
<p>그렇지만 안드로이드에서는 <code>&lt;option&gt;</code>에 해당하는 것을 각각의 객체로 만들어서 넣어줄 수 있기 때문에 텍스트 뿐만 아니라 이미지도 함께 넣어줄 수 있습니다.</p>
<h3 id="android의-spinner">Android의 Spinner</h3>
<p>우선 스피너를 만들어주기 위해 <code>activity_main.xml</code>에 스피너를 추가해 주겠습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;335dp&quot;
            android:layout_height=&quot;33dp&quot;
            android:text=&quot;Hello World!&quot;
            android:layout_centerHorizontal=&quot;true&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            app:layout_constraintVertical_bias=&quot;0.537&quot;/&gt;
    &lt;Spinner
            android:id=&quot;@+id/spinner&quot;
            android:layout_width=&quot;386dp&quot;
            android:layout_height=&quot;55dp&quot;
            app:layout_constraintBottom_toTopOf=&quot;@+id/textView&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            app:layout_constraintVertical_bias=&quot;0.742&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>그리고 스피너 내부에 들어갈 아이템을 텍스트뷰로 만들어주겠습니다.</p>
<p><code>layout</code> 디렉터리에 <code>item_spinner.xml</code>을 추가해줍니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;TextView
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        android:id=&quot;@+id/tvItemSpinner&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;45dp&quot;
        android:paddingTop=&quot;10dp&quot;
        android:paddingStart=&quot;30dp&quot;
        android:textColor=&quot;@android:color/black&quot;
        android:textSize=&quot;15sp&quot;
        android:paddingLeft=&quot;30dp&quot;
/&gt;</code></pre>
<p>이 아이템 하나가 각각의 스피너 아이템 객체가 될 것입니다.</p>
<p>이제 <code>MainActivity</code>로 돌아와 스피너를 초기화 해주겠습니다. 과일 이름이 들어있는 배열을 사용할 것입니다.</p>
<p>스피너를 초기화 해주기 위해 <code>setUpSpinnerFruits</code>라는 함수를 만들어줍시다.</p>
<pre><code class="language-kotlin">class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setUpSpinnerFruits()
    }

    // 스피너 아이템에 추가할 항목
    val fruits = arrayOf(&quot;과일 선택&quot;, &quot;사과&quot;, &quot;배&quot;, &quot;바나나&quot;, &quot;포도&quot;)

    // 스피너 초기화(값 설정) - initialize
    fun setUpSpinnerFruits() {
        val adapter = ArrayAdapter(this, R.layout.item_spinner, fruits)     // fruits 배열의 각 인덱스마다 Adapter 적용

        // spinner에 적용
        val spinner = findViewById&lt;Spinner&gt;(R.id.spinner)
        spinner.adapter = adapter
    }

}</code></pre>
<p>우선 스피너의 아이템이 될 배열을 하나 만들어주었습니다.</p>
<p>그리고 <code>ArrayAdapter</code>를 사용하여 각 배열의 인덱스마다 <code>Adapter</code>를 적용하여 스피너 아이템으로 만들어줍니다.</p>
<p>이 과정을 통해 위에서 작성한 <code>item_spinner.xml</code>의 서식이 각각 지정됩니다.</p>
<p><code>Spinner</code>에 위에서 적용시킨 <code>Adapter</code> 넣어주는 과정을 거칩니다. 그리고 <code>onCreate</code> 함수에서 애플리케이션 실행과 동시에 초기화시켜줍니다.</p>
<p>그러면 이제 스피너 아이템 선택을 감지하고 기본적으로 배치되어있는 텍스트뷰에 선택한 스피너의 값이 찍히도록 해보겠습니다.</p>
<p><code>setUpSpinnerFruits</code> 함수에 이어서 작성합니다.</p>
<pre><code class="language-kotlin">// 스피너 아이템 선택 감지 및 출력
fun setUpSpinnerHandler() {
    val spinner = findViewById&lt;Spinner&gt;(R.id.spinner)
    val textView = findViewById&lt;TextView&gt;(R.id.textView)

    spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {

        override fun onItemSelected(p0: AdapterView&lt;*&gt;?, view: View?, position: Int, id: Long) {
            textView.text = &quot;selected: $position ${spinner.getItemAtPosition(position)}&quot;
        }

        override fun onNothingSelected(p0: AdapterView&lt;*&gt;?) {

        }
    }
}</code></pre>
<p>함수 내부에는 스피너와 텍스트뷰를 불러오는 변수가 있습니다.</p>
<p>스피너에 대해 <code>onItemSelectedListener</code>를 사용하여 선택된 아이템에 대해 처리해 줄 작업을 지정합니다.</p>
<p>이 때 <code>AdapterView</code>는 <code>ListView</code>, <code>GridView</code>, <code>Spinner</code>, <code>Gallery</code>의 상위 클래스입니다. 우리가 사용하는 스피너에 <code>OnItemSelectedListener</code>로 이벤트를 등록해 줄 것입니다.</p>
<p>내부에 콜백함수 두개가 선언되어 있는데 <code>onItemSelected</code>는 클릭된 아이템에 대해 처리할 작업이며 <code>onNothingSelected</code>는 아무것도 선택되지 않았을 때 처리할 작업입니다.</p>
<p>우리는 아이템이 선택되었을 때 텍스트뷰의 내용을 스피너 아이템 인덱스 번호와 내용을 가져와서 뿌려줄 것입니다.</p>
<p>아이템 내용을 가져오는 방법은 <code>getItemAtPosition</code> 메서드를 사용하여 <code>position</code>을 매개변수로 받아 가져옵니다.</p>
<h3 id="외부에서-배열-받아오기">외부에서 배열 받아오기</h3>
<p>앞에서 실습한 내용은 메인 클래스 내부에서 임의로 배열을 만들어 적용한 것입니다. 외부에서 배열을 가져올 수도 있는데 <code>values</code> 디렉터리에 <code>array.xml</code>을 만들어주고 다음과 같이 입력해줍니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;resources&gt;
    &lt;string-array name=&quot;fruits&quot;&gt;
        &lt;item&gt;과일 선택&lt;/item&gt;
        &lt;item&gt;귤&lt;/item&gt;
        &lt;item&gt;파인애플&lt;/item&gt;
        &lt;item&gt;키위&lt;/item&gt;
        &lt;item&gt;망고&lt;/item&gt;
    &lt;/string-array&gt;
&lt;/resources&gt;</code></pre>
<p><code>&lt;string-array&gt;</code> 태그 안에 아이템 태그로 스피너 아이템을 만들어주었습니다.</p>
<p>메인으로 돌아가서 <code>fruits</code> 변수로 선언된 배열만 바꿔주면 됩니다.</p>
<pre><code class="language-kotlin">val fruits = resources.getStringArray(R.array.fruits)</code></pre>
<br>

<h2 id="view를-객체화-하여-접근하기">View를 객체화 하여 접근하기</h2>
<hr>
<details>
<summary>펼처보기</summary>
<div markdown="1">


<pre><code class="language-kotlin">// MainActivity.kt

class MainActivity : AppCompatActivity() {

    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContentView(R.layout.activity_main)
        setContentView(binding.root)

        var data = listOf(&quot;select&quot;, &quot;1월&quot;, &quot;2월&quot;, &quot;3월&quot;, &quot;4월&quot;, &quot;5월&quot;, &quot;6월&quot;)
        var adapter = ArrayAdapter&lt;String&gt;(this, R.layout.item_spinner, data)
        binding.spinner.adapter = adapter
        binding.spinner.onItemSelectedListener =object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(p0: AdapterView&lt;*&gt;?, view: View?, pos: Int, p3: Long) {
                binding.result.text = data.get(pos)
            }

            override fun onNothingSelected(p0: AdapterView&lt;*&gt;?) {

            }
        }
    }
}</code></pre>
<pre><code class="language-xml">&lt;!-- activity_main.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:id=&quot;@+id/result&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;선택 결과&quot;
            android:textSize=&quot;30sp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot; /&gt;
    &lt;Spinner
            android:id=&quot;@+id/spinner&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.38&quot;/&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<pre><code class="language-xml">&lt;!-- item_spinner.xml --&gt;

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;

    &lt;TextView
            xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
            android:id=&quot;@+id/tvItemSpinner&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;45dp&quot;
            android:paddingTop=&quot;10dp&quot;
            android:paddingStart=&quot;30dp&quot;
            android:textColor=&quot;@android:color/black&quot;
            android:textSize=&quot;15sp&quot;
            android:paddingLeft=&quot;30dp&quot;/&gt;</code></pre>
  </div>
  </details>]]></description>
        </item>
        <item>
            <title><![CDATA[Android: 라디오 버튼과 체크박스]]></title>
            <link>https://velog.io/@htwenty-1/Android-%EB%9D%BC%EB%94%94%EC%98%A4-%EB%B2%84%ED%8A%BC</link>
            <guid>https://velog.io/@htwenty-1/Android-%EB%9D%BC%EB%94%94%EC%98%A4-%EB%B2%84%ED%8A%BC</guid>
            <pubDate>Sat, 05 Feb 2022 18:24:18 GMT</pubDate>
            <description><![CDATA[<h2 id="html과-android의-라디오-버튼-비교">HTML과 Android의 라디오 버튼 비교</h2>
<hr>
<h3 id="html의-라디오-버튼">HTML의 라디오 버튼</h3>
<p>라디오 버튼은 어떤 항목 내에서 하나만 선택하여 값을 받을 때 사용합니다.</p>
<p>우리가 흔히 익숙하게 알고 있는 동그란 모양의 그 버튼을 말합니다. html에서는 다음과 같은 방법으로 만들어주었습니다.</p>
<pre><code class="language-html">&lt;input type=&quot;radio&quot; /&gt;</code></pre>
<p>이 때, 다양한 선택지가 존재한다면 <code>name</code> 속성으로 라디오 버튼을 그룹화 해주고 각각의 <code>value</code>를 다르게 지정해서 선택한 값을 서버로 전송해 줄 수 있는 것입니다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&gt;
    &lt;title&gt;Fruits&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form method=&quot;get&quot;&gt;
      &lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;apple&quot; /&gt; 사과 &lt;br /&gt;
      &lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;pear&quot; /&gt; 배 &lt;br /&gt;
      &lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;grape&quot; /&gt; 포도 &lt;br /&gt;
      &lt;button type=&quot;button&quot; onclick=&quot;onSubmit()&quot;&gt;조회&lt;/button&gt;
    &lt;/form&gt;
  &lt;/body&gt;

  &lt;script&gt;
    function onSubmit() {
      let clickedBtn = document.querySelector(&#39;input[name=&quot;fruit&quot;]:checked&#39;)
        .value;
      console.log(clickedBtn);
    }
  &lt;/script&gt;
&lt;/html&gt;</code></pre>
<p>위의 코드에서 살펴보면 각각의 라디오 버튼은 <code>name=&quot;fruit&quot;</code>이라는 속성으로 그룹화 되어있기 때문에 셋 중에 하나가 선택되는 구조로 되어 있음을 알 수 있습니다. 이 때 <code>value</code>를 각각 다르게 지정해서 조회 버튼을 클릭했을 때 어떤 값이 출력되었는지를 확인해 볼 수 있습니다.</p>
<h3 id="android에서의-라디오-버튼">Android에서의 라디오 버튼</h3>
<p>안드로이드에서는 <code>RadioGroup</code>이라는 태그를 중심으로 하위에 <code>RadioButton</code>이 위치하고 있으며 <code>RadioGroup</code>은 <code>html</code>의 라디오 버튼에서 <code>name</code>과 같은 역할을 합니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;


    &lt;RadioGroup
            android:id=&quot;@+id/radioGroup&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    &gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio1&quot;
                android:text=&quot;사과&quot;
                android:checked=&quot;true&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio2&quot;
                android:text=&quot;바나나&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio3&quot;
                android:text=&quot;오렌지&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
    &lt;/RadioGroup&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>라디오 그룹을 먼저 봤을 때 보통의 태그들과 별반 다를 것은 없어보입니다.
아이디가 주어져있고, 컨텐츠의 너비, 높이 그리고 기준점이 등록되어 있습니다.</p>
<p>그렇다면 라디오 버튼 하나만 가져와서 분해 해보겠습니다.</p>
<pre><code class="language-xml">&lt;RadioButton
    android:id=&quot;@+id/radio3&quot;
    android:text=&quot;오렌지&quot;
    android:layout_width=&quot;wrap_content&quot;
    android:layout_height=&quot;wrap_content&quot;
/&gt;</code></pre>
<p>안드로이드와 html의 라디오 버튼 접근 방식의 차이라고 한다면 html에서는 라디오버튼의 값을 조회할 때 value로 어떤 값이 선택되었는지 확인할 수 있지만, 안드로이드에서는 id를 사용해서 해당 아이디의 버튼이 선택되었을 경우에 대한 작업을 처리하게 할 수 있습니다.</p>
<p>예를 들어서 <code>radio1</code>이라는 아이디를 가진 버튼이 클릭되었을 때 작업을 처리한다면 <code>R.id.radio1 -&gt; 처리할 작업</code>과 같은 형태로 작성할 수 있습니다.</p>
<br>

<h2 id="선택된-라디오-버튼-값-조회해보기">선택된 라디오 버튼 값 조회해보기</h2>
<hr>
<h3 id="준비사항">준비사항</h3>
<p>라디오 버튼 그룹 밑에서 바로 확인할 수 있도록 텍스트뷰를 만들어서 값을 뿌려줄 준비를 해보겠습니다.</p>
<p>레이아웃 XML에서 텍스트뷰를 추가해줍니다. 이 때 <code>&lt;TextView&gt;</code>의 아이디는 <code>textView</code>로 줍니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;


    &lt;RadioGroup
            android:id=&quot;@+id/radioGroup&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
    &gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio1&quot;
                android:text=&quot;사과&quot;
                android:checked=&quot;true&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio2&quot;
                android:text=&quot;바나나&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
        &lt;RadioButton
                android:id=&quot;@+id/radio3&quot;
                android:text=&quot;오렌지&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
        /&gt;
    &lt;/RadioGroup&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:text=&quot;TextView&quot;
            android:layout_width=&quot;226dp&quot;
            android:layout_height=&quot;60dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/radioGroup&quot;
            android:layout_marginTop=&quot;60dp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.0&quot;
    /&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<h3 id="mainactivity에서-코드-작성">MainActivity에서 코드 작성</h3>
<h4 id="by-lazy를-사용해서-컴포넌트에-접근하기"><code>by lazy</code>를 사용해서 컴포넌트에 접근하기</h4>
<p>app 디렉터리 안에 들어있는 <code>build.gradle</code>에 뷰를 객체화 해주기 위해 다음과 같이 추가해줍니다.</p>
<pre><code class="language-gradle">android {
...

    buildFeatures {
        viewBinding true
    }
}</code></pre>
<p>그 다음 상단의 Sync Now를 클릭하여 프로젝트를 업데이트 해줍니다.</p>
<p>다시 MainActivity로 돌아와서 </p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.RadioGroup
import android.widget.TextView
import com.example.sample11.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    // 컴포넌트에 자유롭게 접근 가능
    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {

        // ActivityMainBiding을 사용할 때 setContentView를 아래와 같이 사용한다.
        setContentView(binding.root)

        // 실시간으로 바뀌는 값 가져오기
        binding.radioGroup.setOnCheckedChangeListener { _, checkedId -&gt;
            Log.d(&quot; &quot;, &quot;RadioButton is Clicked&quot;)
            when (checkedId) {
                R.id.radio1 -&gt; {
                    binding.textView.text = &quot;Apple is selected&quot;
                    Log.d(&quot; &quot;, &quot;Apple is selected&quot;)
                }
                R.id.radio2 -&gt; {
                    binding.textView.text = &quot;Banana is selected&quot;
                    Log.d(&quot; &quot;, &quot;Banana is selected&quot;)
                }
                R.id.radio3 -&gt; {
                    binding.textView.text = &quot;Orange is selected&quot;
                    Log.d(&quot; &quot;, &quot;Orange is selected&quot;)
                }
            }
        }

        super.onCreate(savedInstanceState)
    }
}</code></pre>
<p>여기에서는 <code>by lazy</code>를 사용해서 컴포넌트에 보다 쉽게 접근하여 <code>setOnCheckedChangeListener</code>를 사용해서 각 라디오버튼의 아이디를 기준으로 특정 작업을 처리하도록 해주었습니다.</p>
<h4 id="아이디-값으로-바로-컴포넌트에-접근하는-방법">아이디 값으로 바로 컴포넌트에 접근하는 방법</h4>
<p><code>by lazy</code>로 접근하는 방법은 접근해야 할 컴포넌트의 개수가 많을 때 유리하게 사용할 수 있습니다.</p>
<p>우리가 접근할 컴포넌트는 두개에 한정되기 때문에 어떤 방법을 사용하더라도 크게 문제가 되진 않지만 접근해야 할 컴포넌트의 개수가 많다면 아래와 같이 <code>id</code> 값으로 바로 접근하는 것은 코드의 양이 많아지는 결과를 초래할 수 있씁니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.RadioGroup
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        setContentView(R.layout.activity_main)
        super.onCreate(savedInstanceState)

        // id로 접근하기
        val radioGroup = findViewById&lt;RadioGroup&gt;(R.id.radioGroup)
        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        radioGroup.setOnCheckedChangeListener { _, checkedId -&gt;
            Log.d(&quot; &quot;, &quot;RadioButton is Clicked&quot;)
            when (checkedId) {
                R.id.radio1 -&gt; {
                    textView.text = &quot;Apple is selected&quot;
                    Log.d(&quot; &quot;, &quot;Apple is selected&quot;)
                }
                R.id.radio2 -&gt; {
                    textView.text = &quot;Banana is selected&quot;
                    Log.d(&quot; &quot;, &quot;Banana is selected&quot;)
                }
                R.id.radio3 -&gt; {
                    textView.text = &quot;Orange is selected&quot;
                    Log.d(&quot; &quot;, &quot;Orange is selected&quot;)
                }
            }
        }
    }
}</code></pre>
<br>

<h2 id="html과-android의-체크-박스-비교">HTML과 Android의 체크 박스 비교</h2>
<hr>
<h3 id="html의-체크박스">HTML의 체크박스</h3>
<p>체크박스는 라디오버튼과 다르게 체크가 되어 있는지를 확인한 후 <code>Boolean</code>으로 값을 반환해줍니다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot; /&gt;
    &lt;title&gt;Fruits&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;form method=&quot;get&quot;&gt;
      &lt;input type=&quot;checkbox&quot; name=&quot;fruit&quot; value=&quot;apple&quot; /&gt; 사과 &lt;br /&gt;
      &lt;input type=&quot;checkbox&quot; name=&quot;fruit&quot; value=&quot;pear&quot; /&gt; 배 &lt;br /&gt;
      &lt;input type=&quot;checkbox&quot; name=&quot;fruit&quot; value=&quot;grape&quot; /&gt; 포도 &lt;br /&gt;
      &lt;button type=&quot;button&quot; onclick=&quot;onSubmit()&quot;&gt;조회&lt;/button&gt;
    &lt;/form&gt;
  &lt;/body&gt;

  &lt;script&gt;
    function onSubmit() {
      let checkbox = document.querySelector(&quot;input:checked&quot;);
      console.log(Boolean(checkbox));
    }
  &lt;/script&gt;
&lt;/html&gt;</code></pre>
<h3 id="android의-체크박스">Android의 체크박스</h3>
<p>안드로이드의 체크박스는 <code>&lt;ChechBox&gt;</code>라는 태그를 사용하여 만들어줍니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;CheckBox
            android:id=&quot;@+id/checkBox&quot;
            android:text=&quot;CheckBox&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            app:layout_constraintBottom_toTopOf=&quot;@+id/textView&quot;
            android:layout_marginBottom=&quot;148dp&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;1.0&quot;/&gt;
    &lt;TextView
            android:id=&quot;@+id/textView&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintVertical_bias=&quot;0.596&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>이 체크박스를 체크여부에 따라 텍스트뷰의 내용을 바꿔보겠습니다.</p>
<p>우선 <code>MainActivity</code>에서 뷰를 객체화 해주기 위해 <code>build.gradle</code>에 다음과 같이 추가해줍니다.</p>
<pre><code class="language-gradle">android {
...

    buildFeatures {
        viewBinding true
    }
}</code></pre>
<p><code>MainActivity</code>에서 각 컴포넌트에 접근해서 체크박스가 체크되었을 때, 그렇지 않을 때 텍스트뷰의 내용을 바꿔주도록 하겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // traditional
        setContentView(R.layout.activity_main)
        val checkBox = findViewById&lt;CheckBox&gt;(R.id.checkBox)
        val textView = findViewById&lt;TextView&gt;(R.id.textView)

        checkBox.setOnCheckedChangeListener { _, isChecked -&gt;
            if (isChecked) {
                textView.text = &quot;checked!!&quot;
            } else {
                textView.text = &quot;unChecked!!&quot;
            }
        }
    }
}</code></pre>
<p><code>ActivityMainBinding</code>을 사용하는 방법으로 작성해보겠습니다. 이 때 <code>CompoundButton</code>을 사용하여 모든 버튼 요소에 접근에 접근해서 <code>OnCheckedChangeListener</code>를 사용하여 체크박스의 상태가 바뀔 때마다 텍스트뷰의 내용을 바꿔주는 함수를 별도로 작성해주겠습니다.</p>
<p>이를 <code>setOnCheckedChangeListener</code>의 매개변수로 받아서 체크박스에 대한 이벤트를 처리해줍니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CheckBox
import android.widget.CompoundButton
import android.widget.TextView
import com.example.sample12.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(binding.root)
        binding.checkBox.setOnCheckedChangeListener(checkListener)

    }

    val checkListener by lazy {
        // CompoundButton으로 모든 버튼 요소에 접근 가능
        CompoundButton.OnCheckedChangeListener { buttonView, isChecked -&gt;
            val checkBox = findViewById&lt;CheckBox&gt;(R.id.checkBox)
            val textView = findViewById&lt;TextView&gt;(R.id.textView)

            if (isChecked) {
                when (buttonView.id) {
                    R.id.checkBox -&gt; {
                        textView.text = &quot;checked!!&quot;
                    }
                }
            } else {
                when (buttonView.id) {
                    R.id.checkBox -&gt; {
                        textView.text = &quot;unChecked!!&quot;
                    }
                }
            }
        }
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: 상단 메뉴와 이벤트 처리하기]]></title>
            <link>https://velog.io/@htwenty-1/Android-%EC%83%81%EB%8B%A8-%EB%A9%94%EB%89%B4%EC%99%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@htwenty-1/Android-%EC%83%81%EB%8B%A8-%EB%A9%94%EB%89%B4%EC%99%80-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 03 Feb 2022 12:05:46 GMT</pubDate>
            <description><![CDATA[<h2 id="상단-메뉴-추가하기">상단 메뉴 추가하기</h2>
<hr>
<p>html에서는 상단바에 <code>navbar</code>를 추가할 때 웹에서는 <code>&lt;ul&gt;</code> 태그를 이용해서 메뉴들을 만들어주었습니다.</p>
<p>안드로이드에서는 <code>onCreateOptionsMenu</code>라는 함수를 오버라이드하여 사용자 지정 메뉴를 추가할 수 있습니다.</p>
<p>안드로이드에서의 <code>navbar</code>는 <code>action bar</code>라고 부릅니다.</p>
<p>우선 액션바를 만들어주기 위해서는 컴포넌트를 생성해주는 xml이 있어야 합니다.</p>
<pre><code class="language-xml">&lt;?xml version =&quot;1.0&quot; encoding =&quot;utf-8&quot;?&gt;
&lt;!--  Learn More about how to use App Actions: https://developer.android.com/guide/actions/index.html --&gt;
&lt;menu xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
      xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;

    &lt;!-- ACTION BAR --&gt;
    &lt;item
        android:id=&quot;@+id/menu_search&quot;
        android:icon=&quot;@android:drawable/ic_menu_search&quot;
        android:title=&quot;검색&quot;
        app:showAsAction=&quot;always|withText&quot;
    /&gt;

    &lt;item
        android:id=&quot;@+id/menu_chat&quot;
        android:icon=&quot;@android:drawable/sym_action_chat&quot;
        android:title=&quot;채팅&quot;
        app:showAsAction=&quot;always&quot;
    /&gt;

    &lt;item
        android:id=&quot;@+id/menu_email&quot;
        android:icon=&quot;@android:drawable/sym_action_email&quot;
        android:title=&quot;이메일&quot;
        app:showAsAction=&quot;ifRoom&quot;
    /&gt;

    &lt;item
        android:id=&quot;@+id/action_setting&quot;
        android:title=&quot;세팅&quot;
        app:showAsAction=&quot;never&quot;
    /&gt;

&lt;/menu&gt;</code></pre>
<p><code>menu</code>라는 태그 안에 <code>item</code>이라는 태그들이 들어 있으며 <code>item</code>이 액션바의 각 메뉴 역할을 합니다.</p>
<p>안드로이드에서 제공하는 무료 아이콘을 사용하기 위해 <code>android:icon</code>이라는 속성을 사용해 주었습니다.</p>
<p>그리고 <code>app:showAsAction</code> 속성은 직접 보여줄지 아닐지를 결정해줍니다.</p>
<p>검색의 경우 <code>app:showAsAction=&quot;always|withText&quot;</code>로 설정하여 항상 보여주거나 텍스트(검색)을 같이 보여주도록 하고 있습니다.</p>
<p>채팅의 경우는 항상 보여주도록 되어있고, 이메일은 공간의 여유가 있다면 보여주도록 하고 있습니다.</p>
<p>세팅의 경우 <code>never</code>로 되어 있기 때문에 토글 메뉴 속으로 숨겨질 것입니다.</p>
<p><code>MainActivity</code>로 돌아와 <code>onCreateOptionsMenu</code> 함수를 오버라이드 해주고 <code>menuInflater</code>로 메뉴 XML을 객체로 인스턴스화 해줍니다. </p>
<p>이를 <code>menu</code> 디렉터리의 <code>menu_main</code>에 확장시켜주었습니다.</p>
<p>액션바의 각 메뉴를 클릭하면 로그를 통해 함수가 실행되었음을 알려주고 <code>id</code>로 지정된 것들을 누르면 텍스트뷰가 바뀌도록 해주었습니다.</p>
<pre><code class="language-kotlin">// MainActivity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // action bar를 보이지 않게 해줌
//        supportActionBar?.setDisplayShowTitleEnabled(false)
    }

    // 사용자 지정 메뉴 추가
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_main, menu)
        return super.onCreateOptionsMenu(menu)
//        return false
    }

    // 메뉴 item 클릭시
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        Log.i(ContentValues.TAG,&quot;onOptionsItemSelected()가 실행됨.&quot;)

        val textView:TextView = findViewById(R.id.textView)
        when(item.itemId) {
            R.id.menu_search -&gt; textView.text = &quot;검색 메뉴가 클릭됨.&quot;
            R.id.menu_chat -&gt; textView.text = &quot;채팅 메뉴가 클릭됨.&quot;
            R.id.menu_email -&gt; textView.text = &quot;이메일 메뉴가 클릭됨.&quot;
            R.id.action_setting -&gt; textView.text = &quot;세팅 메뉴가 클릭됨.&quot;
        }
        return super.onOptionsItemSelected(item)
    }
}</code></pre>
<br>

<h2 id="이벤트-처리하기">이벤트 처리하기</h2>
<hr>
<p>어떤 버튼을 누르거나 기기를 흔들거나 할 때 모달을 띄우고 내용을 바꿔주고 보이던 것을 보이지 않게하는 것, 바로 이벤트입니다.</p>
<p>자바스크립트에서 이벤트 리스너를 통해 DOM 요소를 동적으로 만들어주었는데, 안드로이드에서도 마찬가지로 각각의 컴포넌트를 동적으로 만들어줄 수 있습니다.</p>
<p>이 때 <code>onClick</code> 함수를 오버라이드하여 사용하거나 각각의 컴포넌트에 ID로 접근하여 <code>OnClickListener</code>라는 메서드로 제어합니다.</p>
<p>다음과 같은 구조의 XML에 대해서</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;EditText
            android:id=&quot;@+id/editText&quot;
            android:layout_width=&quot;282dp&quot;
            android:layout_height=&quot;47dp&quot;
            android:inputType=&quot;text&quot;
            android:text=&quot;Name&quot;
            android:ems=&quot;10&quot;
            android:hint=&quot;@string/edit_hint&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintHorizontal_bias=&quot;0.496&quot;
            app:layout_constraintVertical_bias=&quot;0.39&quot;/&gt;
    &lt;Button
            android:id=&quot;@+id/button&quot;
            android:layout_height=&quot;46dp&quot; 
            android:text=&quot;Button&quot;
            android:layout_width=&quot;281dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/editText&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot; 
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot; 
            app:layout_constraintVertical_bias=&quot;0.137&quot;
            app:layout_constraintHorizontal_bias=&quot;0.492&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>입력란에 이름을 입력하고 버튼을 클릭했을 때 알림창으로 이름을 출력해주는 로직을 작성해보겠습니다.</p>
<pre><code class="language-kotlin">class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById&lt;Button&gt;(R.id.button)
        val edit = findViewById&lt;EditText&gt;(R.id.editText)

        button.setOnClickListener {
            AlertDialog.Builder(this@MainActivity)
                .setTitle(&quot;이름이 뭐에요?&quot;)
                .setMessage(edit.text)
                .setCancelable(false)
                .setNeutralButton(&quot;닫기&quot;, DialogInterface.OnClickListener{
                        _, _ -&gt; // ここに処理させたい内容を入れる。
                }).show()
        }
    }
}</code></pre>
<p>프로젝트 생성 동시에 기본적으로 생성되는 <code>onCreate</code> 함수 안에서 실행시켜주었습니다.</p>
<p>입력란과 버튼에 ID로 접근하여 버튼에 대해 이벤트를 세팅해줍니다.</p>
<h3 id="by-lazy-사용하여-이벤트-처리하기"><code>by lazy</code> 사용하여 이벤트 처리하기</h3>
<p>또 다른 방법으로는 <code>by lazy</code>를 사용하는 방법이 있습니다.</p>
<p>초기화를 늦게 시켜준다는 개념이었는데, 프로그램을 실행하자마자 초기화할 필요가 없는 경우에 대비하여 만들어진 녀석입니다.</p>
<p>두개의 버튼을 위 아래로 주고 위에 있는 버튼을 눌렀을 때 아래에 있는 버튼의 내용을 날짜가 출력되도록 프로그램을 작성해보겠습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;Button
            android:id=&quot;@+id/btn&quot;
            android:text=&quot;버튼_ONE&quot;
            android:layout_width=&quot;177dp&quot;
            android:layout_height=&quot;59dp&quot;
            android:onClick=&quot;onClick&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    /&gt;
    &lt;Button
            android:id=&quot;@+id/btn2&quot;
            android:text=&quot;TIME_BUTTON&quot;
            android:layout_width=&quot;248dp&quot;
            android:layout_height=&quot;64dp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintHorizontal_bias=&quot;0.501&quot;
            app:layout_constraintVertical_bias=&quot;0.135&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/btn&quot;/&gt;
&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<pre><code class="language-kotlin">import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import android.util.Log
import android.view.View
import android.widget.Button
import java.text.SimpleDateFormat
import java.util.*

class MainActivity : AppCompatActivity(), View.OnClickListener {

    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState
        setContentView(R.layout.activity_main)

        val btn2 = findViewById&lt;Button&gt;(R.id.btn2)
        btn2.setOnClickListener {
            Toast.makeText(this.applicationContext, &quot;버튼2 클릭&quot;, Toast.LENGTH_SHORT).show()
        }

    }


    @SuppressLint(&quot;SimpleDateFormat&quot;)
    override fun onClick(view: View?) {
        when(view?.id) {
            R.id.btn -&gt; {
                Log.d(&quot;버튼&quot;, &quot;클릭&quot;)

                val btn2 = findViewById&lt;Button&gt;(R.id.btn2)
                btn2.text = SimpleDateFormat(&quot;yyyy-MM-dd kk:mm:ss&quot;).format(Date())  // time에서 kk 사용시 24시간제로 출력됨
            }
        }
    }


}</code></pre>
<p><code>View.OnClickListener</code>를 메인클래스에서 사용하게 되면 <code>findViewId</code>로 직접 컴포넌트에 접근하여 클릭 이벤트를 줄 수 있습니다. 또한 <code>onClick</code> 함수를 별도로 만들어서 xml상에서 <code>android:onClick=&quot;onClick&quot;</code>로 직접 부여하여 사용할 수도 있습니다.</p>
<p>여기에서 <code>by lazy</code> 를 사용해 보겠습니다.</p>
<pre><code class="language-kotlin">import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.sample09.databinding.ActivityMainBinding
import java.util.*

class MainActivity : AppCompatActivity() {

    val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)    // 이 코드를 마주했을 때 binding이 초기화(객체화)됨.

        binding.btn.setOnClickListener {
            Toast.makeText(this.applicationContext, &quot;버튼_one 클릭&quot;, Toast.LENGTH_SHORT).show()

            binding.btn2.text=&quot;시간 출력~&quot;
        }
    }
}</code></pre>
<p><code>by lazy</code>를 사용하면 초기화를 늦게 해줍니다. 그래서 우선적으로 <code>onCreate</code> 함수가 실행되게 되고 함수 내부에서 <code>setContentView</code>를 만나면 <code>binding</code>이 초기화 되면서 버튼을 클릭했을 때 이벤트 리스너가 실행됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android: Layout]]></title>
            <link>https://velog.io/@htwenty-1/Android-Layout</link>
            <guid>https://velog.io/@htwenty-1/Android-Layout</guid>
            <pubDate>Thu, 03 Feb 2022 11:32:11 GMT</pubDate>
            <description><![CDATA[<h2 id="layout">Layout</h2>
<hr>
<h3 id="layout이란">Layout이란?</h3>
<p>흔히 레이아웃이라 하면 어떤 요소들을 적재적소에 효율적으로 배치하는 것을 말합니다.</p>
<p>예를 들어 새로 오픈한 마트의 전단지를 보면 마트 이름, 행사 상품, 약도, 주소, 전화번호 등등 다양한 것들이 기재되어 있는데, 보기좋은 형태를 취하고 있습니다.</p>
<p>소비자의 눈에 한눈에 들어오도록 일목요연하게 정리되어 있지요.</p>
<p>Application을 제작할 때 사용자가 조작하기 쉽도록 UI를 각 공간에 효율적으로 배치하는 일을 레이아웃이라고 합니다.</p>
<p>레이아웃에는 다양한 종류가 있고, 이 포스팅에서는 6가지 정도에 대해 살펴보려고 합니다.</p>
<h3 id="android의-layout">Android의 Layout</h3>
<p>우선 안드로이드 개발자 문서에서는 다음과 같이 레이아웃을 정의하고 있습니다.</p>
<blockquote>
</blockquote>
<p>레이아웃은 앱에서 사용자 인터페이스를 위한 구조(예: 활동)를 정의합니다. 레이아웃의 모든 요소는 <code>View</code>와 <code>ViewGroup</code> 객체의 계층 구조를 사용하여 빌드됩니다. 일반적으로 <code>View</code>는 사용자가 보고 상호작용할 수 있는 것을 그립니다. <code>ViewGroup</code>은 그림 1과 같이 <code>View</code> 및 기타 <code>ViewGroup</code> 객체의 레이아웃 구조를 정의하는 보이지 않는 컨테이너입니다.
<img src="https://images.velog.io/images/htwenty-1/post/683a5f3c-81b6-4287-8b7d-a6a631107909/image.png" alt="">
<strong>그림 1. UI 레이아웃을 정의하는 뷰 계층 구조 예</strong></p>
<p>우리에게 가장 친숙한 HTML로 살펴본다면 <code>View</code>는 사용자와 소통하는 각각의 컴포넌트에, <code>ViewGroup</code>은 그 컴포넌트들을 감싸고 있는 <code>&lt;div&gt;</code> 태그 정도로 봐도 무방할 것 같습니다.</p>
<p>안드로이드에서는 이를 XML로 작성하여 화면에 보여주며, 반드시 하나의 <code>View</code>나 <code>ViewGroup</code>으로 감싸져 있어야 합니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
              android:layout_width=&quot;match_parent&quot;
              android:layout_height=&quot;match_parent&quot;
              android:orientation=&quot;vertical&quot; &gt;
    &lt;TextView android:id=&quot;@+id/text&quot;
              android:layout_width=&quot;wrap_content&quot;
              android:layout_height=&quot;wrap_content&quot;
              android:text=&quot;Hello, I am a TextView&quot; /&gt;
    &lt;Button android:id=&quot;@+id/button&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello, I am a Button&quot; /&gt;
&lt;/LinearLayout&gt;</code></pre>
<p>이렇게 작성된 XML은 초기에 <code>MainActivity.kt</code> 안에 있는 클래스의 <code>onCreate()</code> 함수에 의해 호출되어 생성됩니다.</p>
<pre><code class="language-kotlin">fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}</code></pre>
<h3 id="layout에-배치되는-ui">Layout에 배치되는 UI</h3>
<p>여기서 UI라고 함은 텍스트 상자, 입력상자, 버튼 등 사용자에게 보여줄 다양한 요소를 말합니다. 이는 위에서 언급한 XML 문서로부터 작성되고 <code>onCreate()</code> 함수에 의해 초기화 됩니다.</p>
<p>각각의 요소들은 속성을 갖습니다.</p>
<pre><code class="language-html">&lt;div id=&quot;container&quot; class=&quot;wrap&quot; style=&quot;width: 100px; height: 100px;&quot; /&gt;</code></pre>
<p>html에서도 각 태그들은 위와 같이 속성과 값이라는 구조를 가지며 태그만의 특성을 나타내주었습니다.</p>
<p>안드로이드에서도 비슷한 방식을 취하는데 위의 xml을 예로 들어보겠습니다.</p>
<h4 id="androidlayout_width와-androidlayout_height"><code>android:layout_width</code>와 <code>android:layout_height</code></h4>
<p>모든 컴포넌트는 레이아웃 위에 배치됩니다. 이 때 레이아웃 컨테이너 내부에서 어느 정도의 너비와 높이를 가질 것인지 나타냅니다.</p>
<h4 id="match_parent와-wrap_content"><code>match_parent</code>와 <code>wrap_content</code></h4>
<p><code>match_parent</code>는 상위 뷰 그룹이 허용하는 한 최대한 커지도록 뷰에 지시합니다.
<code>wrap_content</code>는 콘텐츠에 필요한 치수대로 알아서 크기를 조절하라고 뷰에 지시합니다.</p>
<p>단, 픽셀과 같이 절대적인 단위를 사용하여 레이아웃 너비와 높이를 지정하는 것은 권장되지 않습니다. 밀도 독립형 픽셀 단위(dp)나 <code>wrap_content</code>, <code>match_parent</code>와 같은 상대적인 측정값을 사용하는 것이 좋습니다. </p>
<h4 id="androididid아이디"><code>android:id=&quot;@+id/아이디&quot;</code></h4>
<p>컴포넌트의 아이디를 나타냅니다. 아이디를 통해 <code>MainActivity</code>에서 각 컴포넌트에 접근하여 이벤트를 제어하거나 할 수 있습니다.</p>
<h4 id="androidorientationvertical-또는-horizontal"><code>android:orientation=&quot;vertical 또는 horizontal&quot;</code></h4>
<p>컨텐츠가 쌓이는 방식입니다. <code>horizontal</code>이면 컴포넌트가 수평하게 쌓입니다.
반대로 <code>vertical</code>이면 컴포넌트가 수직으로 쌓입니다.</p>
<br>

<h2 id="constraintlayout">ConstraintLayout</h2>
<hr>
<p>최신 레이아웃 방식입니다.</p>
<p>기존의 레이아웃도 물론 멋있는 애플리케이션을 만들 수 있었지만, 개발자들을 힘들게 만들었습니다.</p>
<p>그것은 바로 기기마다 다른 해상도가 주원인이었고, 개발자들은 어쩔 수 없이 다양한 해상도를 지원하기 위해 해상도만 다른 같은 앱을 여러개 만들었어야 했습니다.</p>
<p>그러나 Constraint Layout은 혁신을 불러왔습니다. 마치 HTML의 flex box처럼 작동하여 다양한 기기의 해상도에 맞게 알아서 컴포넌트의 크기를 최적화 해주기 때문입니다.</p>
<blockquote>
</blockquote>
<p>A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.</p>
<p>안드로이트 프로젝트를 새로 만들게 되면 레이아웃은 기본적으로 <code>Constraint</code>로 설정되어 있습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;</code></pre>
<br>


<h2 id="linearlayout">LinearLayout</h2>
<hr>
<blockquote>
</blockquote>
<p>LinearLayout is a view group that aligns all children in a single direction, vertically or horizontally. You can specify the layout direction with the <code>android:orientation</code> attribute.</p>
<p>쉽게 말해서 뷰 그룹의 하위에 속한 항목들을 수직 또는 수평방향으로, 단일 방향으로 배치하는 레이아웃입니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/99e9e117-c56e-40a6-b58d-50fa38cdb8d6/image.png" alt=""></p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
              android:layout_width=&quot;match_parent&quot;
              android:layout_height=&quot;match_parent&quot;
              android:orientation=&quot;vertical&quot; &gt;
    &lt;TextView android:id=&quot;@+id/text&quot;
              android:layout_width=&quot;wrap_content&quot;
              android:layout_height=&quot;wrap_content&quot;
              android:text=&quot;Hello, I am a TextView&quot; /&gt;
    &lt;Button android:id=&quot;@+id/button&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello, I am a Button&quot; /&gt;
&lt;/LinearLayout&gt;</code></pre>
<p>위 xml에서 레이아웃의 오리엔테이션이 수직으로 정의되어 있으므로 텍스트뷰와 버튼은 수직으로 배치됩니다.</p>
<p>위 아래로 긴 형태가 되는 것이지요.</p>
<br>

<h2 id="relativelayout">RelativeLayout</h2>
<hr>
<p>상대적 레이아웃이라고도 부릅니다. 구글 개발자 문서에 우연히 한국어로 된 문서가 있었습니다.</p>
<blockquote>
</blockquote>
<p><code>RelativeLayout</code>은 상대 위치에 하위 뷰를 표시하는 뷰 그룹입니다. 각 뷰의 위치는 동위 요소(예: 다른 뷰의 왼쪽 또는 아래)에 상대적이거나 상위 <code>RelativeLayout</code> 영역(예: 맨 아래, 왼쪽 또는 중앙으로 정렬됨)에 상대적인 위치로 지정될 수 있습니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/da60c87e-00e4-4086-9701-daab1ac1e8a4/image.png" alt=""></p>
<p>단, 컴포넌트를 만들어주고 위치를 지정해주지 않으면 모두 왼쪽 상단에 그려지기 때문에 <code>RelativeLayout.LayoutParams</code>를 사용하여 위치를 지정해줄 수 있습니다.</p>
<p><code>RelativeLayout.LayoutParams</code>를 네가지 정도만 가져와서 소개해보겠습니다.</p>
<blockquote>
</blockquote>
<ol>
<li><code>android:layout_alignParentTop</code> : &quot;<code>true</code>&quot;면 뷰의 상단 가장자리를 상위 뷰의 상단 가장자리와 일치시킵니다.</li>
<li><code>android:layout_centerVertical</code> : &quot;true&quot;면 하위 요소를 상위 요소 내에 세로로 중앙에 배치합니다.</li>
<li><code>android:layout_below</code> : 뷰의 상단 가장자리를 리소스 ID로 지정한 뷰 아래에 배치합니다.</li>
<li><code>android:layout_toRightOf</code> : 이 뷰의 왼쪽 가장자리를 리소스 ID로 지정된 뷰의 오른쪽에 배치합니다.</li>
<li>더 많은 내용은 <a href="https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams">여기</a>를 참고해주세요.</li>
</ol>
<br>

<h2 id="framelayout">FrameLayout</h2>
<hr>
<p>우선 설명입니다.</p>
<blockquote>
<p>FrameLayout is designed to block out an area on the screen to display a single item. Generally, FrameLayout should be used to hold a single child view, because it can be difficult to organize child views in a way that&#39;s scalable to different screen sizes without the children overlapping each other. You can, however, add multiple children to a FrameLayout and control their position within the FrameLayout by assigning gravity to each child, using the android:layout_gravity attribute.</p>
</blockquote>
<p>집어 치우고 여기서 FRAME은 액자입니다. 액자에는 사진을 넣습니다.</p>
<p>하나의 액자에 여러개의 사진을 같이 넣으면 마지막에 넣은 사진은 앞에 넣은 사진에 가려서 보이지 않을 것입니다.</p>
<p>이를 프레임 레이아웃에 연결시켜보면 액자 속에서 보이는 뷰는 보이지 않는 뷰를 가리고 있어서 보이지 않는 뷰의 전체를 다 볼 수 없게 됩니다.</p>
<p>세 개의 뷰가 있다고 가정했을 때 크기가 모두 같다면 가장 앞에 있는 뷰만 보이게 되고, 크기가 모두 다르다면 가장 큰 크기의 뷰는 자신을 가리고 있는 뷰에 의해 일부분만 보이게 될 것입니다.</p>
<p>아래와 같이 xml에서 컴포넌트를 정의했다고 가정하면</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:orientation=&quot;vertical&quot;
        tools:context=&quot;.MainActivity&quot;&gt;

    &lt;Button
            android:id=&quot;@+id/btn&quot;
            android:text=&quot;Button&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;112dp&quot;
            android:layout_weight=&quot;1&quot;
            android:onClick=&quot;onClick&quot;
    /&gt;

    &lt;FrameLayout
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot;
            android:layout_weight=&quot;1&quot;
    &gt;

        &lt;!-- 바다 그림 --&gt;
        &lt;ImageView
                android:id=&quot;@+id/sea&quot;
                android:layout_width=&quot;wrap_content&quot;
                android:layout_height=&quot;wrap_content&quot;
                app:srcCompat=&quot;@drawable/sea&quot;
        /&gt;

        &lt;!-- 자동차 그림 --&gt;
        &lt;ImageView
                android:id=&quot;@+id/pride&quot;
                android:layout_width=&quot;337dp&quot;
                android:layout_height=&quot;181dp&quot;
                app:srcCompat=&quot;@drawable/pride&quot;
        /&gt;

    &lt;/FrameLayout&gt;


&lt;/LinearLayout&gt;</code></pre>
<p><img src="https://images.velog.io/images/htwenty-1/post/5bfd05c7-9b38-4a78-86c5-3cd92c915a5d/image.png" alt=""></p>
<p>이와 같은 형태로 보일 것입니다.</p>
<p>나중에 들어간 자동자 사진이 맨 앞으로 나와서 처음 들어간 바다 사진을 가리는 것이지요.</p>
<p>참고로 여기서 <code>app:srcCompat=&quot;@drawable/pride&quot;</code>는 미디어를 삽입하기 위한 속성으로 <code>@drawble</code> 디렉터리 안에 들어있는 사진이름을 적어준 것입니다.</p>
<br>

<h2 id="gridlayout">GridLayout</h2>
<hr>
<p>CSS에서 그리드 시스템이라는 개념에 대해 들어보았을 것입니다.</p>
<p>MDN에서 다음과 같이 정의합니다.</p>
<blockquote>
</blockquote>
<p>그리드는 수평선과 수직선으로 이루어진 집합체로, 디자인 요소를 정렬할 수 있는 대상 패턴을 생성한다. 이 디자인은 페이지에서 페이지로 이동할 때 요소가 널뛰거나 너비가 바뀌지 않는 디자인 생성에 도움을 주어 웹 사이트의 일관성을 높여준다.
하나의 그리드은 대게 columns, rows로 구성되며, 각 행과 열 사이에 공백이 있는데, 대게는 이를 일컬어 gutters라고 부른다.</p>
<p>안드로이드에서도 마찬가지로 row와 column을 가지며 지정된 row와 column에 맞게 컴포넌트를 순서대로 정렬해줍니다.</p>
<p>아래 XML을 보시면 <code>&lt;GridLayout /&gt;</code>으로 선언되었고 이 태그는 <code>android:rowCount</code>과 <code>android:columnCount</code>라는 속성을 갖습니다.</p>
<p>4행 3열의 구조로 총 12칸을 가지며 1 ~ 12라는 값을 가진 버튼들은 순서대로 배치됩니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;LinearLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        android:orientation=&quot;vertical&quot;
        tools:context=&quot;.MainActivity&quot;&gt;

    &lt;TextView
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;/&gt;

    &lt;GridLayout
            android:layout_width=&quot;282dp&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:columnCount=&quot;3&quot;
            android:rowCount=&quot;4&quot;
            android:orientation=&quot;horizontal&quot;
    &gt;
        &lt;Button android:text=&quot;1&quot;/&gt;
        &lt;Button android:text=&quot;2&quot;/&gt;
        &lt;Button android:text=&quot;3&quot;/&gt;
        &lt;Button android:text=&quot;4&quot;/&gt;
        &lt;Button android:text=&quot;5&quot;/&gt;
        &lt;Button android:text=&quot;6&quot;/&gt;
        &lt;Button android:text=&quot;7&quot;/&gt;
        &lt;Button android:text=&quot;8&quot;/&gt;
        &lt;Button android:text=&quot;9&quot;/&gt;
        &lt;Button android:text=&quot;10&quot;/&gt;
        &lt;Button android:text=&quot;11&quot;/&gt;
        &lt;Button android:text=&quot;12&quot;/&gt;

    &lt;/GridLayout&gt;


&lt;/LinearLayout&gt;</code></pre>
<p>다음과 같은 결과를 얻을 수 있습니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/8be263e6-74e0-481b-8ee6-6bff0e09d29c/image.png" alt=""></p>
<br>

<h2 id="tablelayout">TableLayout</h2>
<hr>
<p>단어에서 느껴지는 것처럼 표를 기반으로 한 레이아웃입니다.</p>
<p>그리드와 비슷할 수 있으나 그리드는 행렬에 순서대로 컴포넌트가 자리잡는데 반해 테이블은 HTML에서의 테이블처럼 지정된 곳에 값을 넣어줄 수 있습니다.</p>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;&gt;
    &lt;TextView
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;Hello World!&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;/&gt;
    &lt;TableLayout
            android:layout_width=&quot;412dp&quot;
            android:layout_height=&quot;393dp&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot; 
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot; 
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;&gt;

        &lt;TableRow android:layout_width=&quot;match_parent&quot; 
                  android:layout_height=&quot;match_parent&quot;&gt;
            &lt;TextView android:text=&quot;국어&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
            &lt;TextView android:text=&quot;수학&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
            &lt;TextView android:text=&quot;영어&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
        &lt;/TableRow&gt;
        &lt;TableRow android:layout_width=&quot;match_parent&quot; 
                  android:layout_height=&quot;match_parent&quot;&gt;
            &lt;TextView android:text=&quot;80&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
            &lt;TextView android:text=&quot;90&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
            &lt;TextView android:text=&quot;100&quot; 
                      android:textSize=&quot;30sp&quot; 
                      android:padding=&quot;10dp&quot;/&gt;
        &lt;/TableRow&gt;
        &lt;TableRow android:layout_width=&quot;match_parent&quot; 
                  android:layout_height=&quot;match_parent&quot;/&gt;
        &lt;TableRow android:layout_width=&quot;match_parent&quot;
                  android:layout_height=&quot;match_parent&quot;/&gt;
    &lt;/TableLayout&gt;

&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>테이블 레이아웃 내부에는 <code>TableRow</code>가 존재하고 내부에 <code>TextView</code>가 들어있는 구조입니다.</p>
<p>마치</p>
<pre><code class="language-html">&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</code></pre>
<p>와 같은 구조로 볼 수 있습니다.</p>
<p>결과는 다음과 같습니다.</p>
<p><img src="https://images.velog.io/images/htwenty-1/post/2f032a42-ab12-4c63-89a4-a6050373308c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android : activity_main.xml 구성]]></title>
            <link>https://velog.io/@htwenty-1/Android-activitymain.xml-%EA%B5%AC%EC%84%B1</link>
            <guid>https://velog.io/@htwenty-1/Android-activitymain.xml-%EA%B5%AC%EC%84%B1</guid>
            <pubDate>Sun, 30 Jan 2022 07:53:17 GMT</pubDate>
            <description><![CDATA[<p><code>/app/src/main/res/layout/activity_main.xml</code>은 View를 구성하는 요소들이다.</p>
<h3 id="view-activity-fragment란">View, Activity, Fragment란?</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>View</td>
<td>화면 내 기본적인 UI 요소, 모든 UI 요소는 View 클래스의 서브클래스<br>Widget과 Layout으로 구분하며 Widget은 Button, TextView, CheckBox와 같은 시각적인 UI 요소를 의미함. <br> Layout은 화면에서 보이지 않으나 다른 View들을 담는 container 역할을 하는 것을 의미함.</td>
</tr>
<tr>
<td>Activity</td>
<td>하나의 화면과 밀접하게 연관되어 있는 독립형 실행 모듈</td>
</tr>
<tr>
<td>Fragment</td>
<td>두 개 이상의 Activity를 하나의 화면에서 구성하는 것.</td>
</tr>
</tbody></table>
<h3 id="activity_mainxml-구성">activity_main.xml 구성</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.MainActivity&quot;
&gt;
    &lt;TextView
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot;
            android:text=&quot;say Hello to&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintLeft_toLeftOf=&quot;parent&quot;
            app:layout_constraintRight_toRightOf=&quot;parent&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot; 
            android:id=&quot;@+id/sayHello&quot; 
            tools:ignore=&quot;HardcodedText&quot;
    /&gt;

    &lt;Button
            android:text=&quot;@string/butter&quot;
            android:layout_width=&quot;wrap_content&quot;
            android:layout_height=&quot;wrap_content&quot; 
            android:id=&quot;@+id/butter&quot;
            tools:ignore=&quot;MissingConstraints&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            android:layout_marginBottom=&quot;258dp&quot;
            android:layout_marginTop=&quot;50dp&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/sayHello&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            android:layout_marginStart=&quot;160dp&quot;
            android:layout_marginEnd=&quot;160dp&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    /&gt;


&lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;</code></pre>
<p>TextView는 텍스트 상자를 나타내고, Button은 버튼을 나타냄.</p>
<h3 id="mainactivitykt">MainActivity.kt</h3>
<pre><code class="language-kotlin">package com.test.androidstudy

import android.content.ContentValues
import android.content.DialogInterface
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog

class MainActivity : AppCompatActivity() {

    // val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {

        /*  biding을 사용한다면
            setContentView(R.layout.activity_main)
            setContentView(binding.root)

            binding.btnSay.setOnClickListener {
                Log.i(ContentValues.TAG, &quot;btnSay Tapped&quot;)
                binding.sayHello.text = &quot;Hello World!&quot;
            }
        */
        super.onCreate(savedInstanceState)

        // layout에 있는 activity_main.xml로 화면 정의
        setContentView(R.layout.activity_main)

        val sayHello:TextView = findViewById(R.id.sayHello)
        val butter = findViewById&lt;Button&gt;(R.id.butter)

        // 이벤트 추가
        butter.setOnClickListener {
            sayHello.text = &quot;What a nice Android World!&quot;

            // Toast 만들기
            val toast = Toast.makeText(this.applicationContext, &quot;button tapped&quot;, Toast.LENGTH_SHORT)
            toast.show()    // 토스트 보여주기

            // Alert 보여주기
            AlertDialog.Builder(this@MainActivity)
                .setTitle(&quot;Welcome to the Android World!&quot;)
                .setMessage(&quot;안드로이드 세계에 오신것을 환영합니다!!&quot;)
                .setCancelable(false)
                .setNeutralButton(&quot;닫기&quot;, DialogInterface.OnClickListener {
                    dialog, which -&gt; // 닫기버튼을 눌렀을 때 처리할 로직을 넣어줍니다.
                }).show()
        }

    }

    override fun onStart() {
        super.onStart()
        Log.i(ContentValues.TAG, &quot;onStart 실행&quot;)
    }

    override fun onResume() {
        super.onResume()
        Log.i(ContentValues.TAG, &quot;onResume 실행&quot;)
    }

    override fun onRestart() {
        super.onRestart()
        Log.i(ContentValues.TAG, &quot;onRestart 실행&quot;)
    }

    override fun onPause() {
        super.onPause()
        Log.i(ContentValues.TAG, &quot;onPause 실행&quot;)
    }

    override fun onStop() {
        super.onStop()
        Log.i(ContentValues.TAG, &quot;onStop 실행&quot;)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.i(ContentValues.TAG, &quot;onDestroy 실행&quot;)
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 24089 : ボールの移動 (Moving Balls)]]></title>
            <link>https://velog.io/@htwenty-1/BOJ-24089-%E3%83%9C%E3%83%BC%E3%83%AB%E3%81%AE%E7%A7%BB%E5%8B%95-Moving-Balls</link>
            <guid>https://velog.io/@htwenty-1/BOJ-24089-%E3%83%9C%E3%83%BC%E3%83%AB%E3%81%AE%E7%A7%BB%E5%8B%95-Moving-Balls</guid>
            <pubDate>Fri, 28 Jan 2022 04:58:09 GMT</pubDate>
            <description><![CDATA[<h2 id="問題">問題</h2>
<hr>
<p>$N$個のボールがあり、１から$N$までの番号が付けられている。
また、何個でもボールを入れることのできる$N$個の箱があり、箱には１から$N$までの番号が付けられている。</p>
<p>箱$i$（$1≦i≦N$）には最初、ボール$i$が入っていた。</p>
<p>JOI高校の生徒である葵は、この状態から箱とボールに対して$M$回の操作を行なった。</p>
<p>$j$回目の（$1≦j≦M$）の操作は、次のように行われた。</p>
<p>ボール$X_j$が入っている箱を探し、その箱からボール$X_j$を取り出す。その後、箱$Y_j$にボール $X_j$を入れる。</p>
<p>葵が$M$回の操作をすべて終えた後、$N$個のボールがそれぞれどの箱に入っているかを求めよ。</p>
<br>

<h2 id="input-＆-output">INPUT ＆ OUTPUT</h2>
<hr>
<p><img src="https://images.velog.io/images/htwenty-1/post/b72872e3-f742-4cb6-8618-b4fc9c0fb621/image.png" alt=""></p>
<br>

<h2 id="input-＆-outputの例">INPUT ＆ OUTPUTの例</h2>
<hr>
<p><img src="https://images.velog.io/images/htwenty-1/post/8ca6aa7c-aaab-43da-b822-48fb864c306b/image.png" alt=""></p>
<br>

<h2 id="コード作成">コード作成</h2>
<hr>
<h3 id="java">Java</h3>
<pre><code class="language-java">import java.util.Scanner;

public class Main {

    public static void main(String[] args) {

        // BOJ24089

        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();                   // 공의 개수
        int m = sc.nextInt();                   // 조작 횟수

        int[] box = new int [n];                // 박스를 공의 개수만큼 만들어줌

        for (int i = 0; i &lt; box.length; i++) {
            box[i] = i+1;                       // 조작하기 전 조건에 맞게 공 초기화
        }

        for (int i = 0; i &lt; m; i++) {
            int x = sc.nextInt();               // 꺼낼 공
            int y = sc.nextInt();               // 옮길 상자
            box[x-1] = y;
        }

        for (int ball : box) {
            System.out.println(ball);           // 개행을 두고 공을 순서대로 출력
        }

    }
}
</code></pre>
<br>

<h3 id="kotlin">Kotlin</h3>
<pre><code class="language-kotlin">import java.util.Scanner

fun main(args: Array&lt;String&gt;) = with(Scanner(System.`in`)) {

    val n:Int = nextInt()    // 공의 개수
    val m:Int = nextInt()    // 조작 횟수

    var index = 1
    val box:Array&lt;Int&gt; = Array(n) { index++ }


    for(i in 0 until m) {
        val x:Int = nextInt()
        val y:Int = nextInt()
        box[x-1] = y
    }

    for(ball in box) {
        println(ball)
    }

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin Programming Intermediate - 11]]></title>
            <link>https://velog.io/@htwenty-1/Kotlin-Programming-Intermediate-11</link>
            <guid>https://velog.io/@htwenty-1/Kotlin-Programming-Intermediate-11</guid>
            <pubDate>Thu, 27 Jan 2022 07:20:04 GMT</pubDate>
            <description><![CDATA[<h2 id="구단-관리-프로그램-작성하기">구단 관리 프로그램 작성하기</h2>
<blockquote>
</blockquote>
<h4 id="야구팀-관리-프로그램을-작성하시오">야구팀 관리 프로그램을 작성하시오.</h4>
<p>DTO는 Human을 상속받는 Picher, Batter가 있고 DAO에서 Mutablelist로 CRUD를 구현할 것. 단, 각각의 클래스는 하나의 파일에서 작성할 것.
파일 입출력 기능 구현할 것.</p>
<h3 id="main">Main</h3>
<pre><code class="language-kotlin">import dao.MemberDao
import kotlin.system.exitProcess

fun main(args: Array&lt;String&gt;) {

    // dao 생성
    val dao = MemberDao()

    while(true) {
        println(&quot;******************************************&quot;)
        println(&quot;************* 구단 관리 프로그램 *************&quot;)
        println(&quot;** 사용하실 메뉴 번호를 입력 후 엔터키를 누르세요. **&quot;)
        println(&quot;************* 1. 선수 등록 *****************&quot;)
        println(&quot;************* 2. 전체 선수 조회 *************&quot;)
        println(&quot;************* 3. 선수 검색 *****************&quot;)
        println(&quot;************* 4. 선수 정보 수정**************&quot;)
        println(&quot;************* 5. 선수 삭제 *****************&quot;)
        println(&quot;************* 6. 파일로 저장 ****************&quot;)
        println(&quot;************* 7. 파일 바로 출력 **************&quot;)
        println(&quot;************* 8. 프로그램 종료 ***************&quot;)
        print(&quot;****** 사용할 메뉴의 번호 &gt;&gt;&gt;&gt; &quot;)

        var wantToUse: Int = readLine()!!.toInt()

        when (wantToUse) {
            1 -&gt; dao.addMember()
            2 -&gt; dao.printAllData()
            3 -&gt; dao.searchWithName()
            4 -&gt; dao.editTeamList()
            5 -&gt; dao.deleteTeamList()
            6 -&gt; dao.saveAsText()
            7 -&gt; dao.printFileToConsole()
            8 -&gt; {
                println(&quot;프로그램이 종료됩니다...&quot;)
                exitProcess(0)
            }
        }
    }



}</code></pre>
<br>

<h3 id="dto">DTO</h3>
<pre><code class="language-kotlin">package dto

open class Human(var index:Int, var number: Int, var name: String, var age:Int, var height: Double, var ref:Int) {

    override fun toString(): String {
        return &quot;$index. 선수번호: $number, 선수이름: &#39;$name&#39;, 나이: $age, 선수 신장: $height, &quot;
    }
}

class Pitcher(index: Int, number: Int, name: String, age:Int, height: Double, ref:Int, var win:Int, var lost:Int, var defense:Double) : Human(index, number, name, age, height, ref) {

    override fun toString(): String {
        return super.toString() + &quot;전적: ${win}승 / ${lost}패, 방어율: $defense&quot;
    }

}

class Batter(index:Int, number:Int, name:String, age:Int, height:Double, ref:Int, var batCount:Int, var hit:Int, var batAvg:Double) : Human(index, number, name, age, height, ref) {

    override fun toString(): String {
        return super.toString() + &quot;타수: $batCount, 안타수: $hit, 타율: $batAvg&quot;
    }

}
</code></pre>
<br>

<h3 id="dao">DAO</h3>
<pre><code class="language-kotlin">package dao

import dto.Batter
import dto.Human
import dto.Pitcher
import java.io.File
import java.io.FileWriter

class MemberDao {

    var teamList:MutableList&lt;Human&gt; = mutableListOf(
        Pitcher(1, 1001, &quot;Kim&quot;, 25, 181.5, 1, 100, 42, 75.0, ),
        Batter(2, 1002, &quot;Park&quot;, 24, 181.5, 2, 75, 10, 24.0, )
    )



    // CRUD
    // CREATE
    fun addMember() {

        print(&quot;입력할 선수의 번호 &gt;&gt; &quot;)
        var number:Int = readLine()!!.toInt()
        print(&quot;입력할 선수명 &gt;&gt; &quot;)
        var name:String = readLine()!!
        print(&quot;입력할 선수의 나이 &gt;&gt; &quot;)
        var age:Int = readLine()!!.toInt()
        print(&quot;입력할 선수의 신장 &gt;&gt; &quot;)
        var height:Double = readLine()!!.toDouble()

        print(&quot;투수라면 1, 타자라면 2를 입력하세요 &gt;&gt; &quot;)
        var ref:Int = readLine()!!.toInt()

        var index = 0
        index++

        when (ref) {
            1 -&gt; {
                print(&quot;승리한 경기 수 &gt;&gt; &quot;)
                var win:Int = readLine()!!.toInt()
                print(&quot;패배한 경기 수 &gt;&gt; &quot;)
                var lost:Int = readLine()!!.toInt()
                var defense:Double = (win / lost).toDouble()

                teamList.add(Pitcher(index, number, name, age, height, ref, win, lost, defense))

                println(&quot;입력하신 선수가 추가되었습니다.&quot;)
            }

            2 -&gt; {
                print(&quot;타수 &gt;&gt; &quot;)
                var batCount:Int = readLine()!!.toInt()
                print(&quot;안타수 &gt;&gt; &quot;)
                var hit:Int = readLine()!!.toInt()
                var batAvg:Double = (batCount / hit).toDouble()

                teamList.add(Batter(index, number, name, age, height, ref, batCount, hit, batAvg))
                println(&quot;입력하신 선수가 추가되었습니다.&quot;)
            }

            else -&gt; println(&quot;잘못된 입력입니다. 다시 시도하세요.&quot;)
        }



    }


    // READ
    // 모든 데이터 출력
    fun printAllData() {
        if(teamList != null || teamList.size != 0) {
            for (item in teamList) println(item)
        } else if (teamList == null || teamList.size == 0) {
            println(&quot;작성된 명단이 한 건도 존재하지 않습니다.&quot;)
        }
    }

    // 검색
    fun searchWithName() {
        print(&quot;검색할 선수의 이름 입력 &gt;&gt; &quot;)
        var inputName:String = readLine()!!

        for(item in teamList) {
            if (item.name == inputName) {
                println(item)
            } else {
                println(&quot;검색결과가 없습니다&quot;)
            }
        }
    }


    // UPDATE
    // 수정

    private var Human.win: Int
        get() { return win }
        set(value) { win = value }

    private var Human.lost: Int
        get() { return lost }
        set(value) { lost = value }

    private var Human.bat: Int
        get() { return bat }
        set(value) { bat = value }

    private var Human.hit: Int
        get() { return hit }
        set(value) { hit = value }

    fun editTeamList() {
        printAllData()
        print(&quot;수정할 선수의 순번을 입력하세요 &gt;&gt; &quot;)
        val wantEdit:Int = readLine()!!.toInt() - 1
        println(&quot;다음 선수의 정보를 수정합니다.&quot;)
        println(&quot;${teamList[wantEdit]}&quot;)

        println(&quot;수정할 내용을 선택하세요.&quot;)
        for (item in teamList) {
            if (item.ref == 1) {
                print(&quot;*** [1]선수번호, [2]선수이름, [3]나이, [4]신장, [5]이긴 게임 수, [6]진 게임 수 &gt;&gt; &quot;)

                val editInform:Int = readLine()!!.toInt()

                when(editInform) {
                    1 -&gt; {
                        print(&quot;변경할 선수번호를 입력하세요 &gt;&gt; &quot;)
                        val newNumber:Int = readLine()!!.toInt()
                        teamList[wantEdit].number = newNumber
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    2-&gt; {
                        print(&quot;변경할 선수이름을 입력하세요 &gt;&gt; &quot;)
                        val newName:String = readLine()!!
                        teamList[wantEdit].name = newName
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    3-&gt; {
                        print(&quot;변경할 선수나이를 입력하세요 &gt;&gt; &quot;)
                        val newAge:Int = readLine()!!.toInt()
                        teamList[wantEdit].age = newAge
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    4-&gt; {
                        print(&quot;변경할 선수신장을 입력하세요 &gt;&gt; &quot;)
                        val newHeight:Double = readLine()!!.toDouble()
                        teamList[wantEdit].height = newHeight
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    5 -&gt; {
                        print(&quot;변경할 이긴 게임 수를 입력하세요 &gt;&gt; &quot;)
                        val newWinValue:Int = readLine()!!.toInt()
                        teamList[wantEdit].win = newWinValue
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    6 -&gt; {
                        print(&quot;변경할 이긴 게임 수를 입력하세요 &gt;&gt; &quot;)
                        val newWinValue:Int = readLine()!!.toInt()
                        teamList[wantEdit].lost = newWinValue
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }
                }

            } else if (item.ref == 2) {
                print(&quot;*** [1]선수번호, [2]선수이름, [3]나이, [4]신장, [5]타수, [6]안타수 &gt;&gt; &quot;)

                val editInform:Int = readLine()!!.toInt()

                when(editInform) {
                    1 -&gt; {
                        print(&quot;변경할 선수번호를 입력하세요 &gt;&gt; &quot;)
                        val newNumber:Int = readLine()!!.toInt()
                        teamList[wantEdit].number = newNumber
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    2-&gt; {
                        print(&quot;변경할 선수이름을 입력하세요 &gt;&gt; &quot;)
                        val newName:String = readLine()!!
                        teamList[wantEdit].name = newName
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    3-&gt; {
                        print(&quot;변경할 선수나이를 입력하세요 &gt;&gt; &quot;)
                        val newAge:Int = readLine()!!.toInt()
                        teamList[wantEdit].age = newAge
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    4-&gt; {
                        print(&quot;변경할 선수신장을 입력하세요 &gt;&gt; &quot;)
                        val newHeight:Double = readLine()!!.toDouble()
                        teamList[wantEdit].height = newHeight
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    5 -&gt; {
                        print(&quot;변경할 타수를 입력하세요 &gt;&gt; &quot;)
                        val newBat:Int = readLine()!!.toInt()
                        teamList[wantEdit].bat = newBat
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }

                    6 -&gt; {
                        print(&quot;변경할 안타 수를 입력하세요 &gt;&gt; &quot;)
                        val newHit:Int = readLine()!!.toInt()
                        teamList[wantEdit].hit = newHit
                        println(&quot;변경이 완료 되었습니다.&quot;)
                        break
                    }
                }
            }
        }

    }


    // DELETE
    fun deleteTeamList() {
        printAllData()
        print(&quot;삭제할 선수의 순번을 입력하세요 &gt;&gt; &quot;)
        var wantToDelete = readLine()!!.toInt() - 1
        teamList.removeAt(wantToDelete)
    }

    // File IO
    // 파일로 저장
    fun saveAsText() {

        val path:String = &quot;/User/hwangduil/test/test.rtf&quot;
        val writer = FileWriter(path)

        try {
            writer.write(teamList.toString())
        } catch (e:Exception) {
            e.printStackTrace()
        } finally {
            writer.close()
        }

    }

    // 파일을 콘솔로 출력
    fun printFileToConsole() {

        val path:String = &quot;/User/hwangduil/test/test.rtf&quot;

        val br = File(path).bufferedReader()
        val list = mutableListOf&lt;String&gt;()
        br.useLines { e -&gt; e.forEach { list.add(it) } }
        list.forEach { println(it) }

    }

}</code></pre>
]]></description>
        </item>
    </channel>
</rss>