Android: 상단 메뉴와 이벤트 처리하기

Beautify.log·2022년 2월 3일
0

Android with Kotlin

목록 보기
3/17
post-thumbnail

상단 메뉴 추가하기


html에서는 상단바에 navbar를 추가할 때 웹에서는 <ul> 태그를 이용해서 메뉴들을 만들어주었습니다.

안드로이드에서는 onCreateOptionsMenu라는 함수를 오버라이드하여 사용자 지정 메뉴를 추가할 수 있습니다.

안드로이드에서의 navbaraction bar라고 부릅니다.

우선 액션바를 만들어주기 위해서는 컴포넌트를 생성해주는 xml이 있어야 합니다.

<?xml version ="1.0" encoding ="utf-8"?>
<!--  Learn More about how to use App Actions: https://developer.android.com/guide/actions/index.html -->
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- ACTION BAR -->
    <item
        android:id="@+id/menu_search"
        android:icon="@android:drawable/ic_menu_search"
        android:title="검색"
        app:showAsAction="always|withText"
    />

    <item
        android:id="@+id/menu_chat"
        android:icon="@android:drawable/sym_action_chat"
        android:title="채팅"
        app:showAsAction="always"
    />

    <item
        android:id="@+id/menu_email"
        android:icon="@android:drawable/sym_action_email"
        android:title="이메일"
        app:showAsAction="ifRoom"
    />

    <item
        android:id="@+id/action_setting"
        android:title="세팅"
        app:showAsAction="never"
    />

</menu>

menu라는 태그 안에 item이라는 태그들이 들어 있으며 item이 액션바의 각 메뉴 역할을 합니다.

안드로이드에서 제공하는 무료 아이콘을 사용하기 위해 android:icon이라는 속성을 사용해 주었습니다.

그리고 app:showAsAction 속성은 직접 보여줄지 아닐지를 결정해줍니다.

검색의 경우 app:showAsAction="always|withText"로 설정하여 항상 보여주거나 텍스트(검색)을 같이 보여주도록 하고 있습니다.

채팅의 경우는 항상 보여주도록 되어있고, 이메일은 공간의 여유가 있다면 보여주도록 하고 있습니다.

세팅의 경우 never로 되어 있기 때문에 토글 메뉴 속으로 숨겨질 것입니다.

MainActivity로 돌아와 onCreateOptionsMenu 함수를 오버라이드 해주고 menuInflater로 메뉴 XML을 객체로 인스턴스화 해줍니다.

이를 menu 디렉터리의 menu_main에 확장시켜주었습니다.

액션바의 각 메뉴를 클릭하면 로그를 통해 함수가 실행되었음을 알려주고 id로 지정된 것들을 누르면 텍스트뷰가 바뀌도록 해주었습니다.

// 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,"onOptionsItemSelected()가 실행됨.")

        val textView:TextView = findViewById(R.id.textView)
        when(item.itemId) {
            R.id.menu_search -> textView.text = "검색 메뉴가 클릭됨."
            R.id.menu_chat -> textView.text = "채팅 메뉴가 클릭됨."
            R.id.menu_email -> textView.text = "이메일 메뉴가 클릭됨."
            R.id.action_setting -> textView.text = "세팅 메뉴가 클릭됨."
        }
        return super.onOptionsItemSelected(item)
    }
}

이벤트 처리하기


어떤 버튼을 누르거나 기기를 흔들거나 할 때 모달을 띄우고 내용을 바꿔주고 보이던 것을 보이지 않게하는 것, 바로 이벤트입니다.

자바스크립트에서 이벤트 리스너를 통해 DOM 요소를 동적으로 만들어주었는데, 안드로이드에서도 마찬가지로 각각의 컴포넌트를 동적으로 만들어줄 수 있습니다.

이 때 onClick 함수를 오버라이드하여 사용하거나 각각의 컴포넌트에 ID로 접근하여 OnClickListener라는 메서드로 제어합니다.

다음과 같은 구조의 XML에 대해서

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <EditText
            android:id="@+id/editText"
            android:layout_width="282dp"
            android:layout_height="47dp"
            android:inputType="text"
            android:text="Name"
            android:ems="10"
            android:hint="@string/edit_hint"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" 
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" 
            app:layout_constraintHorizontal_bias="0.496"
            app:layout_constraintVertical_bias="0.39"/>
    <Button
            android:id="@+id/button"
            android:layout_height="46dp" 
            android:text="Button"
            android:layout_width="281dp"
            app:layout_constraintTop_toBottomOf="@+id/editText"
            app:layout_constraintBottom_toBottomOf="parent" 
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent" 
            app:layout_constraintVertical_bias="0.137"
            app:layout_constraintHorizontal_bias="0.492"/>
</androidx.constraintlayout.widget.ConstraintLayout>

입력란에 이름을 입력하고 버튼을 클릭했을 때 알림창으로 이름을 출력해주는 로직을 작성해보겠습니다.

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

        val button = findViewById<Button>(R.id.button)
        val edit = findViewById<EditText>(R.id.editText)

        button.setOnClickListener {
            AlertDialog.Builder(this@MainActivity)
                .setTitle("이름이 뭐에요?")
                .setMessage(edit.text)
                .setCancelable(false)
                .setNeutralButton("닫기", DialogInterface.OnClickListener{
                        _, _ -> // ここに処理させたい内容を入れる。
                }).show()
        }
    }
}

프로젝트 생성 동시에 기본적으로 생성되는 onCreate 함수 안에서 실행시켜주었습니다.

입력란과 버튼에 ID로 접근하여 버튼에 대해 이벤트를 세팅해줍니다.

by lazy 사용하여 이벤트 처리하기

또 다른 방법으로는 by lazy를 사용하는 방법이 있습니다.

초기화를 늦게 시켜준다는 개념이었는데, 프로그램을 실행하자마자 초기화할 필요가 없는 경우에 대비하여 만들어진 녀석입니다.

두개의 버튼을 위 아래로 주고 위에 있는 버튼을 눌렀을 때 아래에 있는 버튼의 내용을 날짜가 출력되도록 프로그램을 작성해보겠습니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <Button
            android:id="@+id/btn"
            android:text="버튼_ONE"
            android:layout_width="177dp"
            android:layout_height="59dp"
            android:onClick="onClick"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
    />
    <Button
            android:id="@+id/btn2"
            android:text="TIME_BUTTON"
            android:layout_width="248dp"
            android:layout_height="64dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.501"
            app:layout_constraintVertical_bias="0.135"
            app:layout_constraintTop_toBottomOf="@+id/btn"/>
</androidx.constraintlayout.widget.ConstraintLayout>
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<Button>(R.id.btn2)
        btn2.setOnClickListener {
            Toast.makeText(this.applicationContext, "버튼2 클릭", Toast.LENGTH_SHORT).show()
        }
        
    }

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

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

}

View.OnClickListener를 메인클래스에서 사용하게 되면 findViewId로 직접 컴포넌트에 접근하여 클릭 이벤트를 줄 수 있습니다. 또한 onClick 함수를 별도로 만들어서 xml상에서 android:onClick="onClick"로 직접 부여하여 사용할 수도 있습니다.

여기에서 by lazy 를 사용해 보겠습니다.

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, "버튼_one 클릭", Toast.LENGTH_SHORT).show()

            binding.btn2.text="시간 출력~"
        }
    }
}

by lazy를 사용하면 초기화를 늦게 해줍니다. 그래서 우선적으로 onCreate 함수가 실행되게 되고 함수 내부에서 setContentView를 만나면 binding이 초기화 되면서 버튼을 클릭했을 때 이벤트 리스너가 실행됩니다.

profile
tried ? drinkCoffee : keepGoing;

0개의 댓글