Benutzerdefiniertes ListView-Klickproblem bei Elementen in Android

110

Ich habe also ein benutzerdefiniertes ListView-Objekt. Die Listenelemente haben zwei übereinander gestapelte Textansichten sowie einen horizontalen Fortschrittsbalken, den ich verbergen möchte, bis ich tatsächlich etwas tue. Ganz rechts befindet sich ein Kontrollkästchen, das ich nur anzeigen möchte, wenn der Benutzer Aktualisierungen in seine Datenbank (en) herunterladen muss. Wenn ich das Kontrollkästchen deaktiviere, indem ich die Sichtbarkeit auf Visibility.GONE setze, kann ich auf die Listenelemente klicken. Wenn das Kontrollkästchen sichtbar ist, kann ich nur auf die Kontrollkästchen in der Liste klicken. Ich habe etwas gesucht, aber nichts gefunden, was für meine aktuelle Situation relevant ist. Ich habe diese Frage gefundenIch verwende jedoch einen überschriebenen ArrayAdapter, da ich ArrayLists verwende, um die Liste der Datenbanken intern zu enthalten. Muss ich nur die LinearLayout-Ansicht abrufen und einen onClickListener hinzufügen, wie es Tom getan hat? Ich bin mir nicht sicher.

Hier ist das XML-Listenlayout für die Listenansicht:

<?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>

Und hier ist die Klasse, die die ListActivity erweitert. Offensichtlich befindet es sich noch in der Entwicklung. Verzeihen Sie also die Dinge, die fehlen oder möglicherweise herumliegen:

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
}

edit: Ich habe immer noch dieses Problem. Ich betrüge und füge den Textansichten onClick-Handler hinzu, aber es scheint äußerst dumm, dass meine onListItemClick () -Funktion überhaupt nicht aufgerufen wird, wenn ich nicht auf mein Kontrollkästchen klicke.

MattC
quelle

Antworten:

243

Das Problem ist, dass Sie mit Android keine Listenelemente auswählen können, auf denen sich Elemente befinden, die fokussierbar sind. Ich habe das Kontrollkästchen für das Listenelement so geändert, dass es ein Attribut wie das folgende enthält:

android:focusable="false"

Jetzt sind meine Listenelemente, die Kontrollkästchen enthalten (funktioniert auch für Schaltflächen), im herkömmlichen Sinne "auswählbar" (sie leuchten auf, Sie können auf eine beliebige Stelle im Listenelement klicken und der Handler "onListItemClick" wird ausgelöst usw.).

BEARBEITEN: Als Update erwähnte ein Kommentator: "Nur eine Anmerkung, nachdem ich die Sichtbarkeit der Schaltfläche geändert hatte, musste ich den Fokus programmgesteuert wieder deaktivieren."

MattC
quelle
24
Diese Lösung funktioniert anscheinend nicht, wenn ImageButton im Listenelement verwendet wird. :(
Julian A.
1
Ok, aber was ist, wenn ich möchte, dass sich mein Kontrollkästchen und meine Listenansicht gegenseitig ausschließen? Wenn ich das ListView-Element auswähle, möchte ich das Kontrollkästchen nicht unbedingt aktivieren. Ist das mit dieser Lösung möglich?
Mike6679
@Mike Ja, für diese Lösung muss das Kontrollkästchen weiterhin explizit angeklickt werden, um mit ihm interagieren zu können. Es aktiviert lediglich die Funktionen in der ListView, die auf mysteriöse Weise umgangen werden, wenn Sie fokussierbare Elemente in Ihrem Listenelementlayout haben.
MattC
2
Tolle Antwort, danke, funktioniert auch gut mit ImageButtons. Nur eine Anmerkung, nachdem ich die Sichtbarkeit der Schaltfläche geändert hatte, musste ich den Fokus programmgesteuert wieder deaktivieren.
Ljdawson
1
Möglicherweise müssen Sie auch Android einstellen: clickable = "false"
Mina Samy
43

Wenn sich ImageButton im Listenelement befindet, sollten Sie den descendantFocusabilityWert im Element des Stammlistenelements auf 'blocksDescendants' setzen.

android:descendantFocusability="blocksDescendants"

Und die focusableInTouchModeFlagge truein der ImageButtonAnsicht.

android:focusableInTouchMode="true"
micnoy
quelle
1
Dies funktioniert perfekt für Listenelemente mit Bildschaltflächen. Aber das könnte funktionieren, außer ImageButton
Raksja
12

Ich habe ein ähnliches Problem festgestellt und festgestellt, dass die CheckBox in einer ListView ziemlich pingelig ist. Was passiert, ist, dass es dem gesamten ListItem seinen Willen auferlegt und den onListItemClick überschreibt. Möglicherweise möchten Sie dafür einen Klick-Handler implementieren und die Texteigenschaft auch für die CheckBox festlegen, anstatt die TextViews zu verwenden.

Ich würde sagen, schauen Sie sich auch dieses View-Objekt an, es funktioniert möglicherweise besser als die CheckBox

Überprüfte Textansicht

Andrew Burgess
quelle
6
Ich habe festgestellt, dass Sie Ihre onListItemClick-Funktion erneut verwenden können, wenn Sie die Einstellung "focusable" für die fokussierbaren Elemente in der Liste auf false setzen.
MattC
2
Das Kontrollkästchen wird jedoch wie das Listenelement orange. Kennt jemand eine Lösung?
Erdomester
8

Verwenden Sie diese Zeile in der Stammansicht des Listenelements

android: descantFocusability = "blocksDescendants"

Suresh Kumar
quelle