recyclerview adpater onclick

조회수 2128회

리사이클러뷰에 레이아웃이 2개가 있는데 한개는 Visibility.Gone을 해놓고 보여진 레이아웃을 클릭하면 Gone인 레이아웃이 Visibility.Visible이 되게 하려고 합니다. 어댑터에서 레이아웃을 클릭했을 때 다른 레이아웃이 보이게 코딩을 했는데 클릭하면 잠깐 보였다가 다시 사라지네요 ㅜㅜ 왜 그럴까요

        boolean istrue = true;
        holder.llm2.setVisibility(View.GONE);
        holder.llm.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(istrue == true) {
                    new SubAsyncTask(position).execute("my url");
                    holder.llm2.setVisibility(View.VISIBLE);
                    istrue = false;
                } else if(istrue == false) {
                    new SubAsyncTask(position).execute("my url");
                    holder.llm2.setVisibility(View.INVISIBLE);
                    istrue = true;
                }
            }
        });
    }

2 답변

  • 좋아요

    1

    싫어요
    채택 취소하기

    리사이클러뷰는 아이템뷰를 재사용하기 때문에 View의 Visibility를 컨트롤 하고 싶다면 해당 정보를 별도의 모델에 저장하고, 모델로부터 정보를 가져와서 Visibility를 설정해야 됩니다.

    예를 들어 아이템뷰에 텍스트뷰가 있다고 가정을 하고 버튼을 클릭했을 때, 텍스트를 변경했다고 해봅시다. 이 때 리사이클러뷰를 스크롤을 하게되면 뷰가 재사용되면서 의도한 화면이 나오지 않을 것 입니다. 왜냐하면 텍스트가 단지 뷰의 속성만 변경했기 때문이고, 이 뷰는 리사이클러뷰에 의해 재사용되기 때문입니다.

    뷰에 표시할 정보를 Adapter 각각의 아이템에 담아두는 것처럼 Visibility 속성도 별도로 저장 후 onBindViewHolder() 함수에서 값을 설정하세요.

    • (•́ ✖ •̀)
      알 수 없는 사용자
    • Visibility 속성을 별도로 저장하라는 게 무슨 말인가요? 리사이클러뷰 아이템처럼 따로 클래스에 저장시키라는 건가요? kyudongPark 2016.9.21 16:09
    • 리사이클러뷰 각각 아이템에 해당하는 모델이 있을텐데요. 그 모델에 boolean 변수를 하나 추가해서 Visibility를 제어하면 될 것 같습니다. 알 수 없는 사용자 2016.9.21 19:28
    • boolean visibility; 를 변수로 추가해서 어댑터에서 레이아웃을 클릭했을 때 나오고 다시 클릭햇을 때 사라지고 하라는 말씀인가요? kyudongPark 2016.9.22 10:17
    • 모델에 boolean visibility; 변수를 하나 추가하고 onBindViewHolder에서 if(item.visibility == true)이면 레이아웃을 클릭했을 때 다른 레이아웃이 나타나게 되고 item.visibility = false로 하고 if(item.visibility == false)이면 클릭했을 때 레이아웃이 Gone이 되게 했는데 화면이 갱신됬을 때 나타났던 레이아웃이 마음대로 변경되네요 ㅜ kyudongPark 2016.9.22 10:56
    • 네 맞습니다. 알 수 없는 사용자 2016.9.22 10:57
    • 리사이클러뷰를 스크롤 하면 화면이 나타나있던 레이아웃이 마음대로 사라지고 생기고 이러네요 ㅜ 이건 어떡하죠 kyudongPark 2016.9.22 11:03
    • onBincViewHolder 함수내에서 visibility 변수 값을 보고 setVisibility() 설정을 하셨나요? 클릭 리스너는 클릭 시에 대한 처리이고, 별개로 뷰의 상태를 setVisibility()로 설정하셔야 합니다. 알 수 없는 사용자 2016.9.22 11:51
    • 클릭리스너를 하고 onClick에서 if(item.visibility) { holder.레이아웃.setVisibility(View.Visible); item.visibility = false; 이런식으로 해서 나타났다 사라졌다는 하는데 스크롤을 해서 밑으로 내려갔다가 다시 올라오면 갑자기 레이아웃이 사라진다거나 클릭하지 않았던 뷰의 레이아웃이 나타난다거나 그러더라고요 ㅜ kyudongPark 2016.9.22 12:41
  • 댓글에서는 코드 블럭을 사용할 수가 없어서 추가로 답변 작성했습니다.

    스크롤 시 레이아웃이 사라지거나 클릭하지 않았던 뷰가 나타나는 현상은 뷰가 재사용되기 때문입니다. 즉, 1번 인덱스의 뷰가 스크롤 시 10번 인덱스에서 재사용될 수 있다는 이야기이고요. 이 때 1번이 Gone 상태였다면 10번의 뷰도 Gone 상태가 되게 됩니다. (실제 10번째 모델의 상태는 Gone 상태가 아니더라도)

    따라서 다음 코드와 같이 모델의 visibility 값에 따라 setVisibility()를 설정해야지만 기대한 것처럼 동작하게 됩니다.

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
         ...
         holder.view.setVisibility(item.visibility ? View.Visible : View.Gone);
         ...
    }
    
    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 진짜 감사합니다! 해결되었습니다 이건!! kyudongPark 2016.9.22 14:08
    • 그러면 클릭을 했을 때 나타나는 레이아웃에 통신을 해서 값들을 뿌려주려고 하는데 AsyncTask를 bindViewHolder에서 해야 하나요 아니면 Main에서 해야 하나요? kyudongPark 2016.9.22 14:24
    • 지금 통신을 해서 리사이클러뷰에 뿌려주고 리사이클러뷰를 클릭하면 리사이클러뷰 속의 레이아웃이 Visible하게 되면서 다른 통신을 해서 뿌려줘야 하는데, 메인에서 통신을 하고 위에 답변처럼 클릭했을 때 Visibility를 관리하는 것까지는 했는데 다른 통신을 어떻게 해야 하는지를 모르겠어요 ㅜ kyudongPark 2016.9.22 15:41
    • 말씀하신 통신이라는 것이 뭘 이야기하는 것인지 잘 모르겠습니다. 알 수 없는 사용자 2016.9.23 00:51
    • AsyncTask입니다. 서버에서 url json 파싱을 해오는 것 입니다. 리사이클러뷰 하나를 클릭했을 때 json파싱을 통해서 얻은 데이터를 나타나는 레이아웃에 뿌려줘야 되는데 현재 Adapter의 OnBindViewHolder에서 클릭 리스너를 설정했는데 어댑터에서 바로 asynctask를 사용할 수 있나요? kyudongPark 2016.9.23 09:38
    • 어댑터에서 AsyncTask를 사용하는 것은 문제 없습니다. 다만 어댑터의 책임이 뷰를 생성하고, 뷰를 교체하는 것이라고 볼 때, 이곳에서 네트워크 통신까지 하는 것은 책임의 범위를 벗어나는 것일 수 있습니다. 설계적인 관점에서 너무 많은 책임을 어댑터가 가지는 것이 아닌가 대한 의문은 가질 수 있겠습니다만 이 부분은 나중에 고민해도 될 것 같습니다. 알 수 없는 사용자 2016.9.23 11:51

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)