1. 팀 프로젝트(숙련) 2일차
지난 시간에는 어떻게 앱을 만들지 구상하고, 기본적인 컨벤션을 가지고, git을 설정하는 시간을 가졌다.
오늘부터 본격적으로 앱 만들기에 돌입했다.
이번 프로젝트는 기술적으로 어려운 부분들이 꽤나 많아서 바로바로 뚝딱 만들어지진 않았고, 여러 시행착오 끝에 완성한 것들이 대부분이다.
상세페이지 UI 프로토타입
상세페이지 UI를 어떤 식으로 구성할지 파악하기 위해서 프로토타입을 먼저 만들어봤다.
(X같은 보노보노좌 등판)
파란 선을 기준으로, 위칸은 ScrollView 적용, 밑의 칸은 ScrollView 미적용이다.
그리고 Fragment이기 때문에 아래칸에 Contact와 Mypage Fragment로 이동하는 버튼도 따로 있다.
이미지, 번호, 상태메시지, 이메일, 이벤트는 유저의 데이터를 받아와서 연동할 예정이다.
(그리고 그걸 이제 Bundle을 이용해서 받아올 거고)
위의 화면을 구성하는 xml은 다음과 같다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toTopOf="@id/const_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_detail"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_dummy"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_phone"
android:layout_width="350dp"
android:layout_height="60dp"
android:layout_marginTop="30dp"
android:background="@drawable/rounded_background"
android:clipToOutline="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_detail">
<TextView
android:id="@+id/txt_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:hint="번호"
android:textColor="@color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/user_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="Phone Number"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txt_number" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_message"
android:layout_width="350dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="@drawable/rounded_background"
android:clipToOutline="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/const_phone">
<TextView
android:id="@+id/txt_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:hint="상태메시지"
android:textColor="@color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/user_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="Comment"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txt_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_email"
android:layout_width="350dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="@drawable/rounded_background"
android:clipToOutline="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/const_message">
<TextView
android:id="@+id/txt_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:hint="이메일"
android:textColor="@color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/user_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="e-mail"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txt_email" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_event"
android:layout_width="350dp"
android:layout_height="60dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="@drawable/rounded_background"
android:clipToOutline="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/const_email">
<TextView
android:id="@+id/txt_event"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:hint="이벤트"
android:textColor="@color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/user_event"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="Event"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/txt_event" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_btn"
android:layout_width="match_parent"
android:layout_height="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/btn_message"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:text="메시지 보내기"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_call"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_margin="10dp"
android:text="전화 걸기"
app:layout_constraintBottom_toBottomOf="@id/btn_message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_message" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Bundle
그 다음은 Bundle을 이용하여 ContactFragment에서 ContactDetailFragment로 데이터 전달을 하는 기능을 추가했다.
우선, Fragment에서 Fragment로 데이터를 전달하므로 RecyclerView와 Adapter를 사용하는 ContactFragment에서 데이터를 넘긴다.
adapter.itemClick = object : MyAdapter.ItemClick {
override fun onClick(view: View, position: Int) {
requireActivity().supportFragmentManager.beginTransaction().apply {
replace(R.id.frame, ContactDetailFragment.newInstance(dataList[position]))
setReorderingAllowed(true)
addToBackStack("")
}.commit()
}
}
그리고 ContactDetailFragment에서는 ContactFragment에서 전달한 데이터를 받는다.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val receiveData = arguments?.getParcelable<MyItem>("EXTRA_USER")
binding.userImage.setImageURI(receiveData?.icon)
binding.userName.text = receiveData?.name
binding.userPhone.text = receiveData?.phoneNum
binding.userMessage.text = receiveData?.myMessage
binding.userEmail.text = receiveData?.email
}
이 때, 데이터를 전달받을 때에 getParcelable을 사용한다.
마지막으로, ContactDetailFragment 밑에 있는 newInstance에 다음과 같이 적는다.
fun newInstance(myItem: MyItem) =
ContactDetailFragment().apply {
arguments = Bundle().apply {
putParcelable("EXTRA_USER", myItem)
}
}
이번에 처음으로 Parcelable을 이용해서 데이터 전달을 했는데 확실히 데이터를 전달받을 때에 굉장히 간결해졌다. 원래 데이터를 전달받을 때에는 param1, param2 등등을 사용해야 하는데 모든 putParcelable, getParcelable을 통해서 data class에 있는 객체들을 전부 끌어다 쓸 수 있으니.
트러블 슈팅 & 피드백
1. 트러블 슈팅
- Parcelable
- 물론 그 Parcelable을 처음부터 능숙하게 사용한 건 아니고, 여러가지 시행착오를 겪었다. 액티비티에서 액티비티로 사용할 때에는 별 문제가 없었는데 프래그먼트에서 프래그먼트로 받아오니 구성이 아예 달라져서 굉장히 힘들었다. Fragment에 있는 newInstance에 putParcelable을 쓰려는데 이걸 데이터를 보내는 ContactFragment에 적는 것이 맞는지, 아니면 데이터를 받는 ContactDetailFragment에 적는 것이 맞는지부터 replace에 있는 fragment.newInstance() 괄호 안에 무슨 변수를 집어넣어야 하는지까지.
- Android Studio 이슈
- Android Studio 프로그램 자체 버그 때문에 중간에 굉장히 당황했다.
- 분명 맞는 코드이고, 몇 초 전까지만 해도 정상적으로 돌아가던 건데 뭐 하나 수정하니까 갑자기 이상하게 작동하더라. 그래서 한 몇십 분 간 이리 고치고 저리 고치고 해도 안 됐다. 그런데 재실행 하니까 다시 정상적으로 돌아오드라.
2. 피드백
- 어제 만든 와이어프레임과 역할분배가 너무 간결하게 되어 있다고 하셨다. 그래서 팀원들끼리 모여서 이 부분을 보강하였다.
- 반대로 git 컨벤션은 너무 많다며 안 쓰는 기능은 생략해도 된다고 하셨다. 역시 팀원들과의 합의 하에 자주 안 쓰는 건 삭제하였다.
'[TIL][내일배움캠프]' 카테고리의 다른 글
[내일배움캠프][TIL] 24.01.18 (목) - 팀 프로젝트(숙련) 4일차 (0) | 2024.01.18 |
---|---|
[내일배움캠프][TIL] 24.01.17 (수) - 팀 프로젝트(숙련) 3일차 (0) | 2024.01.17 |
[내일배움캠프][TIL] 24.01.15 (월) - 팀 프로젝트(숙련) 1일차 (0) | 2024.01.15 |
[내일배움캠프][TIL] 24.01.12 (금) - Clone UI (1) | 2024.01.12 |
[내일배움캠프][TIL] 24.01.11 (목) - Android 앱개발 숙련 실습과제 4일차 (0) | 2024.01.11 |