안드로이드 리스트뷰 다중 선택 처리하기. (Android ListView Multi Choice)

2016. 4. 25. 13:19


1. ListView 아이템 선택 기능

일반적으로 ListView의 아이템은 텍스트 또는 이미지 등으로 구성된 내용을 표시할 때 많이 사용하지만, 아이템 추가, 수정, 삭제 기능을 통해 데이터의 내용이나 개수를 조절하는 경우에도 자주 사용됩니다. 이 때 ListView의 어떤 아이템이 수정 또는 삭제될 것인지 판단하기 위한 방법이 필요한데, 이를 위해 ListView 아이템에는 "선택 기능"이 사용됩니다.


ListView의 아이템이 "선택 기능"을 가지도록 만들기 위해서는 ListView의 "choiceMode" 속성을 사용합니다. "choiceMode" 속성에 어떤 값을 지정하느냐에 따라 단일 선택 또는 다중 선택 모드가 결정되는데, 단일 선택 모드를 사용할 때는 "singleChoice", 다중 선택 모드를 사용할 때는 "multipleChoice" 값을 지정합니다.
("singleChoice"에 대한 간단한 예제는 [안드로이드 리스트뷰 아이템 추가,수정,삭제] 내용을 참고하세요.)


단일 선택 모드와 다중 선택 모드에서의 구현 작업은 크게 차이나지 않습니다. 하나의 선택 아이템을 다루는지, 여러 선택 아이템을 루프를 돌며 처리하는지 정도의 차이가 있을 뿐입니다.


오히려 구현 과정에서의 복잡함은 선택 기능을 지원하는 Custom ListView를 만드는 데 있을 수 있습니다. 이와 관련된 내용은 별도의 주제로 다루겠습니다.


그럼 지금부터 다중 선택을 지원하는 ListView를 만드는 방법에 대해 알아보겠습니다.


2. 기본적인 아이템 다중 선택 기능 구현 방법

ListView의 "choiceMode" 속성을 사용한 아이템 다중 선택 기능 구현 방법을 예제를 통해 알아보도록 하겠습니다.


예제에서는 다중 선택이 가능한 ListView 및 아이템 추가를 위한 Button과 선택된 아이템을 삭제하기 위한 Button, 그리고 전체 아이템을 선택하기 위한 Button으로 구성됩니다.



안드로이드 다중 선택 리스트뷰 아이템 레이아웃


2.1 ListView 및 Button 추가.

늘 그렇듯이 ListView와 Button들이 추가된 Layout 리소스 XML을 작성합니다. ListView는 다중 선택이 가능해야 하므로, "choiceMode" 속성에 "multipleChoice" 값을 지정합니다.

[STEP-1] "activity_main.xml" - MainActivity에 ListView와 Button 추가.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.madwin.listviewitemcontrolexample1.MainActivity"
    tools:showIn="@layout/activity_main"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listview1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:choiceMode="multipleChoice" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Add" />

        <Button
            android:id="@+id/delete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Delete" />

        <Button
            android:id="@+id/selectAll"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Select All" />

    </LinearLayout>

</LinearLayout>

2.2 ListView, ArrayList 및 Adapter 생성

MainActivity의 onCreate() 함수에서 ListView, ArrayList, Adapter를 생성합니다.

[STEP-2] "MainActivity.java" - onCreate() 함수에서 ListView, ArrayList, Adapter 생성.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ... 코드 계속

        // 빈 데이터 리스트 생성.
        final ArrayList<String> items = new ArrayList<String>() ;
        // ArrayAdapter 생성. 아이템 View를 선택(multiple choice)가능하도록 만듦.
        final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_multiple_choice, items) ;

        // listview 생성 및 adapter 지정.
        final ListView listview = (ListView) findViewById(R.id.listview1) ;
        listview.setAdapter(adapter) ;

        // 코드 계속 ...
    }
}

위의 코드에서 Adatper에 전달되는 Layout으로 "android.R.layout.simple_list_item_multiple_choice"가 사용된 것을 주목하세요. 앞에서 잠깐 언급했듯이 본 예제에서는 ListView 아이템 Layout을 만들지 않습니다. 대신 안드로이드 SDK에서 제공되는 Layout을 사용하는거죠. 즉, "android.R.layout.simple_list_item_multiple_choice"가 안드로이드 SDK에서 기본적으로 제공되는 Layout입니다.


"android.R.layout.simple_list_item_multiple_choice"는 TextView와 CheckBox 위젯이 배치되어 있는 Layout입니다. [안드로이드 리스트뷰 아이템 추가,수정,삭제]에서 단일 선택 모드 예제를 작성하면서 사용했던 "android.R.layout.simple_list_item_single_choice"는 TextView와 RadioButton으로 만들어져 있었죠. 둘 다 "선택" 기능을 위해 만들어졌지만 다중 선택 가능 여부에 따라 CheckBox를 사용하는지, RadioButton을 사용하는지가 차이가 나는 것입니다.


2.3 "Add" Button 클릭 시 아이템 추가.

예제에 따라 "Add" Button을 클릭하면, 새로운 아이템을 추가하도록 구현합니다.

[STEP-3] "MainActivity.java" - "Add" Button에 대한 핸들러 작성.
        // add button에 대한 이벤트 처리.
        Button addButton = (Button)findViewById(R.id.add) ;
        addButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                int count;
                count = adapter.getCount();

                // 아이템 추가.
                items.add("LIST" + Integer.toString(count + 1));

                // listview 갱신
                adapter.notifyDataSetChanged();
            }
        }) ;

2.4 "Delete" Button 클릭 시 선택 아이템 삭제.

"Delete" Button을 누르면 아이템을 삭제하도록 구현합니다. 단일 선택 모드를 사용한 [안드로이드 리스트뷰 아이템 추가,수정,삭제]에서 아이템을 삭제할 때, ListView로부터 선택(Checked)된 아이템 위치를 getCheckedItemPosition() 함수를 사용하여 가져왔는데, 다중 선택 모드에서는 조금 다른 방법을 사용합니다.

[STEP-4] "MainActivity.java" - "Delete" Button 클릭 시 선택(Checked)된 아이템 삭제.
        // delete button에 대한 이벤트 처리.
        Button deleteButton = (Button)findViewById(R.id.delete) ;
        deleteButton.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                SparseBooleanArray checkedItems = listview.getCheckedItemPositions();
                int count = adapter.getCount() ;

                for (int i = count-1; i >= 0; i--) {
                    if (checkedItems.get(i)) {
                        items.remove(i) ;
                    }
                }

                // 모든 선택 상태 초기화.
                listview.clearChoices() ;

                adapter.notifyDataSetChanged();
            }
        }) ;

먼저 현재 선택된 아이템들을 가져오기 위해 getCheckedItemPositions() 함수를 사용합니다. 단일 선택일 때 사용했던 getCheckedItemPosition() 함수 이름에 "s"가 더해져있죠. 물론 함수의 리턴 타입도 다릅니다.


getCheckedItemPositions()에서 리턴되는 SparseBooleanArray는 정수 값들을 boolean 값들로 매핑시키는 기능을 하는 클래스입니다. 여기서 정수 값은 ListView 아이템의 위치(position)로 사용하고, boolean 값은 선택(Checked) 여부로 사용됩니다.
SparseBooleanArray의 get() 함수를 사용하면 인자로 입력되는 position의 상태가 Checked인지 확인할 수 있습니다.


그리고 선택된 아이템을 remove() 함수를 사용하여 삭제한 다음에 clearChoices() 함수를 호출한 것을 주의하세요. 보통 Adapter로 입력된 데이터를 삭제하고 notifyDataSetChanged()함수를 호출하면 선택(Checked) 상태까지 초기화될 것이라 생각되어질 수 있습니다. 하지만 그렇지 않죠. (위의 코드에서 "listview.clearChoices() ;" 문장을 주석처리하면 그 결과를 확인할 수 있습니다.)


아이템의 데이터와 화면에 표시되는 View를 연결해주는 역할을 해주는 것이 분명 Adapter의 역할이긴 하지만, 선택(Checked) 상태는 ListView 자체가 유지하고 있습니다. 그러므로 아이템을 삭제하고 Adapter의 notifyDataSetChanged()를 호출한다고 해도 유효한 position의 선택(Checked) 상태를 그대로 유지하고 있는 것입니다.


마지막으로 위의 코드에서 아이템을 삭제하기 위해 for 루프를 (count-1) 부터 감소시켜가며 실행한 것을 주의하세요. remove() 함수를 호출하면 아이템이 삭제되면서 삭제 위치의 뒤에 있던 아이템들의 position이 앞으로 이동하게 되고 아이템의 갯수가 줄어듭니다. 그러면 당연히 의도하지 않은 아이템이 삭제되거나, for 루프가 줄어든 아이템 갯수보다 많이 실행되는 문제가 발생합니다. 리스트 자료 구조에서 데이터를 삭제할 땐 "마지막 아이템부터" 루프를 실행해야 한다는 것을 꼭 명심하시기 바랍니다.

2.5 "Select All" Button 클릭 시 모든 아이템 선택.

"Select All" Button을 클릭하면 ListView의 모든 아이템을 선택합니다. 아이템 선택을 위해 호출하는 함수는 ListView의 setItemChecked() 함수입니다. setItemChecked() 함수는 입력받은 position에 대해서만 선택 여부를 설정하므로, 현재 Adapter에 지정된 모든 아이템에 대해 루프를 돌며 호출해줘야 합니다.

[STEP-5] "MainActivity.java" - "Select All" Button 클릭 시 모든 아이템 선택.
    // selectAll button에 대한 이벤트 처리.
    Button selectAllButton = (Button)findViewById(R.id.selectAll) ;
    selectAllButton.setOnClickListener(new Button.OnClickListener() {
        public void onClick(View v) {
            int count = 0 ;
            count = adapter.getCount() ;

            for (int i=0; i<count; i++) {
                listview.setItemChecked(i, true) ;
            }
        }
    }) ;

2.5 예제 실행 화면.

예제 코드를 모두 작성하고 실행하면 아래와 같은 실행 화면을 확인할 수 있습니다.


안드로이드 다중 선택 리스트뷰 예제 실행 화면


각 버튼 클릭 시 동작은 다음과 같습니다.


3. 참고.

.END.


ANDROID 프로그래밍/LISTVIEW , , , , , , ,

  1. 이전 댓글 더보기
  2. Blog Icon
    모바일과탑

    올려주신 글 잘 보고있어요. 감사합니다!! 도움 진짜 많이 된거 같아요
    DB에서 리스트를 불러와 리스트뷰를 만드는거나 웹사이트에서 파싱을 해서 리스트뷰를 구성하는것도 추가되면 좋을 것 같아요

  3. 네~ 적어주신 "DB나 웹사이트 파싱해서 리스트뷰 적용" 같은 내용 또한 기회가 된다면 정리할 예정입니다. (제 주변 사람의 요청 또한 있었던 관계로.. ^^)
    하지만 당분간은 리스트뷰 자체에 대한 활용 방법을 조금 더 진행할 예정이라 시간이 걸릴 수도 있겠네요.
    코멘트로 의견주셔서 감사합니다. ^^

  4. 안드로이드 개발자 페이지를 보고 다른 참고 글들을 보아도 ListView 에서 다중선택은 되는데 다중삭제 구현이 만만하지는 않은 듯하다.
    필자가 초보라서 그럴 수도 있지만 다른 분들도 어려워하는 것 같이 보인다.

    아래 글은 베껴넣고 돌리면 바로 결과를 확인할 수 있다.
    다만, 입력하는 에디트가 없고 [추가] 버튼을 누르면 아이템이 자동으로 추가되게 만든 점을 참고하면 된다.

    원작자의 글을 읽으면서 너무나 깔끔하고 적확하며 군더더기 하나 없어 보이는 데 감탄했다.
    많은 참고글들은 가져와서 다듬기 일상이지만, 이 글은 손댈 곳도 없어보인다.

    ListView 를 처음 접하는 분은 원작자의 다른 글
    http://recipes4dev.tistory.com/42
    페이지를 먼저 보면 도움이 될 것이다.

    원작자에게 진심으로 감사하면서, 공유하려고 베껴서 올린다.

    위 http://blog.daum.net/andro_java/178 페이지에 올린 소개글입니다.
    감사합니다.

  5. 안녕하세요.
    먼저, 올린 글의 내용에 비해 과분한 평을 남겨주셔서 몸둘바를 모르겠네요. 최대한 이해되기 쉽게 쓰려고 노력하고 있지만, 뜻한대로 작성이 잘 되지 않아 고민이 많던 차에, 김병희님 코멘트를 보니 힘이 나네요.

    그런데 한가지 부탁드릴 것이 있습니다. 근 시일 내에 공지 글을 올릴 예정이지만, 미리 조금 언급드리자면..
    일단, 제 블로그에 적은 글들은 링크 연결 외의 내용 복사는 허용하지 않습니다. 제 나름의 목적을 가지고, 많은 시간과 노력을 들여 작성한 글이다보니, 많이 아끼게 되네요.

    대신 특별한 사정이 생기지 않는 한 모든 내용은 지우지 않고, 계속 유지할 예정이니, 블로그 글 유지에 대해서는 큰 걱정 안하셔도 될 것 같습니다.

    이미 복사해가신 글은 따로 삭제 요청 드리지 않겠지만,
    만약 다른 글에 대한 참조가 필요하시다면, 링크로만 연결 부탁드립니다.
    죄송하고, 또, 감사합니다.

  6. 안드로이드 리스트뷰에 여러 종류의 아이템뷰 사용하기.
    안드로이드 리스트뷰에 Header와 Footer 사용하기.
    등 ListView 관련 글들을 대충 다 훑어보았습니다.

    Custom ListView 를 구현하지 않고, 다만 아이템 일부 내용만 보여주는 간단한 방법은 없을까요?

    아이템 데이터 = 폴더/파일 : 내용1 내용2 내용3
    표시 아이템 뷰 = 파일 : 내용1

    이런 식으로 윗줄의 데이터 일부 내용만 아랫줄처럼 보여주는 방법 말입니다.
    가능할 것 같은데 머리가 돌아가지 않아서 부탁 드립니다.

  7. Custom ListView를 구현한다는 것은..
    안드로이드 SDK 내에 "내가 표현하고자 하는 ListView 아이템 UI"가 없기 때문입니다.
    이미 ListView와 관련된 글들을 읽어보셨으니, "android.R.layout.simple_list_item_1" 또는 "android.R.layout.simple_list_item_multiple_choice" 등에 대해서는 파악하고 계시리라 생각합니다.
    android.R.layout.XXX 등은 안드로이드 SDK 내에 포함되어 있는 아이템 UI 리소스들이죠.

    질문 글에 적어주신 내용에서, "표시 아이템 뷰 = 파일 : 내용1"를 출력할 아이템 View가 SDK 내에 정의된 것이 있다면 그것을 사용하시면 되고, 그게 아니라면 Custom ListView를 만드셔야 합니다.
    즉, 화면에 어떤 위젯들을 사용해서 출력하고자 하는가...가 먼저 정의가 된 다음, SDK 내에 있는가? 없다면 Custom ListView로 작성해야 한다는 것이죠.

    P.S
    만약 단순하게 문자열 텍스트로만 출력하고자 한다면 "http://recipes4dev.tistory.com/42"에서 설명한 내용을 토대로 작성하셔도 됩니다.

  8. Blog Icon
    황찬우

    진짜 덕분에 많이 알아갑니다!!
    그런데 싱글초이스에선 modify버튼이 잘 작동하는데 멀티초이스로 수정한 뒤로는 modify버튼이
    작동을 아예 안합니다. 코드를 어떻게 수정해야 하나요??

  9. singleChoice인 경우와 multipleChoice인 경우, 처리하는 과정이 다른 것은 확인하셨지요?
    즉, singleChoice인 경우는 선택된 아이템 한 개만 처리하면 되고,
    multipleChoice인 경우는 여러개의 아이템을 루프를 돌면서 처리해줘야 합니다.

    그러므로 choiceMode 값만 변경한다고 되는 것은 아니고,
    choiceMode 값에 따라 아이템을 처리하는 코드도 변경해줘야 합니다.

    말씀하신 multipleChoice인 경우에 아이템 수정 처리를 해주시려면,
    본문 내용 중에 [STEP-4]에 있는 "삭제" 과정을 조금 수정해주시면 됩니다.

    1. 현재 선택된 아이템 리스트를 구해온 다음,
    2. 선택 아이템 리스트 개수만큼 루프를 돌면서,
    3. 어댑터에 저장된 데이터의 값을 수정.
    4. 루프가 종료된 후, 어댑터의 notifyDataSetChanged() 함수 호출.

    이런 과정으로 코드를 작성하시면 될 것 같습니다.

    코드를 작성해보시고 궁금한 점이 또 있으시면 질문 올려주세요~

  10. Blog Icon
    노세환

    이 블로그를 보고 custom 리스트뷰를 구현했지만

    체크된 박스를 어떤식으로 인식해야되나요?

    adapter.additem() 이것으로는 아이템 추가가 안되더라구요...
    추가는 어떤식으로 해야될까요??

  11. "체크된 박스를 인식"한다는 것의 의미가 체크박스의 체크 여부를 어떻게 가져올 것인지를 말하는 것이지요?

    일단 아이템 자체를 체크 가능하도록 만드는 예제는 본문 글과...
    http://recipes4dev.tistory.com/48에서도 확인하실 수 있습니다.

    하지만 아이템 자체 체크 기능이 아니라 단순히 체크박스를 추가하고 그것의 체크 여부를 알아오기 위한 것이라면, 조금 다른 방법으로 처리해줘야 합니다.

    음.. 크게 두 가지 방법이 있는데요..
    체크 박스 눌려졌을 때 리스트 데이터의 값을 바로 변경시킨 다음, 필요한 곳에서 해당 값을 읽는 방법이 있구요.
    두 번째는 체크 박스 자체의 현재 상태를 읽어오는 것입니다. 이 때 position값과 리스트뷰의 getChildAt() 함수를 사용해서 아이템뷰 참조를 얻어올 수 있고, 그것을 통해 체크박스의 참조를 가지고 올 수 있죠. 하지만, 별로 추천하진 않구요.. 첫번째 방법이 나은 것 같아요.

    그리고 본문에서는 addItem() 함수가 없는데.. 어떤 글의 예제를 보신 건가요?
    일단 예제들의 실행 여부 및 출력 결과는 모두 확인하고 올린 거라, 절차대로 따라 하셨다면 문제 없이 실행될 겁니다.

    혹시 잘 안되시면 해당 글에서 질문 남겨주시면 다시 알려드릴게요. 질문에 적힌 에러 메시지 등이 자세할수록 도움 드리기가 더 용이할 것 같네요. ^^

    감사합니다.

  12. Blog Icon
    노세환

    음.. 크게 두 가지 방법이 있는데요..
    체크 박스 눌려졌을 때 리스트 데이터의 값을 바로 변경시킨 다음, 필요한 곳에서 해당 값을 읽는 방법이 있구요.
    라고 하셨는데요

    그값을 바로 변경한 후에 읽는방법이 무었일까요...

  13. 리스트 데이터의 값을 ArrayList 중 해당하는 아이템의 데이터에 저장하면, ArrayList로부터 아이템 데이터를 가져와서 사용할 수 있는거죠.

    ArrayList 데이터는 어댑터를 통해 접근할 수 있으니깐, 어댑터의 getItem() 함수를 사용하여 원하는 위치의 아이템 데이터를 얻어올 수 있습니다.

  14. 저 이 글과 맞지않는 질문인데 제가 이 글대로 코딩을해서 커스텀 리스트 뷰를 만들었습니다. 그렇게 해서 모든 동작이 잘 이루어지는데 제가 액티비티 두개를 만들어 용도가 다르지만 둘다 이 커스텀 뷰 코딩으로 만들었습니다. 그 두개를 서로 오갈때 뒤로가기 버튼을 누르고 다시 들어가니 내용이 초기화 되는데 왜 그러는건가요?

  15. 액티비티가 다시 로딩되는 과정을 거치게 되기 때문인데요. 화면 모드를 가로 또는 세로로 바꿨을 때 초기화되는 과정과 유사하게 생각하시면 될 듯 합니다.

    이를 위해 리스트뷰에 보여줄 데이터를 단순히 메모리 상에만 두기 보다는 별도의 공간에 저장한 다음에, 액티비티가 초기화되는 과정에서 리스트뷰로 로딩하면 됩니다. 파일이나 DB 등에 저장하면 좋겠죠.

    좀 더 자세하게 설명드리면 좋겠는데, 능력이 부족하네요.
    일단 "액티비티 생명주기" 등의 내용을 검색하시면 관련 내용이 정리된 사이트가 많이 있습니다. 참고하시면 도움되실 것 같습니다.

    저도 관련 내용 정리되는대로 글 올리도록 하겠습니다.

    감사합니다.

  16. 감사합니다

  17. 또 다른 질문 사항 있으시면 질문글 남겨주세요.
    감사합니다.

  18. Blog Icon
    N.SAFeel

    혹시 예제를 만든 파일이 있을까요?

  19. 예제들이 아주 간단해서, 프로젝트 파일을 추가적으로 올릴 필요는 없다고 판단했습니다.
    물론, 앞으로 더 복잡한 예제들이 작성되면 프로젝트를 압축 형태로든 블로그에 올리긴 하겠지만, 현재까지 작성된 예제들은 블로그에 올리지 않아도 충분히 이해 가능한 수준이라고 생각됩니다.

    그래도 몇몇 분들이 요청하신 내용이 있어서 고민 좀 해보겠습니다. (시간과 노력이 드는 일이라...)
    양해를 부탁드립니다.
    감사합니다.

  20. Blog Icon

    비밀댓글입니다

  21. "어댑터의 아이템을 불러온다"는 것의 의미가 아마 아이템을 추가하기 위해서 어댑터의 리스터에 어떻게 접근할 수 있는가 인 듯 한데요..

    올려주신 코드를 보면 커스텀 어댑터를 만드신 듯 한데...... 그렇다면 어댑터에서 리스트의 참조를 리턴하는 함수를 하나 만들면 될 것 같습니다.
    그리고 그 함수를 통해 데이터 리스트의 참조를 가져와서, 데이터를 추가하면 될 것 같네요.

    참고로 올려주신 코드에 보면, 에러가 난다고 한 부분에 "itmes"라고 되어 있는데... 오타가 아닌가요?

    음.. 어쨌든, 커스텀 어댑터 만드는 방법을 조금 더 숙지하시고 작업하시는 게 도움될 것 같네요.

    [안드로이드 커스텀 리스트뷰 만드는 방법. "http://recipes4dev.tistory.com/43"]을 통해 확인하실 수 있습니다.

    원하시는 답변이 되었는지 모르겠네요. 또 다른 질문 있으시면 질문글 남겨주세요.

    감사합니다.

  22. Blog Icon
    행인

    올려주신 글을 잘 보고 listview를 습득하고 있는데요. 삭제 하는 부분에서
    SparseBooleanArray로 배열을 만들어 true/false로 판단해서 삭제하는거 같은데

    SparseBooleanArray checkitem = listview.getCheckedItemPositions();
    int count = adapter.getCount();


    Log.d("test","ErrorCheck");

    if(count > 0) {
    for (int i = count - 1; i >= 0; i--) {
    Log.d("test", "count : "+count+" checkitem"+checkitem.get(i));

    if (checkitem.get(i)) {
    Log.d("test", "크기"+checkitem.size()+"값"+checkitem.get(i));
    adapter.deletItem(i);

    }

    현재 이렇게 코딩을 해놨는데 checkitem.get(i)에서 모든게 false로 나와서 삭제는 되지 않고 체크박스 초기화만 되는데 어떤게 문제인지 모르겠네요....

    알려주시면 감사하겠습니다.

    항상 감사합니다~~!

  23. 올려주신 코드를 보면, 딱히 이상이 있어보이진 않네요. 그렇다면 아래의 내용들을 확인해보시기 바랍니다.

    1. 리스트뷰의 choiceMode 속성 확인.
    리스트뷰를 추가할 때 choiceMode를 "multipleChoice"로 설정했는지 확인해보시기 바랍니다. 본문의 [STEP-1]의 XML 소스를 보시면 확인하실 수 있습니다.

    2. 커스텀 리스트뷰를 만든 경우.
    혹시 리스트뷰를 만들 때 커스텀리스트뷰로 작성하셨나요? 그리고 체크박스를 직접 정의하신 건지 확인해보세요. 만약 커스텀리스트뷰를 만드신 거라면 본문의 내용만으로는 부족하고, (선택 기능을 지원하는 커스텀 리스트뷰 만드는 방법, "recipes4dev.tistory.com/68")의 내용을 적용하셔야 합니다.

    위의 두 가지 내용을 확인해보시고, 그래도 잘 안되면 질문글 남겨주세요.

    감사합니다.

  24. Blog Icon
    행인

    말씀하신데로 커스텀 리스트뷰로 만들었구요. 홈페이지에 있는 내용을 참고해서 제작했습니다.
    1번조건 또한 제작할때 확인했던 내용이었습니다.
    모든게 false로 나와서 false체크를 하지않고 for문을 통해 모두 지우는 동작을 수행해봤는데 모두 지우기는 되더라구요...
    그거 외에는 문제될 내용이 없는건가요...? API에 있는 함수가 제대로 작동을 안할리도 없을꺼 같은데... 모가 문제가 되는건지 모르겠네요.

  25. "행인" 님께서 작성 하신 내용에는 별다른 문제가 없음을 확인했습니다. 대신 제가 올려드린 소스 내용에서 잘못된 부분이 있는 것을 확인하였습니다.

    (선택 기능을 지원하는 커스텀 리스트뷰 만드는 방법, "recipes4dev.tistory.com/68")의 내용을 확인하여 커스텀 리스트뷰를 만드셨다고 했으니, 리스트뷰 아이템에 들어가는 CheckBox에 "clickable" 속성을 "false"로 지정해보시기 바랍니다. "clickable" 속성을 "false"로 지정하지 않으면 CheckBox가 클릭 이벤트를 처리하고 리스트뷰로 전달하지 않는 문제가 있네요.

    수정된 내용은 (선택 기능을 지원하는 커스텀 리스트뷰 만드는 방법, "recipes4dev.tistory.com/68")의 [STEP-2] 소스에 반영해두었습니다.

    기능을 구현하는데 혼란을 드려 죄송합니다.
    적용해보신 다음, 잘 안되면 다시 질문 남겨주세요.

    감사합니다.

  26. 볼 게 많은데 setItemChecked 하나만 참고하고 갑니다.
    감사합니다.

  27. 네. 저도 감사합니다.

  28. Blog Icon
    행인

    checkBox에 clickable을 주니 잘 수행이 됩니다. 정말 감사합니다.
    제가 찾아보면서 문제점을 알려드렸으면 정말 좋았을텐데 그러지 못했네요...

    계속해서 진행하면서 안되는 부분들 많이 여쭤보겠습니다~

    정말 감사합니다.!!

  29. 글을 쓰고 정보를 제공하는 입장에서, 좀 더 꼼꼼하게 체크했어야 하는데 그러지 못해서 오히려 제가 죄송합니다.

    게다가 문제점까지 지적해 주셨으니 제가 더 감사하죠.

    블로그의 내용을 보시다가 의문점이 있으면 언제든지 글 남겨주세요.

    감사합니다.

  30. Blog Icon
    chiechie

    안녕하세요 리스트뷰와 체크리스트에 관해 글 정말 잘 읽었습니다. 도움이 정말 많이 되었어요.
    질문이 있습니다. 체크리스트를 체크했을때 안보였던 버튼이 보이게 할 수도 있을까요 ?
    삭제버튼을 숨겼다가 체크가되면 버튼이 나오게 하고 싶습니다.
    여러방법을 해봤지만, 되지 않아서 댓글 남깁니다.

  31. 질문하신 내용에 대한 구현은 충분히 가능합니다. 음, 크게 두 가지 방법으로 접근해볼 수 있는데요.

    먼저 리스트뷰 아이템이 눌려지면 리스트뷰의 아이템 뷰에 대한 참조를 직접 가져와서 버튼의 보이기 설정을 변경하는 방법이 있습니다. 접근 방법은 직관적이긴 한데, 이래 저래 고려해야 할 부분이 많아서 그리 추천드리고 싶진 않습니다.

    다음, 버튼이 보일 것인지 여부에 대한 변수를 리스트뷰 아이템 데이터에 전달하여, 어댑터의 getView() 함수에서 해당 변수에 따라 버튼을 보이거나 감추는 방법입니다. 이 때 버튼 이벤트는 버튼의 핸들러에서 직접 처리하지 않고, 리스트뷰의 부모(액티비티 정도가 되겠죠?) 리스너를 호출하도록 만들면 됩니다. 클릭 이벤트가 발생한 position과 함께 말이죠.

    그리고 나서 position에 해당하는 버튼 보이기 관련 변수 값을 바꿔준 다음, 어댑터의 notifyDataSetChanged() 함수를 호출해주면 될 것입니다.

    관련 내용은 "안드로이드 리스트뷰에 버튼 넣기(http://recipes4dev.tistory.com/45)"에서 참고해 보시기 바랍니다.

    음, 답글만으로 구현 방법이 잘 전달되었을지 모르겠네요.
    잘 이해 안되시거나, 또 다른 문제점이나 궁금한 점 있으시면 다시 글 남겨주세요.

    감사합니다.

  32. Blog Icon
    choice

    다중선택 리스트뷰를 생성하였는데 체크박스를 각각 컨트롤할수있나요??
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    if(position==0) xxxxxxx
    if(position==1) xxxxxxx

    }

    이렇게 사용하면 체크, 해제 상태를 알수가 없습니다

    클릭할때 체크 or 해제상태를 알수있는방법이 있을까요??

  33. 리스트뷰 아이템의 체크 여부를 리스트뷰가 가지고 있긴 하지만, 그 체크 정보를 리스트뷰로 전달하는 역할은 리스트뷰 아이템의 루트 레이아웃이 수행합니다. 대신, 리스트뷰 아이템의 루트 레이아웃은 Checkable 인터페이스를 implements해야 하구요. 관련 내용은 "선택 기능을 지원하는 커스터 리스트뷰 만드는 방법 (http://recipes4dev.tistory.com/68)"에서 확인할 수 있습니다.

    자, 그럼 리스트뷰 아이템의 루트 레이아웃은 어디서 참조할 수 있을까요?

    선택 기능이 구현된(Checkable 인터페이스가 implements된) 리스트뷰에서는 onItemClick() 함수의 두 번째 파라미터인 view가 바로 리스트뷰 아이템의 루트 레이아웃을 가리킵니다. 그러므로 view를 사용하면 아이템 선택 여부를 알 수 있습니다.

    그런데 view는 View 클래스 변수입니다. 체크 여부와 관계된 함수는 View에 정의되지 않았기 때문에 view를 그대로 사용할 수 없습니다. 하지만 위에서 리스트뷰 루트 아이템이 Checkable 인터페이스를 implements 하고 있다고 언급했었죠.

    정리하자면, view는 Checkable 인터페이스를 implements하고 있는 리스트뷰 아이템의 루트 레이아웃입니다. 그래서 Checkable 인터페이스의 함수 isChecked() 를 통해 아이템의 선택 여부를 확인할 수 있습니다.

    public void onItemClick(AdapterView parent, View view, int position, long id) {
    System.out.println("checked : " + ((Checkable)view).isChecked()) ;
    }

    설명이 좀 길었네요.
    도움 되셨길 바랍니다.

    감사합니다.

  34. Blog Icon
    감사합니다.

    안녕하세요 검색,다중선택 삭제까지 모두 잘됩니다. 정말 감사합니다.

  35. 정리한 내용이 도움이 된 것 같아서 조금 뿌듯하네요.
    다른 내용들도 도움이 되셨으면 좋겠습니다.

    감사합니다.

  36. Blog Icon
    visible은 안되나요

    checkbox를 gone해놓고 oncreate에서 버튼 누르면 visible로 변환 시켜주면서 사용하고 싶은데
    inflater로 가져와도 visible상태가 되지 않는데 원래 이런가요???

  37. 질문하신 내용이, 원래 그런 것은 아니라고 생각됩니다.
    아마, inflater로 가지고 왔을 때의 초기 상태와 setVisivility() 함수를 호출한 후의 상태를 조금 헷갈리신 게 아닌가 생각이 드네요.

    일단, 작성하신 코드 내용을 확인하면 문제점을 파악하기 더 용이할 듯 합니다. 조금 번거로우시더라도 관련 코드를 같이 올려주시면 도움 드리기가 수월할 듯 하네요.

  38. Blog Icon
    궁금합니다...ㅎ

    안녕하세요! 초보 안드로이드 개발자입니다...
    다름 아니라 산택된 아이템 위치의 배경색을 바꿀려고 하고 있는데 아래 방식으로는 화면 전체의 색이 바뀌게 되네요.. 어떻게 해야 선택된 아이템 배경색만 바꿀수 있을까요..?
    colorButton.setOnClickListener(new Button.OnClickListener(){
    public void onClick(View v){
    SparseBooleanArray checkedItems = listview.getCheckedItemPositions();
    int count = adapter.getCount() ;

    for (int i = count-1; i >= 0; i--) {
    if (checkedItems.get(i)) {
    Log.d("로그 check", i+"");
    listview.setBackgroundColor(Color.BLUE);
    }
    }
    adapter.notifyDataSetChanged();
    }
    });

  39. listview.setBackgroundColor() 메서드를 호출하면, 말그대로 리스트뷰의 배경 색을 모두 변경하게 됩니다. 이런 경우, 전체 배경색이 아닌 아이템 별 배경 색상을 바꿔줘야 하는데요.

    일단 리스트뷰 아이템을 직접 구성하시고, checked 상태일 때의 배경색을 직접 지정해 주셔야 합니다.

    "선택 기능을 지원하는 커스텀 리스트뷰 만드는 방법(https://recipes4dev.tistory.com/68)" 글을 참고하시면 도움될 듯 한데요,

    위 링크 글에서 CheckableLinearLayout의 setChecked() 메서드에서 this의 setBackgroundColor()를 호출하면, 원하시는 결과 얻으실거라 생각이 드네요.

    시도해보시고, 잘 안되면 다시 질문글 남겨주세요.

    감사합니다.

  40. Blog Icon
    suu

    btn2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
    SparseBooleanArray checkedItems = listview.getCheckedItemPositions();
    int count = adapter.getCount();
    for(int i=count-1;i>=0;i--)
    {
    if(checkedItems.get(i))
    {

    adapter.delItem(i);
    }
    }
    listview.clearChoices();
    adapter.notifyDataSetChanged();
    }
    });

    CustomAdapter의 메소드 부분

    public void delItem(int index)
    {
    Log.i("CustomAdapter", "delItem");
    listviewItems.remove(index);
    }

    이런식으로 구현했습니다만ㅠㅠ 다중선택이 잘 되는 줄 알았더니 마지막것만 선택해서 삭제할 경우 삭제가 안되더군요ㅠㅠ 왜그런지 알수 있을까요

  41. 음... 언뜻 코드만 봐서는 별문제 없어 보이는데요. 그래도 안된다면, 안되는 이유가 있겠지요. ^^

    일단, 마지막 아이템만 선택한 다음 아래 과정에서 값들이 정상적으로 들어 있는지 확인해 보세요.

    먼저, 질문글의 코드에서,
    for 루프를 돌기 전에 checkedItems의 크기를 한번 확인해 보세요.
    SparseBooleanArray 클래서의 size() 메서드를 호출하면 됩니다.

    그리고 for 루프 내에서, if (checkedItems.get(i)) 조건이 true가 되는지 확인해 보세요.

    그리고 for 루프가 종료된 다음, 리스트 아이템 갯수를 출력해 보시기 바랍니다.

    그래도 원인이 안 찾아지면, 다시 질문글 남겨주세요.

    감사합니다.