해설 코드보고 개인과제 수정 및 추가하기
디테일페이지
우선 이미지를 받아오는 코드
//데이터 받아오기
var data = intent?.getParcelableExtra<MyItem>(Contants.Item_OBJECT)?:
//?: 로 null일 경우 앱이 꺼지지 않게 넣는 데이터
MyItem(R.drawable.sample1,"제목","위치","내용","아이디",1000,1,1,false)
//받은 데이터 집어넣기
binding.imgTitle.setImageResource(data.aImg)
binding.userId.text = data.aUserid
binding.userPrice.text = DecimalFormat("#,###").format(data.aPrice) + "원"
binding.userLocation.text = data.aUserlocation
binding.userSubtitle.text = data.aSubtitle
binding.userTitle.text = data.aTitle
이렇게 했었는데 튜터님께 물어보니 엘비스 연산자나, !! 같은 건 안좋다고 한다.
그래서 내가 했던 거에서 고치자면
//데이터 받아오기
var data = intent?.getParcelableExtra<MyItem>(Contants.Item_OBJECT)
//받은 데이터 집어넣기
binding.imgTitle.setImageResource(data?.aImg as Int)
binding.userId.text = data?.aUserid
binding.userPrice.text = DecimalFormat("#,###").format(data?.aPrice) + "원"
binding.userLocation.text = data?.aUserlocation
binding.userSubtitle.text = data?.aSubtitle
binding.userTitle.text = data?.aTitle
이렇게 as Int로 Int라고 정해주면 된다고 한다.그리고 다른 방법으로는 해설 코드에 나와있는 대로
setImageDrawable(ResourcesCompat.getDrawable(ResourcesCompat.getDrawable(resources,resId,null))
이 방식을 그냥 쓰라고 한다. 대신 저기 resId는 지금 받아온 데이터를 넣어야 하니
binding.imgTitle.setImageDrawable(ResourcesCompat.getDrawable(resources,data?.aImg,null))
이렇게 바꾸면 되는데 다만 이러면 어제처럼 Int? 로 뜨면서 이 코드를 쓸 수가 없다. 여기에 아까 배운 as Int로 인트라고 해주면
binding.imgTitle.setImageDrawable(ResourcesCompat.getDrawable(resources,data?.aImg as Int,null))
올바르게 오류가 뜨지 않는다. 다만 여기서 as Int 대신 let으로 바꾸면(오류뜨는거 alt+shift+enter 누르면 바뀐다)
binding.imgTitle.setImageDrawable(data?.aImg?.let {
ResourcesCompat.getDrawable(resources,
it,null)
})
이렇게 해설 코드와 똑같이 바뀐다.
길게 클릭해서 지우기
//길게 클릭해서 지우기
adapter.itemLongClick = object : MyAdapter.ItemLongClick {
override fun onLongClick(view: View, position: Int) {
val del = AlertDialog.Builder(this@MainActivity)
del.setIcon(R.mipmap.ic_launcher)
del.setTitle("상품 삭제")
del.setMessage("상품을 정말 삭제하시겠습니까?")
//확인을 눌렀을 때 뒤로가게끔
del.setPositiveButton("확인",
DialogInterface.OnClickListener { dialog, _ ->
dataList.removeAt(position)
adapter.notifyItemRemoved(position)
del.setNegativeButton("취소",
DialogInterface.OnClickListener { dialog, _ ->
//null 대신 dismiss()넣기
dialog.dismiss()
})
del.show()
}
}
이건 해설 코드 그대로 가져와봤는데, onBackPressed로 뒤로가기 다이얼로그 만들 때랑 비슷했다. 다만 리스트에서 삭제하는 기능이 들어가야 하는데 저렇게 리스트.removeAt(position)을 해주면 삭제가 되긴하는데 삭제되고 그 빠진 리스트로 다시 보여져야 하니 notifyItemRemoved(position)을 꼭 사용해야한다.
근데 이상태로 돌려보니 위 코드는 0번이라는 번호를 삭제하고, 리스트에는 1번부터 나타난다. 그런데 정작 그 아이템을 누르면 만약 3번을 눌렀다면 4번의 아이템이 나온다. 그냥 0번이란거를 리스트에서만 삭제하고 데이터를 넘길 때는 0번이 살아나는거 같다. 그래서 찾아보니
adapter.notifyItemRangeChanged(position,dataList.size)
이 코드를 써야했다. 다시 바뀐 리스트를 보여주는 코드인 것 같다.
토스트메세지 말고 스낵바 + 좋아요
fun showSnackbar(){
Snackbar.make(binding.root,"관심목록에 추가되었습니다",Snackbar.LENGTH_SHORT).show()
}
해설이랑 조금 다르게 써볼겸 해서 함수로 써놨는데
isLike = data?.isLike == true
//좋아요 눌렀을 때와 안눌렀을 때 사진 두개 다 넣기
binding.ivHeart.setImageResource(if(isLike){R.drawable.heart2}else{R.drawable.heart})
//좋아요 눌렀을 때
binding.layHeartClick.setOnClickListener {
//좋아요를 처음 눌렀을 때
if (!isLike) {
binding.ivHeart.setImageResource(R.drawable.heart2)
showSnackbar()
isLike = true
//그 외
}else {
binding.ivHeart.setImageResource(R.drawable.heart)
isLike = false
}
}
showSnackbar()대신 그 안에 있는 코드를 집어넣어도 된다.
그리고 좋아요 이미지를 visible과 invisible로 사용하는 줄 알았는데 저렇게 setImageResource안에 if로 해서 하면 두가지를 넣을 수 있었다. 좋아요가 눌렸다, 안눌렸다를 판별하기 위해 MyItem에도 val이 아닌 var로 string이 아닌 boolean으로 선언해준다. 이제 그게 들어갔으니 메인에도 일단 초기에 안눌린 상태이니 false를 모든 아이템 데이터에 추가 해 준다.
좋아요 쓰기 위해서는 메인->디테일->메인 으로 데이터가 다시 메인으로 돌아가야하므로 ActivityResultLauncher를 사용해서 intent해주는거로 바뀌었다.
lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
맨 위에 이렇게 선언을 먼저 해주고 onCreate안에
//디테일에서 받을 때
activityResultLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
val itemNum = it.data?.getIntExtra(Contants.Item_NUMBER, 0) as Int
val isLike = it.data?.getBooleanExtra("isLike", false) as Boolean
if (isLike) {
//안되었던 이유 -> MyItem에 선언된게 val이라 변할 수 없어서 var로 고쳐줘야함
dataList[itemNum].isLike = true
dataList[itemNum].aHeart += 1
} else {
if (dataList[itemNum].isLike) {
dataList[itemNum].isLike = false
dataList[itemNum].aHeart -= 1
}
}
//어댑터 갱신해주는 코드
adapter.notifyItemChanged(itemNum)
}
}
}
이렇게 써서 좋아요가 눌렸을 경우와, 좋아요가 눌리지 않았을 경우 각각 +1, -1 해주는 코드를 넣어준다. 근데
else {
dataList[itemNum].isLike = false
dataList[itemNum].aHeart -= 1
}
이렇게만 써버리면 누르지않고 그냥 뒤로가기를 눌렀을 때도 계속 -1씩 되기에 위에
else {
if (dataList[itemNum].isLike) {
dataList[itemNum].isLike = false
dataList[itemNum].aHeart -= 1
}
}
이렇게 if문으로 저렇게 감싸주면 내가 하트를 뺐을 때만 깎인다.
그리고 제일 중요한건 마지막 어댑터 갱신해주는 코드를 꼭 작성해야 적용이 된다.
플로팅버튼
스크롤 최상단으로 올리는 플로팅버튼 사용하는 건 뭔가 많이 복잡해 보였다.
//플로팅 버튼
binding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
fadeScroll()
}
})
일단 그대로 따라썼는데
fun fadeScroll() {
//애니메이션 효과
val fadeIn = AlphaAnimation(0f,1f).apply { duration = 500 }
val fadeOut = AlphaAnimation(1f,0f).apply { duration = 500 }
var isTop = true
binding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
//맨 위 일때
if (!binding.recyclerview.canScrollVertically(-1)
&& newState == RecyclerView.SCROLL_STATE_IDLE) {
binding.fbTotop.startAnimation(fadeOut)
binding.fbTotop.visibility = View.GONE
isTop = true
//아래일 때
}else {
if (isTop) {
binding.fbTotop.visibility = View.VISIBLE
binding.fbTotop.startAnimation(fadeIn)
isTop = false
}
}
}
})
}
각 애니메이션 효과 (0f는 0%, 1f는 100%를 나타냄)를 dration을 줘서 천천히 사라지고 나타나게 하고... 밑에는 그냥 공식처럼 외워야 할거 같다.
뭔가 수정하고 이런거에 많이 시간 잡아먹었는데...주말에 베이직반 과제도 해봐야겠다.
'내일배움캠프' 카테고리의 다른 글
본 캠프 40일 차 (0) | 2024.01.16 |
---|---|
본 캠프 39일 차 (0) | 2024.01.15 |
본 캠프 37일 차 (0) | 2024.01.11 |
본 캠프 36일 차 (1) | 2024.01.10 |
본 캠프 35일 차 (0) | 2024.01.09 |