
화면 기획에서 입력받는 부분은 제일 마지막에 진행한다.
만약 입력받는 부분을 먼저 기획하는 경우 나중에 다시 수정할 수 있으므로 번거로워짐
화면 UI 요소 배치를 가장 먼저 구현
화면 UI 요소에 대한 기능을 그다음에 구현
기획이 완료된 후
class Tools {
}
// 프래그먼트들의 이름
enum class FragmentName(var str:String){
A_FRAGMENT("A"),
B_FRAGMENT("B"),
}
// 지정한 Fragment를 보여주는 메서드
// name : 프래그먼트 이름
// addToBackStack : BackStack에 포함 시킬 것인지
// isAnimate : 애니메이션을 보여줄 것인지
// data : 새로운 프래그먼트에 전달할 값이 담겨져 있는 Bundle 객체
fun replaceFragment(name:FragmentName, addToBackStack:Boolean, isAnimate:Boolean, data:Bundle?){
// Fragment 전환에 딜레이를 조금 준다.
SystemClock.sleep(200)
// Fragment를 교체할 수 있는 객체를 추출
val fragmentTransaction = supportFragmentManager.beginTransaction()
// 새로운 Fragment를 담을 변수
// var newFragment:Fragment? = null 이 코드는 지워주기
// oldFragment에 newFragment가 가지고 있는 Fragment 객체를 담아준다.
if(newFragment != null){
oldFragment = newFragment
}
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
}
// 새로운 Fragment에 전달할 Bundle 객체가 있다면 arguments 프로퍼티에 넣어준다.
if(data != null){
newFragment?.arguments = data
}
if(newFragment != null){
// 애니메이션 설정
if(isAnimate){
// oldFragment -> newFragment
// oldFragment : exit
// newFragment : enter
// newFragment -> oldFragment
// oldFragment : reenter
// newFragment : return
// MaterialSharedAxis : 좌우, 위아래, 공중 바닥 사이로 이동하는 애니메이션 효과
// X - 좌우
// Y - 위아래
// Z - 공중 바닥
// 두 번째 매개변수 : 새로운 화면이 나타나는 것인지 여부를 설정
// true : 새로운 화면이 나타나는 애니메이션이 동작한다.
// false : 이전으로 되돌아가는 애니메이션이 동작한다.
if(oldFragment != null){
// old에서 new가 새롭게 보여질 때 old의 애니메이션
oldFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
// new에서 old로 되돌아갈 때 old의 애니메이션
oldFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
oldFragment?.enterTransition = null
oldFragment?.returnTransition = null
}
// old에서 new가 새롭게 보여질 때 new의 애니메이션
newFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
// new에서 old로 되돌아갈 때의 애니메이션
newFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
newFragment?.exitTransition = null
newFragment?.reenterTransition = null
}
// Fragment를 교체한다.(이전 Fragment가 없으면 새롭게 추가하는 역할을 수행한다)
// 첫 번째 매개 변수 : Fragment를 배치할 FragmentContainer의 ID
// 두 번째 매개 변수 : 보여주고자 하는 Fragment 객체
fragmentTransaction.replace(R.id.containerMain, newFragment!!)
// addToBackStack 변수의 값이 true면 새롭게 보여질 Fragment를 BackStack에 포함시켜 준다.
if(addToBackStack == true){
// BackStack에 포함시킬 때 이름을 지정해주면 원하는 Fragment를 BackStack에서 제거할 수 있다.
fragmentTransaction.addToBackStack(name.str)
}
// Fragment 교체를 확정한다.
fragmentTransaction.commit()
}
}
// BackStack에서 Fragment를 제거한다.
fun removeFragment(name:FragmentName){
// BackStack에 가장 위에 있는 Fragment를 BackStack에서 제거한다
// supportFragmentManager.popBackStack()
// Fragment 전환에 딜레이를 조금 준다.
SystemClock.sleep(200)
// 지정한 이름으로 있는 Fragment를 BackStack에서 제거한다.
supportFragmentManager.popBackStack(name.str, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false)
}
}
// 프래그먼트들의 이름
enum class FragmentName(var str:String){
MAIN_FRAGMENT("MainFragment"),
B_FRAGMENT("B"),
}
fun replaceFragment(name:FragmentName, addToBackStack:Boolean, isAnimate:Boolean, data:Bundle?){
......
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 첫 화면 프래그먼트
FragmentName.MAIN_FRAGMENT -> {
newFragment = MainFragment()
}
FragmentName.B_FRAGMENT -> {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
// MainFragment가 나타나도록 한다.
replaceFragment(FragmentName.MAIN_FRAGMENT, false, false, null)
}
실행해서 프래그먼트가 잘 나오는지 확인

fragment_main.xml 작성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:transitionGroup="true"
tools:context=".MainFragment" >
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbarMain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/containerMain2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
class MainFragment : Fragment() {
lateinit var fragmentMainBinding: FragmentMainBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMainBinding = FragmentMainBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentMainBinding.root
}
}

https://fonts.google.com/icons





<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menuItemMainCalendar"
android:icon="@drawable/calendar_month_24px"
android:title="일별보기"
app:showAsAction="always" />
<item
android:id="@+id/menuItemMainShowAll"
android:icon="@drawable/clear_all_24px"
android:title="전체보기"
app:showAsAction="always" />
<item
android:id="@+id/menuItemMainAdd"
android:icon="@drawable/add_24px"
android:title="추가"
app:showAsAction="always" />
</menu>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMainBinding = FragmentMainBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
return fragmentMainBinding.root
}
// 툴바 구성
fun settingToolbar(){
fragmentMainBinding.apply {
toolbarMain.apply {
// 타이틀
title = "메모"
// 메뉴
inflateMenu(R.menu.main_menu)
}
}
}

// 프래그먼트들의 이름
enum class FragmentName(var str:String){
MAIN_FRAGMENT("MainFragment"),
B_FRAGMENT("B"),
}
// MainFragment의 하위 Fragment의 이름
enum class MainSubFragmentName(var str:String){
CALENDAR_FRAGMENT("CalendarFragment"),
SHOW_ALL_FRAGMENT("ShowAllFragment")
}
class MainFragment : Fragment() {
......
// 프래그먼트를 담을 프로퍼티
var oldFragment:Fragment? = null
var newFragment:Fragment? = null
......
// 지정한 Fragment를 보여주는 메서드
// name : 프래그먼트 이름
// addToBackStack : BackStack에 포함 시킬 것인지
// isAnimate : 애니메이션을 보여줄 것인지
// data : 새로운 프래그먼트에 전달할 값이 담겨져 있는 Bundle 객체
fun replaceFragment(name:MainSubFragmentName, addToBackStack:Boolean, isAnimate:Boolean, data:Bundle?){
// Fragment 전환에 딜레이를 조금 준다.
SystemClock.sleep(200)
// Fragment를 교체할 수 있는 객체를 추출
val fragmentTransaction = mainActivity.supportFragmentManager.beginTransaction()
// 새로운 Fragment를 담을 변수
// var newFragment:Fragment? = null 이 코드는 지워주기
// oldFragment에 newFragment가 가지고 있는 Fragment 객체를 담아준다.
if(newFragment != null){
oldFragment = newFragment
}
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 일자별 메모 보기 화면
MainSubFragmentName.CALENDAR_FRAGMENT -> {
}
// 전체 메모 보기 화면
MainSubFragmentName.SHOW_ALL_FRAGMENT -> {
}
}
// 새로운 Fragment에 전달할 Bundle 객체가 있다면 arguments 프로퍼티에 넣어준다.
if(data != null){
newFragment?.arguments = data
}
if(newFragment != null){
// 애니메이션 설정
if(isAnimate){
// oldFragment -> newFragment
// oldFragment : exit
// newFragment : enter
// newFragment -> oldFragment
// oldFragment : reenter
// newFragment : return
// MaterialSharedAxis : 좌우, 위아래, 공중 바닥 사이로 이동하는 애니메이션 효과
// X - 좌우
// Y - 위아래
// Z - 공중 바닥
// 두 번째 매개변수 : 새로운 화면이 나타나는 것인지 여부를 설정
// true : 새로운 화면이 나타나는 애니메이션이 동작한다.
// false : 이전으로 되돌아가는 애니메이션이 동작한다.
if(oldFragment != null){
// old에서 new가 새롭게 보여질 때 old의 애니메이션
oldFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
// new에서 old로 되돌아갈 때 old의 애니메이션
oldFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
oldFragment?.enterTransition = null
oldFragment?.returnTransition = null
}
// old에서 new가 새롭게 보여질 때 new의 애니메이션
newFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
// new에서 old로 되돌아갈 때의 애니메이션
newFragment?.enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
newFragment?.exitTransition = null
newFragment?.reenterTransition = null
}
// Fragment를 교체한다.(이전 Fragment가 없으면 새롭게 추가하는 역할을 수행한다)
// 첫 번째 매개 변수 : Fragment를 배치할 FragmentContainer의 ID
// 두 번째 매개 변수 : 보여주고자 하는 Fragment 객체
fragmentTransaction.replace(R.id.containerMain2, newFragment!!)
// addToBackStack 변수의 값이 true면 새롭게 보여질 Fragment를 BackStack에 포함시켜 준다.
if(addToBackStack == true){
// BackStack에 포함시킬 때 이름을 지정해주면 원하는 Fragment를 BackStack에서 제거할 수 있다.
fragmentTransaction.addToBackStack(name.str)
}
// Fragment 교체를 확정한다.
fragmentTransaction.commit()
}
}
// BackStack에서 Fragment를 제거한다.
fun removeFragment(name:MainSubFragmentName){
// BackStack에 가장 위에 있는 Fragment를 BackStack에서 제거한다
// supportFragmentManager.popBackStack()
// Fragment 전환에 딜레이를 조금 준다.
SystemClock.sleep(200)
// 지정한 이름으로 있는 Fragment를 BackStack에서 제거한다.
mainActivity.supportFragmentManager.popBackStack(name.str, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
표시할 메모는 제목만 표시한다.
CalendarFragment 생성

MainFragment의 프래그먼트 교체 when절에 CalendarFragment 객체를 담는 코드 작성
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 일자별 메모 보기 화면
MainSubFragmentName.CALENDAR_FRAGMENT -> {
newFragment = CalendarFragment()
}
// 전체 메모 보기 화면
MainSubFragmentName.SHOW_ALL_FRAGMENT -> {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMainBinding = FragmentMainBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
// 일자별 화면이 나오도록 한다.
replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
return fragmentMainBinding.root
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context=".CalendarFragment" >
<CalendarView
android:id="@+id/calendarMain"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/buttonMainToday"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="오늘" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp" />
</LinearLayout>



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/textCalendarSubject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</LinearLayout>
class CalendarFragment : Fragment() {
lateinit var fragmentCalendarBinding: FragmentCalendarBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentCalendarBinding = FragmentCalendarBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentCalendarBinding.root
}
}
// RecyclerView의 어댑터
inner class RecyclerMainAdapter : RecyclerView.Adapter<RecyclerMainAdapter.RecyclerMainViewHolder>(){
inner class RecyclerMainViewHolder(rowCalendarBinding: RowCalendarBinding):RecyclerView.ViewHolder(rowCalendarBinding.root){
val rowCalendarBinding:RowCalendarBinding
init {
this.rowCalendarBinding = rowCalendarBinding
this.rowCalendarBinding.root.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerMainViewHolder {
val rowCalendarBinding = RowCalendarBinding.inflate(layoutInflater)
val recyclerMainViewHolder = RecyclerMainViewHolder(rowCalendarBinding)
return recyclerMainViewHolder
}
override fun getItemCount(): Int {
return 10
}
override fun onBindViewHolder(holder: RecyclerMainViewHolder, position: Int) {
holder.rowCalendarBinding.textCalendarSubject.text = "메모 : $position"
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentCalendarBinding = FragmentCalendarBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingRecyclerMain()
return fragmentCalendarBinding.root
}
// RecyclerView 설정
fun settingRecyclerMain(){
fragmentCalendarBinding.apply {
recyclerMain.apply {
// 어댑터 설정
adapter = RecyclerMainAdapter()
// 레이아웃 매니저
layoutManager = LinearLayoutManager(mainActivity)
// 데코
val deco = MaterialDividerItemDecoration(mainActivity,MaterialDividerItemDecoration.VERTICAL)
addItemDecoration(deco)
}
}
}

ShowAllFragment 생성

MainFragment의 프래그먼트 교체 when절에 ShowAllFragment 객체를 담는 코드 작성
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 일자별 메모 보기 화면
MainSubFragmentName.CALENDAR_FRAGMENT -> {
newFragment = CalendarFragment()
}
// 전체 메모 보기 화면
MainSubFragmentName.SHOW_ALL_FRAGMENT -> {
newFragment = ShowAllFragment()
}
}
// 툴바 구성
fun settingToolbar(){
fragmentMainBinding.apply {
toolbarMain.apply {
// 타이틀
title = "메모"
// 메뉴
inflateMenu(R.menu.main_menu)
// 메뉴의 항목을 눌렀을 때.
setOnMenuItemClickListener {
// 메뉴의 항목 id로 분기한다.
when(it.itemId){
// 일자별 항목 보기 메뉴
R.id.menuItemMainCalendar -> {
replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
}
// 전체 메모 보기 메뉴
R.id.menuItemMainShowAll -> {
replaceFragment(MainSubFragmentName.SHOW_ALL_FRAGMENT, false, false, null)
}
// 추가
R.id.menuItemMainAdd -> {
}
}
true
}
}
}
}
앱을 실행해서 메뉴 항목이 잘 눌러지는 지 확인


fragment_show_all.xml 작성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
tools:context=".ShowAllFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerShowAll"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/textShowAllSubject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<TextView
android:id="@+id/textShowAllWriteDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
class ShowAllFragment : Fragment() {
lateinit var fragmentShowAllBinding: FragmentShowAllBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentShowAllBinding = FragmentShowAllBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentShowAllBinding.root
}
}
// RecyclerView의 어댑터
inner class RecyclerShowAllAdapter : RecyclerView.Adapter<RecyclerShowAllAdapter.RecyclerShowAllViewHolder>(){
inner class RecyclerShowAllViewHolder(rowShowAllBinding: RowShowAllBinding) : RecyclerView.ViewHolder(rowShowAllBinding.root){
val rowShowAllBinding:RowShowAllBinding
init {
this.rowShowAllBinding = rowShowAllBinding
this.rowShowAllBinding.root.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerShowAllViewHolder {
val rowShowAllBinding = RowShowAllBinding.inflate(layoutInflater)
val recyclerShowAllViewHolder = RecyclerShowAllViewHolder(rowShowAllBinding)
return recyclerShowAllViewHolder
}
override fun getItemCount(): Int {
return 10
}
override fun onBindViewHolder(holder: RecyclerShowAllViewHolder, position: Int) {
holder.rowShowAllBinding.textShowAllSubject.text = "메모 제목 : $position"
holder.rowShowAllBinding.textShowAllWriteDate.text = "2024-02-28"
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentShowAllBinding = FragmentShowAllBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingRecyclerShowAll()
return fragmentShowAllBinding.root
}
// RecyclerView 구성 메서드
fun settingRecyclerShowAll(){
fragmentShowAllBinding.apply {
recyclerShowAll.apply {
// 어댑터 설정
adapter = RecyclerShowAllAdapter()
// 레이아웃 매니저
layoutManager = LinearLayoutManager(mainActivity)
// 데코
val deco = MaterialDividerItemDecoration(mainActivity,
MaterialDividerItemDecoration.VERTICAL)
addItemDecoration(deco)
}
}
}

MemoAddFragment 생성

FragmentName에 B_FRAGMENT를 MEMO_ADD_FRAGMENT로 변경
// 프래그먼트들의 이름
enum class FragmentName(var str:String){
MAIN_FRAGMENT("MainFragment"),
MEMO_ADD_FRAGMENT("MemoAddFragment"),
}
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 첫 화면 프래그먼트
FragmentName.MAIN_FRAGMENT -> {
newFragment = MainFragment()
}
FragmentName.MEMO_ADD_FRAGMENT -> {
newFragment = MemoAddFragment()
}
}
// 메뉴의 항목 id로 분기한다.
when(it.itemId){
// 일자별 항목 보기 메뉴
R.id.menuItemMainCalendar -> {
replaceFragment(MainSubFragmentName.CALENDAR_FRAGMENT, false, false, null)
}
// 전체 메모 보기 메뉴
R.id.menuItemMainShowAll -> {
replaceFragment(MainSubFragmentName.SHOW_ALL_FRAGMENT, false, false, null)
}
// 추가
R.id.menuItemMainAdd -> {
// 메모를 추가하는 화면이 보이게 한다.
mainActivity.replaceFragment(FragmentName.MEMO_ADD_FRAGMENT, true, true, null)
}
}
앱을 실행해서 메뉴 항목이 잘 눌러지는 지 확인

fragment_add_memo.xml 작성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:transitionGroup="true"
tools:context=".MemoAddFragment" >
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbarMemoAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="메모 제목"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoAddSubject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="메모 내용"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoAddText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text|textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>

class MemoAddFragment : Fragment() {
lateinit var fragmentMemoAddBinding: FragmentMemoAddBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoAddBinding = FragmentMemoAddBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentMemoAddBinding.root
}
}





<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menuItemMemoAddDone"
android:icon="@drawable/done_24px"
android:title="완료"
app:showAsAction="always" />
</menu>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoAddBinding = FragmentMemoAddBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
return fragmentMemoAddBinding.root
}
// 툴바 설정 메서드
fun settingToolbar(){
fragmentMemoAddBinding.apply {
toolbarMemoAdd.apply {
// 타이틀
title = "메모 추가"
// Back
setNavigationIcon(R.drawable.arrow_back_24px)
setNavigationOnClickListener {
// 현재 Fragment를 BackStack에서 제거하여 이전 화면이 보이게 한다.
mainActivity.removeFragment(FragmentName.MEMO_ADD_FRAGMENT)
}
// 메뉴
inflateMenu(R.menu.memo_add_menu)
}
}
}

MemoReadFragment 생성

FragmentName에 MEMO_READ_FRAGMENT 추가
// 프래그먼트들의 이름
enum class FragmentName(var str:String){
MAIN_FRAGMENT("MainFragment"),
MEMO_ADD_FRAGMENT("MemoAddFragment"),
MEMO_READ_FRAGMENT("MemoReadFragment"),
}
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 첫 화면 프래그먼트
FragmentName.MAIN_FRAGMENT -> {
newFragment = MainFragment()
}
FragmentName.MEMO_ADD_FRAGMENT -> {
newFragment = MemoAddFragment()
}
FragmentName.MEMO_READ_FRAGMENT -> {
newFragment = MemoReadFragment()
}
}
override fun onBindViewHolder(holder: RecyclerMainViewHolder, position: Int) {
holder.rowCalendarBinding.textCalendarSubject.text = "메모 : $position"
// 항목을 누르면 동작하는 리스너
holder.rowCalendarBinding.root.setOnClickListener {
// 메모를 보는 화면이 나타나게 한다.
mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, null)
}
}
override fun onBindViewHolder(holder: RecyclerShowAllViewHolder, position: Int) {
holder.rowShowAllBinding.textShowAllSubject.text = "메모 제목 : $position"
holder.rowShowAllBinding.textShowAllWriteDate.text = "2024-02-28"
// 항목을 누르면 동작하는 리스너
holder.rowShowAllBinding.root.setOnClickListener {
// 메모를 보는 화면이 나타나게 한다.
mainActivity.replaceFragment(FragmentName.MEMO_READ_FRAGMENT, true, true, null)
}
}




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:transitionGroup="true"
tools:context=".MemoReadFragment" >
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbarMemoRead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="제목">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoReadSubject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="작성날짜">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoReadDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="내용">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoReadText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:inputType="text|textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>

TextInput 속성으로 enabled를 false로 해주면 비활성화처리가 되지만 내용물이 회색으로 연하게 출력된다.


따라서 enabled 속성 대신 editable 속성을 false로 처리해주면 비활성화와 함께 내용물이 제대로 출력된다.


class MemoReadFragment : Fragment() {
lateinit var fragmentMemoReadBinding: FragmentMemoReadBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoReadBinding = FragmentMemoReadBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentMemoReadBinding.root
}
}
delete, edit 아이콘 추가

MemoReadFragment 툴바 메뉴 셋팅


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/memuItemMemoReadModify"
android:icon="@drawable/edit_24px"
android:title="수정"
app:showAsAction="always" />
<item
android:id="@+id/memuItemMemoReadDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/delete_24px"
android:title="삭제"
app:showAsAction="always" />
</menu>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoReadBinding = FragmentMemoReadBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
return fragmentMemoReadBinding.root
}
// 툴바 설정
fun settingToolbar(){
fragmentMemoReadBinding.apply {
toolbarMemoRead.apply {
// 타이틀
title = "메모 보기"
// Back
setNavigationIcon(R.drawable.arrow_back_24px)
setNavigationOnClickListener {
mainActivity.removeFragment(FragmentName.MEMO_READ_FRAGMENT)
}
// 메뉴
inflateMenu(R.menu.memo_read_menu)
}
}
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoReadBinding = FragmentMemoReadBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
settingTextField()
return fragmentMemoReadBinding.root
}
// textField의 내용을 설정해준다.
fun settingTextField(){
fragmentMemoReadBinding.textFieldMemoReadSubject.setText("제목입니다")
fragmentMemoReadBinding.textFieldMemoReadText.setText("내용입니다")
fragmentMemoReadBinding.textFieldMemoReadDate.setText("2024-10-10")
}

MemoModifyFragment 생성

FragmentName에 MEMO_MODIFY_FRAGMENT 추가
// 프래그먼트들의 이름
enum class FragmentName(var str:String){
MAIN_FRAGMENT("MainFragment"),
MEMO_ADD_FRAGMENT("MemoAddFragment"),
MEMO_READ_FRAGMENT("MemoReadFragment"),
MEMO_MODIFY_FRAGMENT("MemoModifyFragment"),
}
// 이름으로 분기한다.
// Fragment의 객체를 생성하여 변수에 담아준다.
when(name){
// 첫 화면 프래그먼트
FragmentName.MAIN_FRAGMENT -> {
newFragment = MainFragment()
}
// 메모 추가 화면
FragmentName.MEMO_ADD_FRAGMENT -> {
newFragment = MemoAddFragment()
}
// 메모 읽기 화면
FragmentName.MEMO_READ_FRAGMENT -> {
newFragment = MemoReadFragment()
}
// 메모 수정 화면
FragmentName.MEMO_MODIFY_FRAGMENT -> {
newFragment = MemoModifyFragment()
}
}
// 툴바 설정
fun settingToolbar(){
fragmentMemoReadBinding.apply {
toolbarMemoRead.apply {
// 타이틀
title = "메모 보기"
// Back
setNavigationIcon(R.drawable.arrow_back_24px)
setNavigationOnClickListener {
mainActivity.removeFragment(FragmentName.MEMO_READ_FRAGMENT)
}
// 메뉴
inflateMenu(R.menu.memo_read_menu)
setOnMenuItemClickListener {
when(it.itemId){
// 수정
R.id.memuItemMemoReadModify -> {
mainActivity.replaceFragment(FragmentName.MEMO_MODIFY_FRAGMENT, true, true, null)
}
}
true
}
}
}
}
앱을 실행하여 MemoModifyFragment가 잘 실행되는지 확인


fragment_memo_modify.xml 작성
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:transitionGroup="true"
tools:context=".MemoModifyFragment" >
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbarMemoModify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="제목">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoModifySubject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="내용">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/textFieldMemoModifyText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text|textMultiLine" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>

class MemoModifyFragment : Fragment() {
lateinit var fragmentMemoModifyBinding: FragmentMemoModifyBinding
lateinit var mainActivity: MainActivity
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoModifyBinding = FragmentMemoModifyBinding.inflate(inflater)
mainActivity = activity as MainActivity
return fragmentMemoModifyBinding.root
}
}

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menuItemMemoModifyDone"
android:icon="@drawable/done_24px"
android:title="완료"
app:showAsAction="always" />
</menu>

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoModifyBinding = FragmentMemoModifyBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
return fragmentMemoModifyBinding.root
}
// 툴바를 구성한다.
fun settingToolbar(){
fragmentMemoModifyBinding.apply {
toolbarMemoModify.apply {
// 타이틀
title = "메모 수정"
// Back
setNavigationIcon(R.drawable.arrow_back_24px)
setNavigationOnClickListener {
mainActivity.removeFragment(FragmentName.MEMO_MODIFY_FRAGMENT)
}
// 메뉴
inflateMenu(R.menu.memo_modify_menu)
}
}
}

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
fragmentMemoModifyBinding = FragmentMemoModifyBinding.inflate(inflater)
mainActivity = activity as MainActivity
settingToolbar()
settingTextField()
return fragmentMemoModifyBinding.root
}
// TextField에 문자열을 설정한다.
fun settingTextField(){
fragmentMemoModifyBinding.apply {
textFieldMemoModifySubject.setText("메모 제목")
textFieldMemoModifyText.setText("메모 내용")
}
}

fragmentCalendarBinding.apply {
buttonMainToday.setOnClickListener {
calendarMain.setDate(Date().time,true,true)
}
}
android:background="?android:attr/selectableItemBackground"※ 출처 : 멋쟁이사자 앱스쿨 2기, 소프트캠퍼스