마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

코틀린 리사이클러뷰 스크롤 이벤트 종료 후 어댑터쪽 텍스트뷰 접근 방법 문의 드립니다.

0 추천

안녕하세요 안드로이드 앱 제작 관련 독학 중 질문 드릴내용이 있어 드리니 답변 해주시면 감사하겠습니다.

현재 리사이클러뷰 공부 중 화면에 7개의 숫자를 보여주고, 스크롤시 화면에 보이는 아이템의 중간값에 텍스트를 진하게 하고 싶습니다. 지금 아래 코드는 화면에 7개의 텍스트뷰 나오면서, 스크롤 완료시 제일 왼쪽 아이템 기준으로 맞추는것까지 구현 하였습니다.

아직 배운지 얼마안되어 찾아봐도 정확한 내용을 못찾게 되어 여기에 올리게 되었습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

-> MainActivity 코드 입니다.

class MainActivity : AppCompatActivity() {

    val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        val list = setData()
        val adapter = NumberAdapter()
        adapter.items = list

        binding.recyclerView.addOnScrollListener(object :RecyclerView.OnScrollListener(){
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)

                var itemsNo = (recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
                binding.recyclerView.smoothScrollToPosition(itemsNo)
                binding.text.setText("나이: ${itemsNo+4}")
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
            }
        })

        binding.recyclerView.adapter = adapter

        binding.recyclerView.layoutManager = LinearLayoutManager(this).also { it.orientation = LinearLayoutManager.HORIZONTAL }

    }

    fun setData():MutableList<org.seokhwan.myrecyclerviewtest5.Number>{
        val data = mutableListOf<org.seokhwan.myrecyclerviewtest5.Number>()
        for (no in 1..100){
            var dataNo = Number("$no")
            data.add(dataNo)
        }
        return data
    }

}

 

->NumberAdapter 입니다.

class NumberAdapter:RecyclerView.Adapter<Holder>() {
    var items = mutableListOf<Number>()
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
        val binding = ItemNumberBinding.inflate(LayoutInflater.from(parent.context),parent,false)
        return Holder(binding)
    }

    override fun onBindViewHolder(holder: Holder, position: Int) {
        val num = items.get(position)
        holder.setNumber(num)

    }

    override fun getItemCount(): Int {
        return items.size
    }
}

class Holder(val binding: ItemNumberBinding):RecyclerView.ViewHolder(binding.root){
    fun setNumber(num:Number){
        binding.numberText.text = num.num
    }
}

 

=> 화면 구성은 

메인액티비티 : 텍스트뷰 + 리사이클러뷰 / 어댑터 : 텍스트뷰 끝입니다.

Sky_chobo (150 포인트) 님이 2021년 7월 13일 질문

1개의 답변

+1 추천

뷰의 스타일을 변경하더라도 데이터를 중심으로 처리하시는 게 좋습니다. 즉 어댑터에 제공되는 데이터가 style을 변경하여야 하는지에 대한 정보를 가지고 있는 것이 유연한 구조입니다.

아래는 머릿속에서 그려지는 대로 코드를 적어보았습니다. 바로 적는 거라 정확하지 고칠 부분들이 있습니다. 변수명, 함수명들은 가독성을 위해 좀 수정했습니다.

data class MyNumber(val data: String, val styled: Boolean = false)

class MainActivity : AppCompatActivity() {
 
    private val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
    private var listItems = listOf<MyNumber>()
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        listItems = getMyNumbers()
  
        binding.recyclerView.apply {
            val myNumberAdapter = MyNumberAdapter(myNumbers)

            addOnScrollListener(object :RecyclerView.OnScrollListener(){
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    super.onScrollStateChanged(recyclerView, newState)
 
                    val positionToStyle = (recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
                    binding.recyclerView.smoothScrollToPosition(positionToStyle)
                    binding.text.setText("나이: ${positionToStyle+4}")
                    listItems = listItems.applyStyleWhen(position = positionToStyle)
                    myNumberAdapter.setItems(listItems)
                }
 
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    super.onScrolled(recyclerView, dx, dy)
                }
            })
 
            adapter = myNumberAdapter
            layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL)
        }
    }
 
    private fun getMyNumbers() : List<MyNumber>{
        return (1..0).map { dataNo ->
             MyNumber("$dataNo")
        }
    }

   private fun List<MyNumbers>.applyStyleWhen(position: Int):  {
        return this.mapIndexed { index: Int, item: MyNumber ->
           item.copy(styled = index == position)
        }
   }
}

 

위에 코드에서 Adpter에 들어가는 데이터 클래스인 MyNumber 클래스에 styled를 속성을 하나 추가했습니다. 가운데 보여지는 아이템을 styled = true 만들어서 Adapter에 전달할 겁니다. 그러면 ViewHolder 쪽에서 이 프로퍼티를 보고 원하는 대로 뷰를 변경시켜주시면 되겠죠. 추가적인 정보가 더 필요하다면 MyNumber에 추가하시면 됩니다.

그리고 Adapter에 필요한 데이터를 가져오고 변경하는 이런 일은 별도의 클래스가 담당하는 것이 좋습니다. 이런 부분 복잡해 지기 때문에 코드에 반영하지 않았습니다.

 

추가로 ItemDecoration 이라는 것이 있습니다. 이걸 이용하면 님이 원하는 걸 좀 더 쉽게 만들 수도 있겠다 싶은 생각이 드는데, 제가 이 클래스는 아주 잘 사용하는 편이 아니라서 찾아보시고 한번 시도해 보세요. 이게 된다면 스크롤할 때 뷰의 스타일을 바꿔야하는  앞의 방법보다 더 나은 방법처럼 보입니다.

spark (225,780 포인트) 님이 2021년 7월 13일 답변
spark님이 2021년 7월 13일 수정
진심으로 감사드립니다.
덕분에 해결방법을 이해하게 되었습니다.
데이터 클래스에 속성을 하나 추가해서 사용하는 방식은 생각도 못했었고요,,
덕분에 실마리를 찾은것 같습니다.
추가로 말씀해주신 itemDecoration 부분도 찾아보고 사용할 부분이 있으면 하도록 하겠습니다.
...