Intro
- 오늘은 사용자 프로필페이지를 만들까한다. 내 페이지와의 차이점이라면 다른 사용자의 프로필을 구경할때 본다는점일것이다.
- 우리 앱에는 게시판기능이 들어가있다. 그래서 사실 프로필이 그렇게까지 필요한가싶기는한데 막상 넣지않기에는 좀 아쉬웠다. 왜냐하면 초기설계때부터 자기소개글을 작성하는부분이 있는데 여행에 도움이 되는 앱을 목표로 만들면서 커뮤니티 게시판을 운영하는데 거기에서 다른사람의 프로필을 볼 수 있으면 어찌되었건 사용자에게 더 좋은것 아닌가싶었다.
프로필 페이지
UI

- UI는 특별한것은 없고 아래 작성한 글 목록에서 해당 사용자가 작성한 글을 가져오는것과 사용자의 프로필 이미지와 닉네임을 가져오는것이 전부다.
- UI를 짜면서 딱히 어려운점은 없었고, 얼마나 실수없이 빠르게 만드는가를 보았을때에는 이전에비해 확실히 속도가 빨라진게 체감이되었다. 대략 10%정도는 빨라지지않았나싶다(느낌적인 느낌으로!?)
Initialize
- 기능이랄건없고 화면을 정상동작하도록하는데 필요한 기능들을 붙이는 시간이었다.
- 여기에 쓰인건 TabLayout+ViewPager2인데 왜냐하면 나중에 요구사항이 어떻게 바뀔지모르기에 지금 탭이 하나라고 TabLayout을 쓰지않았다가 나중에 바뀌면 대략 난감하기 때문에 이렇게구현했다. 그리고 ViewPager에 들어가는 Fragment에는 Recyclerview를 적용하였다. 왜냐하면 게시판 글목록이 넘어오기 때문이다.
- 상단은 Toolbar로 구현하였다. 다른 방식도 있겠지만 Toolbar가 디자인 요구사항에도 맞고 여기에 뒤로가기 화살표 Navigation달아서 쓰는게 깔끔해서이다. 그리고 Title 뿐 아니라 다른 icon을 배치하기도 생각보다 간단해서 사용했다.
- Recyclerview를 썼으니까 당연히 ListAdapter도 구현해줬다. 이게 오늘 내가 한 일이다 허헣..
class UserProfileActivity : AppCompatActivity() {
companion object {
const val EXTRA_MODEL = "extra_model"
fun newIntentForGetUserProfile(context: Context, model: UserProfileModel): Intent =
Intent(context, UserProfileActivity::class.java).apply {
putExtra(EXTRA_MODEL, model)
}
}
private val binding by lazy {
ActivityUserProfileBinding.inflate(layoutInflater)
}
private val adapter by lazy{
UserProfileTabLayoutAdapter(this@UserProfileActivity)
}
private val model by lazy {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(EXTRA_MODEL, UserProfileModel::class.java)
} else {
intent.getParcelableExtra(EXTRA_MODEL)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
initView()
}
private fun initView() = with(binding) {
userProfileViewpager.adapter = adapter
TabLayoutMediator(userProfileTablayout, userProfileViewpager) {tab, position ->
tab.setText(adapter.getTitle(position))
}.attach()
userProfileToolbar.setNavigationOnClickListener {
finish()
}
model?.let {
userProfileThumbnail.load(it.thumbnail)
userProfileNickname.text = it.nickname
userProfileContentTextview.text = it.selfContent
}
}
}
class UserProfileBoardFragment : Fragment() {
companion object{
fun newInstance() : UserProfileBoardFragment = UserProfileBoardFragment()
}
private var _binding : FragmentUserProfileBoardBinding? = null
private val binding get() = _binding!!
private val adapter by lazy {
UserProfileBoardListAdapter()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentUserProfileBoardBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initView()
}
private fun initView()=with(binding) {
userProfileBoardRecyclerview.adapter = adapter
}
override fun onDestroy() {
_binding = null
super.onDestroy()
}
}
class UserProfileBoardListAdapter(
) :
ListAdapter<UserProfileModel, UserProfileBoardListAdapter.UserProfileHolder>(
object : DiffUtil.ItemCallback<UserProfileModel>() {
override fun areItemsTheSame(
oldItem: UserProfileModel,
newItem: UserProfileModel
): Boolean {
return oldItem.thumbnail == newItem.thumbnail
}
override fun areContentsTheSame(
oldItem: UserProfileModel,
newItem: UserProfileModel
): Boolean {
return oldItem == newItem
}
}
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserProfileHolder {
val view = ItemUserProfileBoardBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return UserProfileHolder(view)
}
override fun onBindViewHolder(holder: UserProfileHolder, position: Int) {
holder.bind(getItem(position))
}
class UserProfileHolder(private val binding: ItemUserProfileBoardBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item : UserProfileModel)=with(binding) {
userProfileBoardUserThumbnail.load(item.thumbnail)
userProfileBoardNickname.text = item.nickname
userProfileBoardTitle.text = item.title
userProfileBoardThumbnail.load(item.image)
userProfileBoardLikes.text = item.likes
userProfileBoardViews.text = item.views
}
}
}
- 코드는 위에서 설명한것들중 핵심이라고 여겨지는것들만 적어보았다 ㅎㅎ
깎고 또 깎아야할 때
- 이제 새로 뭔가를 만들고 기능을 구현하는것은 얼추 마무리되었다. 지금부터는 앱을 돌아보며 디테일한 부분들을 하나하나 수정해가야하는 시기인것같다.
- 아직까지는 구현하고 점검하고 구현하고 점검하고 말고 더 좋은 방법을 잘 모르겠다..
- 최근 1주일의 일상은 현재까지 안된사항들 한바닥 적고 그거 쳐내고 또 적고 쳐내고 하고있다! 마지막까지 잘 쳐내자!
Outro
- 많이 배우고싶다. 당연히 지금도 많이 배우고있다. 그리고 내가 알고있다고 생각하는것들이 알고보면 잘 모르고 사용한것들이 많았다.(그중 대표적인게 requireContext, requireActivty) 이런것들도 프로젝트를 진행하고 부딪히며 배우고 알아가는 중이다.
- 일을 진행하는 방식과 개발자들의 협업방식도 더 자세히 배우고싶다. 지금도 최선을다해 글로도 소통하려고 노력중이고 그래서 노션에 최대한 기록하려고 하고있다. 기록을 해놓으니 확실히 소통하는데 시간이 줄어들고 일에 더 집중하게되어 이부분은 큰 장점이라고 느꼈다.
- 더 가독성좋은 코드를 보고싶다. Data와 View가 분리된 깔끔한 코드들을보며 내 코드에 가져와 적용하고싶다. 지금도 고민하며 짜는중이고, 팀원들과 소통하며 짜고있지만 확실히 더 높은 품질의 코드를 보는것이 필요한 시기가 온것같다..! 일단은 팀 프로젝트를 잘 마무리하는데 집중하고 이런모든것들은 취업하면 그곳에서 부분부분 경험할 수 있으리라 기대한다..!