appleMarket - detail

박재원·2024년 1월 11일
0

TIL

목록 보기
28/50
post-thumbnail
post-custom-banner

build.gradle

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("kotlin-parcelize")
}
  • @Parcelize 기능을 사용하기 위해 플러그인에 id를 넣어준다.
 buildFeatures {
        viewBinding = true
    }
  • 이번 프로젝트부터 viewBinding을 사용하기 위해 넣어주었다.

Post.kt

@Parcelize
data class Post() : Parcelable
  • Serializable과 다르게 리플렉션을 사용하지 않고,필요한 부분만 직렬화 비직렬화 할 수 있어 효율성과 가독성을 높일 수 있다.

Adapter.kt

with(holder) {
	imageView.setImageResource(item.itemImage)
	titleText.text = item.itemTitle
	address.text = item.itemAddress
	price.text = "${format.format(money)}원"
	comment.text = item.itemcomment.toString()
	heart.text = item.itemheartCount.toString()
	itemView.setOnClickListener {
		if (itemClick != null) {
			itemClick!!.onClick(it, position)
    	}
	}
}
  • View에 출력되는 데이터들을 Post데이터들과 연결시켜 View생성한다.
  • scope function의 with를 사용해 holder를 묶어 가독성을 높였다.
init {
	imageView.clipToOutline = true
	with(binding) {
		root.setOnClickListener {
			val position = adapterPosition
			if (position != RecyclerView.NO_POSITION) {
				itemClick?.onClick(it, position)
			}
		}	
		root.setOnLongClickListener {
			val position = adapterPosition
			if (position != RecyclerView.NO_POSITION) {
				longitemClick?.onLongClick(it, position)
				true
			} else false
		}
	}	
}
  • View를 클릭하거나 길게 클릭하게되면 View와 Position이 넘어간다.

MainActivity

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
}
  • 뷰 바인딩을 사용하면 직접 id를 적고 타입을 정하고 이런 작업을 하지 않아도 된다.
  • 자동으로 클래스 파일을 생성해주기 때문이다.
val adapter = Adapter(productList)
        binding.recyclerview.adapter = adapter
        binding.recyclerview.layoutManager = LinearLayoutManager(this)
  • 생성한 어댑터를 초기화 해주고 recyclerview를 adapter와 연결해준다.
  • layoutManager의 LinearLayoutManager()를 이용해 수직의 스크롤 리스트를 만든다.
val decoration = DividerItemDecoration(this, VERTICAL)
binding.recyclerview.addItemDecoration(decoration)
  • 위의 코드를 사용해 recyclerview의 View 사이사이에 회색줄을 넣어준다.
adapter.itemClick = object : Adapter.ItemClick {
	override fun onClick(view: View, position: Int) {
	val clickProduct = productList[position]
	val intent = Intent(this@MainActivity,DetailActivity::class.java)
	intent.putExtra("Item", clickProduct)
	intent.putExtra("likePosition", position)
	activityResultLauncher.launch(intent)
	}
}
  • item을 클릭하게되면 View안에 있는 데이터와 position 값을 DetailActivity로 넘겨준다.
adapter.longitemClick = object : Adapter.LongItemClick {
	@SuppressLint("NotifyDataSetChanged")
	override fun onLongClick(view: View, position: Int) {
		val deleteItem = productList[position]
		AlertDialog.Builder(this@MainActivity).apply {
			setIcon(R.drawable.chat)
			setTitle("삭제")
			setMessage("정말로 삭제하시겠습니까?")
			setPositiveButton("확인") { _, _ ->
				productList.remove(deleteItem)
				//notifyDataSetChanged = 아이템 데이터 업데이트
				adapter.notifyDataSetChanged()
			}
			setNegativeButton("취소") { dialog, _ ->
				dialog.dismiss()
			}
			show()
		}
	}
}
  • item을 길게 클릭하게되면 Adapter의 root.setOnLongClickListener {} 가 실행된다.
  • 다이얼로그가 뜨면서 '확인'을 누르게되면 productList.remove(deleteItem)로 item이 삭제된다.
  • adapter.notifyDataSetChanged()로 업데이트를 하게되면서 삭제된 데이터를 빼고 출력하게된다.
val adList = resources.getStringArray(R.array.location)
        val adAdapter =
            ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, adList)
        binding.spinner.adapter = adAdapter
  • 어댑터를 만들어 리스트와 스피너를 연결해 스피너를 클릭하면 연결된 리스트들이 출력된다.
var isTop = true
	binding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
	override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
		super.onScrollStateChanged(recyclerView, newState)
		//canScrollVertically = 스크롤이 최상단 , SCROLL_STATE_IDLE = 현재 스크롤 하지 않은 상태
		if (!binding.recyclerview.canScrollVertically(-1) && newState == RecyclerView.SCROLL_STATE_IDLE) {
			binding.fabTop.visibility = View.INVISIBLE
            binding.fabTop.startAnimation(AlphaAnimation(1f, 0f).also {
				it.duration = 1000
			})
		} else if (isTop) {
			binding.fabTop.visibility = View.VISIBLE
           	binding.fabTop.startAnimation(AlphaAnimation(0f, 1f).also {
				it.duration = 1000
			})
			isTop = false
		}
	}
})
binding.fabTop.setOnClickListener {
  //smoothScrollToPosition = 부드럽게 스크롤 상단으로 옮김
	binding.recyclerview.smoothScrollToPosition(0)
}
  • if문을 통해 스크롤이 최상단에 있거나 움직이 않았을 때는 플로팅 버튼이 보이지 않게 했다.
  • 만일 아니라면 플로팅 버튼이 보이게되고 AlphaAnimation()을 이용해 서서히 보이는 애니메이션을 활용했다.
activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
	if (it.resultCode == RESULT_OK) {
		val likePosition = it.data?.getIntExtra("likePosition", 0) as Int
		val isLiked = it.data?.getBooleanExtra("isLiked", false) as Boolean
		if (isLiked) {
			productList[likePosition].isLiked = true
            productList[likePosition].itemheartCount++
		} else {
			if (productList[likePosition].isLiked) {
				productList[likePosition].isLiked = false
                productList[likePosition].itemheartCount--
			}
		}
		adapter.notifyItemChanged(likePosition)
	}
}
  • DetailActivity에서 전달된 likePosition과 isLiked를 이용하여 true라면 좋아요 카운트를 1증가시킨다.
  • notifyItemChanged()는 recyclerview를 업데이트 하는 역할을 한다.

DetailActivity

val money = getItem.itemPrice
val format = DecimalFormat("#,###")
  • 데이터에서 itemPrice를 받아 DecimalFormat("#,###")를 이용해 1000단위마다 콤마(,)를 찍는다.
private fun goToMain() {
	val likePosition = intent.getIntExtra("likePosition", 0)
	val intent = Intent(this, MainActivity::class.java).apply {
		putExtra("likePosition", likePosition)
		putExtra("isLiked", isLiked)
	}
	setResult(RESULT_OK, intent)
	if (!isFinishing) finish()
    }
  • MainActivity에 대한 intent를 생성해 putExtra로 데이터를 담고 setResult에 reaultCode와 intent를 인수로 준다.
  • finish()로 SomeActivity를 종료하면 MainActivity로 돌아가서 resultLauncher함수에 작성한 내용들이 실행된다.

Product

object Product {}
  • 오브젝트를 생성해 따로 데이터 저장공간을 만들어뒀다.
@MainActivity
val productList = Product.productData()
val adapter = Adapter(productList)
  • MainActivity의 위 코드로 오브젝트의 데이터들을 불러오고 어댑터에 연결해준다.
post-custom-banner

0개의 댓글