html에서는 상단바에 navbar
를 추가할 때 웹에서는 <ul>
태그를 이용해서 메뉴들을 만들어주었습니다.
안드로이드에서는 onCreateOptionsMenu
라는 함수를 오버라이드하여 사용자 지정 메뉴를 추가할 수 있습니다.
안드로이드에서의 navbar
는 action 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
이 초기화 되면서 버튼을 클릭했을 때 이벤트 리스너가 실행됩니다.