Android의 항목에 대한 사용자 지정 ListView 클릭 문제


110

그래서 사용자 지정 ListView 개체가 있습니다. 목록 항목에는 두 개의 텍스트보기가 서로 쌓여 있고 실제로 무언가를 할 때까지 숨겨져있는 가로 진행률 표시 줄이 있습니다. 맨 오른쪽에는 사용자가 데이터베이스에 업데이트를 다운로드해야 할 때만 표시하려는 확인란이 있습니다. 가시성을 Visibility.GONE으로 설정하여 확인란을 비활성화하면 목록 항목을 클릭 할 수 있습니다. 체크 박스가 보이면 체크 박스를 제외하고 목록에서 아무 것도 클릭 할 수 없습니다. 몇 가지 검색을 해 보았지만 현재 상황과 관련된 것을 찾지 못했습니다. 이 질문을 찾았습니다하지만 내부적으로 데이터베이스 목록을 포함하기 위해 ArrayLists를 사용하고 있기 때문에 재정의 된 ArrayAdapter를 사용하고 있습니다. LinearLayout보기를 가져와 Tom처럼 onClickListener를 추가하면 되나요? 잘 모르겠습니다.

다음은 목록보기 행 레이아웃 XML입니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dip"
        android:layout_weight="1"
        android:layout_height="fill_parent">
        <TextView
            android:id="@+id/UpdateNameText"
            android:layout_width="wrap_content"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:textSize="18sp"
            android:gravity="center_vertical"
            />
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:id="@+id/UpdateStatusText"
            android:singleLine="true"
            android:ellipsize="marquee"
            />
        <ProgressBar android:id="@+id/UpdateProgress" 
                     android:layout_width="fill_parent" 
                     android:layout_height="wrap_content"
                     android:indeterminateOnly="false" 
                     android:progressDrawable="@android:drawable/progress_horizontal" 
                     android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal" 
                     android:minHeight="10dip" 
                     android:maxHeight="10dip"                    
                     />
    </LinearLayout>
    <CheckBox android:text="" 
              android:id="@+id/UpdateCheckBox" 
              android:layout_width="wrap_content" 
              android:layout_height="wrap_content" 
              />
</LinearLayout>

다음은 ListActivity를 확장하는 클래스입니다. 분명히 아직 개발 중이므로 누락되었거나 남겨진 부분을 용서하십시오.

public class UpdateActivity extends ListActivity {

    AccountManager lookupDb;
    boolean allSelected;
    UpdateListAdapter list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lookupDb = new AccountManager(this);
        lookupDb.loadUpdates();

        setContentView(R.layout.update);
        allSelected = false;

        list = new UpdateListAdapter(this, R.layout.update_row, lookupDb.getUpdateItems());
        setListAdapter(list);

        Button btnEnterRegCode = (Button)findViewById(R.id.btnUpdateRegister);
        btnEnterRegCode.setVisibility(View.GONE);

        Button btnSelectAll = (Button)findViewById(R.id.btnSelectAll);
        btnSelectAll.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                allSelected = !allSelected;

                for(int i=0; i < lookupDb.getUpdateItems().size(); i++) {
                    lookupDb.getUpdateItem(i).setSelected(!lookupDb.getUpdateItem(i).isSelected());
                }

                list.notifyDataSetChanged();
                // loop through each UpdateItem and set the selected attribute to the inverse 

            } // end onClick
        }); // end setOnClickListener

        Button btnUpdate = (Button)findViewById(R.id.btnUpdate);
        btnUpdate.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
            } // end onClick
        }); // end setOnClickListener

        lookupDb.close();
    } // end onCreate


    @Override
    protected void onDestroy() {
        super.onDestroy();

        for (UpdateItem item : lookupDb.getUpdateItems()) {
            item.getDatabase().close();        
        }
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        UpdateItem item = lookupDb.getUpdateItem(position);

        if (item != null) {
            item.setSelected(!item.isSelected());
            list.notifyDataSetChanged();
        }
    }

    private class UpdateListAdapter extends ArrayAdapter<UpdateItem> {
        private List<UpdateItem> items;

        public UpdateListAdapter(Context context, int textViewResourceId, List<UpdateItem> items) {
            super(context, textViewResourceId, items);
            this.items = items;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = null;

            if (convertView == null) {
                LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                row = li.inflate(R.layout.update_row, null);
            } else {
                row = convertView;
            }

            UpdateItem item = items.get(position);

            if (item != null) {
                TextView upper = (TextView)row.findViewById(R.id.UpdateNameText);
                TextView lower = (TextView)row.findViewById(R.id.UpdateStatusText);
                CheckBox cb = (CheckBox)row.findViewById(R.id.UpdateCheckBox);

                upper.setText(item.getName());
                lower.setText(item.getStatusText());

                if (item.getStatusCode() == UpdateItem.UP_TO_DATE) {
                    cb.setVisibility(View.GONE);
                } else {
                    cb.setVisibility(View.VISIBLE);
                    cb.setChecked(item.isSelected());
                }

                ProgressBar pb = (ProgressBar)row.findViewById(R.id.UpdateProgress);
                pb.setVisibility(View.GONE);
            }
            return row;
        }

    } // end inner class UpdateListAdapter
}

편집 : 여전히이 문제가 있습니다. 나는 속임수를 쓰고 onClick 핸들러를 textviews에 추가하고 있지만 확인란을 클릭하지 않을 때 onListItemClick () 함수가 전혀 호출되지 않는다는 것은 매우 어리석은 것 같습니다.

답변:


243

문제는 Android에서 포커스 가능한 요소가있는 목록 항목을 선택할 수 없다는 것입니다. 목록 항목의 확인란을 다음과 같은 속성을 갖도록 수정했습니다.

android:focusable="false"

이제 체크 박스가 포함 된 내 목록 항목 (버튼에도 작동)은 전통적인 의미에서 "선택 가능"합니다 (불이 켜지면 목록 항목의 아무 곳이나 클릭 할 수 있으며 "onListItemClick"핸들러가 실행되는 등).

편집 : 업데이트로 한 댓글 작성자가 "단추의 가시성을 변경 한 후 프로그래밍 방식으로 포커스를 다시 비활성화해야했습니다."라고 언급했습니다.


24
목록 항목에서 ImageButton을 사용할 때이 솔루션이 작동하지 않는 것으로 나타납니다. :(
Julian A.

1
그래도 내 확인란과 목록보기를 함께 사용할 수 없게하려면 어떻게해야합니까? ListView 항목을 선택하면 반드시 체크 박스를 선택하고 싶지는 않습니다. 이 솔루션으로 가능합니까?
Mike6679

@Mike 예,이 솔루션은 상호 작용하려면 확인란을 명시 적으로 클릭해야합니다. 목록 항목 레이아웃에 포커스 가능한 요소가있을 때 신비하게 우회되는 ListView의 기능을 다시 활성화합니다.
MattC

2
훌륭한 답변 감사합니다. ImageButtons에서도 잘 작동합니다. 참고로, 버튼의 가시성을 변경 한 후 프로그래밍 방식으로 포커스를 다시 비활성화해야했습니다.
Ljdawson

1
세트가 안드로이드에 당신은 또한해야 할 수도 있습니다 : 클릭 =를 "거짓"
미나 새미

43

목록 항목 내에 ImageButton이 descendantFocusability있는 경우 루트 목록 항목 요소에서 값을 'blocksDescendants'로 설정해야합니다 .

android:descendantFocusability="blocksDescendants"

그리고 보기 에서 focusableInTouchMode플래그 .trueImageButton

android:focusableInTouchMode="true"

1
이것은 이미지 버튼이있는 목록 항목에 완벽하게 작동합니다. 그러나하여 ImageButton을 제외하고이 힘 작업
raksja

12

비슷한 문제가 발생하여 CheckBox가 ListView에서 다소 까다 로움을 발견했습니다. 발생하는 일은 전체 ListItem에 대한 의지를 부과하고 일종의 onListItemClick을 재정의합니다. 이를 위해 클릭 핸들러를 구현하고 TextViews를 사용하는 대신 CheckBox에 대한 텍스트 속성도 설정할 수 있습니다.

이 View 개체도 살펴보면 CheckBox보다 더 잘 작동 할 수 있습니다.

확인 된 텍스트보기


6
목록에서 포커스 가능한 항목에 대해 "focusable"설정을 false로 설정하면 onListItemClick 함수를 다시 사용할 수 있다는 것을 발견했습니다.
MattC

2
그러나 체크 박스는 목록 항목처럼 주황색으로 바뀝니다. 누구든지 해결책을 알고 있습니까?
erdomester 2012

8

목록 항목의 루트보기에서이 행을 사용하십시오.

android : descendantFocusability = "blocksDescendants"

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.