Android ListView с ListAdapter, всегда нужно иметь выбранную запись

у меня есть ListView (lvProperties), адаптер которого является пользовательским ListAdapter (не ArrayAdapter). Этот адаптер получает данные из переменной экземпляра раздела пользовательского типа (содержащего несколько строк, целых чисел, списков массивов и методов).

Мне нужно, чтобы этот список ВСЕГДА отображал выбор (всегда должен быть выбранный элемент, даже при запуске активности).

При использовании простого ArrayAdapter в прошлом было бы достаточно этого:

lvProperties.requestFocus();
lvProperties.setSelection(0);

Однако в данном случае это вообще не работает. Я искал SO и Интернет и использовал:

lvProperties.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
lvProperties.setFocusable(true);            
lvProperties.setFocusableInTouchMode(true);
lvProperties.requestFocus();
lvProperties.setSelection(0);

И все равно ничего.

Мой списокадаптер:

    lvProperties.setAdapter(new ListAdapter() {
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
                View v=convertView;

                if(v==null) {
                    LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    v=vi.inflate(R.layout.detail_row1, null);
                }

                TextView name=(TextView)v.findViewById(R.id.propName);
                TextView value=(TextView)v.findViewById(R.id.propValue);

                if(name!=null) {
                    name.setText(section.propNames.get(position));
                }
                if(value!=null) {
                value.setText(section.propValues.get(position));
                }

                return v;
            }

        @Override
        public void unregisterDataSetObserver(DataSetObserver observer) {}

        @Override
        public void registerDataSetObserver(DataSetObserver observer) {}

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public boolean hasStableIds() {
            return false;
        }

        @Override
        public int getViewTypeCount() {
            return 2;
        }

        @Override
        public int getItemViewType(int position) {
            return 0;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public int getCount() {
            return section.propNames.size();
        }

        @Override
        public boolean isEnabled(int position) {
            return true;
        }

        @Override
        public boolean areAllItemsEnabled() {
            return true;
        }
    });

Мой нереализованный OnItemSelectedListener:

    lvProperties.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {
            // TODO Auto-generated method stub

        }
    });

И мой detail_row1.xml (далее я буду реализовывать макеты для строк, но сейчас это так:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:orientation="horizontal" 
  android:layout_height="wrap_content"
  android:padding="6dip"
  >

  <TextView
    android:id="@+id/propName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"   
    android:layout_weight="1"    
    android:textSize="16sp"
    android:textStyle="bold" 
    android:textColor="#000000"
    android:gravity="center_vertical|left"
    android:paddingTop="10sp"
    android:paddingBottom="10sp"
    android:paddingLeft="4sp"
     />

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="2"
    android:id="@+id/propValue"       
    android:textColor="#000000"
    android:textSize="16sp"
    android:textStyle="bold"
    android:paddingTop="10sp"
    android:paddingBottom="10sp"
    android:paddingRight="4sp"
    android:gravity="center_vertical|right"
    />  

</LinearLayout><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:orientation="horizontal" 
  android:layout_height="wrap_content"
  android:padding="6dip"
  >

  <TextView
    android:id="@+id/propName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"   
    android:layout_weight="1"    
    android:textSize="16sp"
    android:textStyle="bold" 
    android:textColor="#000000"
    android:gravity="center_vertical|left"
    android:paddingTop="10sp"
    android:paddingBottom="10sp"
    android:paddingLeft="4sp"
    />

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="2"
    android:id="@+id/propValue"       
    android:textColor="#000000"
    android:textSize="16sp"
    android:textStyle="bold"
    android:paddingTop="10sp"
    android:paddingBottom="10sp"
    android:paddingRight="4sp"
    android:gravity="center_vertical|right"
    />  

</LinearLayout>

любая помощь/указатель на руководство о том, как это сделать? Я не хочу использовать drawable, просто селектор по умолчанию для темы, которую я использую.

Опять же, в списке всегда должна быть одна выбранная запись.

Я понимаю, что по дизайну это не предназначено для списков, НО это один из тех случаев, когда один размер не подходит всем.


person David Homes    schedule 22.08.2012    source источник
comment
Мне нужно, чтобы этот список ВСЕГДА отображал выбор - выбор должен отображаться только с помощью клавиш со стрелками, крестовины или другого указывающего устройства без сенсорного экрана. Я понимаю, что по замыслу это не предназначено для списков, НО это один из тех случаев, когда один размер не подходит всем - если вы хотите объяснить, почему, возможно, мы сможем найти какие-то другие способы указать что бы это ни было Вы хотите, чтобы пользователи знали о. Например, активировано — это состояние, используемое в HC/ICS/JB для указания контекста некоторого смежного материала, выбранного через список.   -  person CommonsWare    schedule 23.08.2012
comment
Причина, вкратце, заключается в том, что другие элементы внутри активности заполняются в зависимости от того, что выбрано в списке. Я переношу одно из своих приложений с iOS на Android и хочу воспроизвести это (из этого приложения) bit.ly/NIXRkZ< /а>. Я знаю, что это разные платформы, но я бы хотел, чтобы они были такими.   -  person David Homes    schedule 23.08.2012
comment
То, что вы описываете, активировано, но как концепция, которая существует только на Android 3.0+, и поэтому будет ожидаться только пользователями на таких устройствах. И даже на этих устройствах активация происходит только после нажатия пользователем, а не до.   -  person CommonsWare    schedule 23.08.2012
comment
Ну, это приложение я пытался портировать когда-то еще во времена Froyo. В то время у основного действия (в данном случае это было бы подробное действие) был ListView с ArrayAdapter, и простой listView.requestFocus() / listView.setSelection() выполнял эту работу. В то время я так и не завершил портирование, так как не знал Java и думал, что это не стоит затраченных усилий. я просто не понимаю, как если бы я мог подражать этому раньше, я не могу сделать это сейчас   -  person David Homes    schedule 23.08.2012
comment
Вы можете попробовать расширить BaseAdapter вместо того, чтобы создавать чистый ListAdapter прямо из интерфейса, и посмотреть, поможет ли это. Я понятия не имею, почему тип адаптера может на что-то повлиять. Определение layout может быть важным, если что-то в нем меняется/мешает выделению выделения, но это не должно иметь значения, является ли адаптер ArrayAdapter, CursorAdapter или BaleOfHayAdapter.   -  person CommonsWare    schedule 23.08.2012
comment
Привет, Коммонс. спасибо за помощь и интерес к этому вопросу. Я пытаюсь «эмулировать» выбор на основе «селекторов» прямо сейчас, если это не сработает, я посмотрю на BaseAdapter, как вы упомянули.   -  person David Homes    schedule 23.08.2012


Ответы (1)


Для всех, кто заинтересован, я просто воспроизвел то, что мне нужно, с необходимостью возиться с ChoiceMode, requestFocus, setSelection и т. д. и т. д. и т. д., отлично работает в API 8 и выше.

когда приложение запускается, я хочу, чтобы первая строка уже была выделена:

selectedItem.setValue(0) // внутренний класс, который у меня есть, также может быть простым целым числом

мой внутренний класс ArrayDapter (мне нужно, чтобы он все время видел родительский элемент selectedItem):

примечание: далее я изменю жестко закодированный цвет, я только что решил проблему, которая у меня была:

public class DetailsAdapter extends ArrayAdapter<Section> {

    public Section section;
    public View v;
    public Context c;

    public DetailsAdapter(Context context, int textViewResourceId,
            Section s) {
        super(context, textViewResourceId);

        this.section=s;

        this.c=context;

    }

    @Override
    public int getCount() {
        return section.propNames.size();
    }

    @Override
    public View getView(int pos, View convertView, ViewGroup parent){
        this.v = convertView;

        LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if(v==null) {     
            v=vi.inflate(R.layout.detail_row1, null); 
        }

        **LinearLayout llc=(LinearLayout) v.findViewById(R.id.detail_container);**
        TextView name=(TextView)v.findViewById(R.id.propName);
        TextView value=(TextView)v.findViewById(R.id.propValue);
        if(pos==selectedItem.value) {
           llc.setBackgroundColor(Color.LTGRAY);
        } else
        { llc.setBackgroundColor(Color.WHITE);}
        Log.e("Pos",""+pos);

        if(llc!=null) {

        }

        if(name!=null) {

            name.setText(section.namesAsArray()[pos]);
        }
        if(value!=null) {
            value.setText(section.valuesAsArray()[pos]);
        }


        return v;

    }
}

Хитрость, позволяющая избежать android:state_xxxxxxx в моем XML-файле, заключалась в том, чтобы обернуть мою пользовательскую строку вложенным LinearLayout, заполняющим внешний.

макет для строки:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="horizontal" 
android:layout_height="wrap_content"
android:id="@+id/detail_linearLayout"
>

<LinearLayout 
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:layout_weight="0"
   android:id="@+id/detail_container"
     android:padding="6dip"
   >

<TextView 
android:id="@+id/propName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"   
android:layout_weight="1"    
android:textSize="16sp"
android:textStyle="bold" 
android:textColor="#000000"
android:gravity="center_vertical|left"
android:paddingTop="10sp"
android:paddingBottom="10sp"
android:paddingLeft="4sp"
/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:id="@+id/propValue"       
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
android:paddingTop="10sp"
android:paddingBottom="10sp"
android:paddingRight="4sp"
android:gravity="center_vertical|right"
/>  

</LinearLayout>
</LinearLayout>

наконец, я установил свой OnItemClickListener:

    lvProperties.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {

                **selectedItem.value=arg2;
                lvProperties.invalidateViews();**
                        .
                                    .
                                    .
                     }});

сделано и сделано!

person David Homes    schedule 23.08.2012