package com.example.clone_recyclerview
data class ProductItem( val ivProduct:Int,
val tvPrice:String,
val tvTime:String,
val tvTitle:String,
val tvLoca:String)
package com.example.clone_recyclerview
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.clone_recyclerview.databinding.LayoutItemBinding
class ProductAdapter (val productItem: MutableList<ProductItem>) : RecyclerView.Adapter<ProductAdapter.Holder>() {
inner class Holder(val binding : LayoutItemBinding) : RecyclerView.ViewHolder(binding.root) {
val ivProduct = binding.ivProduct
val tvPrice = binding.tvPrice
val tvTime = binding.tvTime
val tvTitle = binding.tvTitle
val tvLoca = binding.tvLoca
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = LayoutItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return Holder(binding)
}
override fun getItemCount(): Int = productItem.size
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.ivProduct.setImageResource(productItem[position].ivProduct)
holder.tvPrice.text = productItem[position].tvPrice
holder.tvTime.text = productItem[position].tvTime
holder.tvTitle.text = productItem[position].tvTitle
holder.tvLoca.text = productItem[position].tvLoca
}
}
package com.example.clone_recyclerview
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.clone_recyclerview.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val dataList = mutableListOf<ProductItem>()
dataList.add(ProductItem(R.drawable.product, "200,000원", "12월 16일", "애플워치 팝니다.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product2, "80,000원", "12월 16일", "중고카페의자.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product3, "5,000원", "12월 16일", "귀여운 쿼카 파우치!", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product, "200,000원", "12월 29일", "애플워치 팝니다.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product2, "80,000원", "12월 16일", "중고카페의자.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product3, "5,000원", "12월 17일", "귀여운 쿼카 파우치!", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product, "200,000원", "12월 16일", "애플워치 팝니다.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product2, "80,000원", "12월 15일", "중고카페의자.", "서초구 반포2동"))
dataList.add(ProductItem(R.drawable.product3, "5,000원", "12월 16일", "귀여운 쿼카 파우치!", "서초구 반포2동"))
binding.productRecycle.adapter = ProductAdapter(dataList)
binding.productRecycle.layoutManager = LinearLayoutManager(this)
//상단바에 검색아이콘 클릭이벤트
binding.btnSearch.setOnClickListener {
val intent = Intent(this, SearchActivity::class.java)
startActivity(intent)
}
//플로팅버튼 클릭이벤트
binding.navigation.btnFloating.setOnClickListener{
val intent = Intent(this, SelectImageActivity::class.java)
startActivity(intent)
}
}
}
솔직히 이전 과제에 이미 item레이아웃을 가지고 있었기 때문에 RecyclerView로 바꾸는데에 오랜 시간이 걸리지 않았다. 다만 layout_item.xml의 제일 겉 레이아웃 width와 height를 match_parent로 해놔서, 맨 처음에 에뮬레이터를 켰더니 여백이 아주 빵빵하니 스크롤이 너무나도 길어졌다. 그래서 둘다 wrap_content로 바꿨더니 width가 너무 좁아져서 width는 match_parent로 바꾸고, height는 wrap_content로 맞춰주었다. 아이템뷰를 어떻게 맞춰줄지는 자율적이니까 상황에 맞춰서 작성해주면 되겠다.
겸사겸사 xml에서 문제점을 말하자면, 또! ClipToOutline이 scaleType이랑 같이 사용하니까 전혀 안먹혔기 때문에.. 그냥 ImageView를 CardView로 감싸주었다. 난 이게 제일 편하고 좋은 것 같다. 문제점도 없는 것 같은데.. 이 방법을 선호하게 될 것 같다.
그리고 탑바 밑에 button들도 같이 스크롤되어야해서 NestedScrollView를 활용했는데, 여기에서도 paddingBottom을 주지 않으면 맨 밑에 아이템이 뜨지 않는 오류가 있었다. 그리고 스크롤뷰 아래에 RecyclerView를 줄 때에는, 스크롤뷰 특성상 모든 아이템을 메모리에 로드하려고 해서 큰 리스트의 경우에는 성능 차이를 보일 수 있다고 했다. 그를 방지하기 위해 RecyclerView를 RelativeLayout로 감싸주는 것이 좋다고 해서 일단 좋다는대로 코드를 작성해보았다.
액티비티 코틀린 파일에서 Adapter클래스를 만들어주고, 뷰홀더를 만들어서 MainActivity와 연결하는 것은 실습파일을 바탕으로 만들었기 때문에, 하나씩 따라하다보면 어려운 점이 없었다. 직접 치면서 오히려 코드 이해도가 조금 좋아진 것 같다. 다만, 수준별 수업에서 보여주신 연결 코드는 데이터들을 object을 통해 싱글톤으로.. 관리하셔 데이터 관리에 대한 부분은 나중에 좀 더 공부를 해야할 것 같다..ㅎㅎ
Clone_UI를 아예 폴더째로 복사해서 만들었더니.. Clone_RecyclerView로 프로젝트를 바꾸는데 더 고생한 것 같다. 처음부터 그냥 새로 만들껄..
=> com.example.~ 이 부분은 우클릭으로 Refactor를 할 수 있다. 여기서 Refactor를 해줬어도 안바뀐 부분이 많아서, strings.xml에 "app_name"부분도 따로 바꿔줘야했다. 그 이후에 MainActivity에서 R클래스랑 databinding에서 오류가 나서 확인해보니까 settings.gradle.kts파일에 rootProject.name도 바꿔줘야했다.
그외에는 문자열 하드코딩한거.. stirng.xml에 넣어줬으면 좋았겠지만. 이건 지금 몇개 안되어서 나중에 마음만 고치면 후딱 수정가능할 것 같아서 굳이 손대지 않았다.. 음~
일단 기존에 Clone_UI로 원래 레포지토리를 올렸는데, 어짜피 연결된 거 합치고 싶어서 검색을 해보니까 로컬에서 폴더를 합치고 .git파일을 제일 상위에 옮겨서 push하기만 하면 된다고해서 이 방법을 사용해 보았다.
참고 블로그 : Git) 로컬 저장소의 경로를 변경하고 싶을 때
=> 보고 하긴헀는데, 어디서 push를 해야하는지 좀 헤맸었다. clone_ui와 clone_recyclerview를 포함하고 있는 상위폴더 위치에서 main 브랜치를 통해 그냥 push했는데, pull하라고 했었나..? 여튼 시키는대로 열심히 명령어를 치니까 진짜 만들어지긴했다. 근데 각 파일 수정하는 것에서 꽤 불편하다고 느껴서 프로젝트 진행중인 파일을 이렇게 합치는건 생각해 볼 문제인 것 같다.
폴더를 합치면서 봤는데.. 기존에 Clone_UI 폴더가 Clone_Ui라고 되어있었다. 왜 이런게 그렇게 거슬리는지.. 이름을 바꾸고 싶었는데 오류 파티를 벌였다..
2.1 참고블로그 : [Git] 폴더명 변경사항 반영하기
git mv 이전이름 원하는이름 : 파일이름/폴더이름을 변경하는 명령어
: 근데 얘는 대소문자를 딱히 구별해주는 것은 아니여서 내가 원하는대로 바꾸고 싶을 땐 바로 역할을 하지 못했다.
=> git mv Clone_Ui temp 한번 git mv temp Clone_UI 한번 씩 쳐줘서 통과했다.
2.2 참고 블로그 : github 파일명/폴더명 변경 (대소문자 변경) + 터미널 오류
사실 저 위에 가기 전에. 그냥 Push하면 알아서 바뀔 줄 알고 로컬에서 이름을 Clone_UI로 이미 바꿔놨었다. 그러니까 git mv 이전이름 원하는이름 명령어를 썼을 떄, fatal: source directory is empty, source=src/pages/Review, destination=src/pages/reivew 오류가 나왔다.
=>로컬이랑 github에 올라가 있는 폴더명이 일치해야 폴더(파일)명을 바꿀수 있다는 점을 기억하자.
이것도 별거 아닌데, 상위 폴더에 .idea폴더가 있어서.. 보기 좀.. 거슬린다고 생각해서 뭐하는 애인지 검색해봤더니 젯 브레인 사(안드로이드스튜디오 만든.. 곳이겠지?)의 IDE 설정과 관련된 파일이라고 해서 빼려는 사람들이 많나보다. 그래서 git에서 파일을 삭제하는 명령어를 사용해보았다.
=> git rm --cached -r 폴더/파일명 : 로컬에는 폴더/파일이 삭제되지 않고! 원격저장소에서만 지워진다.
=> git rm -r 폴더/파일명 : 원격저장소, 로컬 모두에서 폴더/파일이 지워진다.
=> .gitignore파일 활용하기 : 참고블로그 : .gitignore 적용하기
원격저장소에 올라가지도 않아도 되는 파일들에 대하여 git에서 추적하지 않도록 관리해주는 파일. 프로젝트 최상위 위치에 존재하여야하고, 작성 규칙(패턴이 있다.)