Android ListView (Custom) soll auf Hardwaretasten nicht reagieren.

insidERR

Mitglied
Hallo zusammen,
ich bin absolut neu in der Java/Androidwelt. Erstelle aber schon lange Tools in VBA, VB.net und habe etwas C (Arduino) Erfahrung.

Meine Java "Hallo Welt" ist eine App für einen Barcodescanner der auf der Arbeit in der Warenwirtschaft eingesetzt werden soll.
Ziel ist es Codes zu scannen und Informationen dazu zu erhalten. Die App soll eigentlich nur den Barcode (Zahlenfolge) an einen Server senden und die antwort darstellen. Das serverseitige Programm habe ich schon in VB.net erstellt. Die Kommunikation funktioniert perfekt.

Mein Problem ist im aktuellen Fall, dass ich die Tasten(Auf/ab, links/rechts, enter, P1,P2) auf dem Gerät schon für andere Funktionen der App nutze, wie z.B. in einem Textfeld die Stückzahl durch auf/ab zu erhöhen/reduzieren und mit {Enter} bestätigen.. Sonst haben die Tasten keine weitere Funktion.

Ich habe ein ListView (benutzerdefiniert mit zwei Zeilen) welches beim Scannen gefüllt wird (Server kriegt den Zahlencode, wertet ihn aus und schickt 1-10 zweizeilige Einträge als antwort welche in der ListView angezeigt werden). Funzt alles wie gewollt.
Nun ist das blöde, dass wenn die Liste gefüllt ist und ich die Tasten auf/ab oder Enter auf dem Geät drücke alle Aktionen auf der/dem ListView landen und verarbeitet werden. Heisst wenn ich {ab} drücke, will ich dass in dem unter dem ListView liegenen Textfeld der Zahlwert kleiner wird.
Das mache ich mit
Java:
@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_DPAD_UP){
            if(StückZahl<999){
                VibrateDevice(150);
                StückZahl++;
                AnzahlEingabe.setText(String.valueOf(StückZahl));
            }
        }

        if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
            if(StückZahl>0){
                VibrateDevice(150);
                StückZahl--;
                AnzahlEingabe.setText(String.valueOf(StückZahl));
            }
        }

        if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT){
            if(StückZahl<989){
                VibrateDevice(150);
                StückZahl +=10;
                AnzahlEingabe.setText(String.valueOf(StückZahl));
            }
        }

        if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT){
            if(StückZahl>9){
                VibrateDevice(150);
                StückZahl -=10;
                AnzahlEingabe.setText(String.valueOf(StückZahl));
            }
        }

        //Buttons: einbuchen / ausbuchen aktivieren
        if(keyCode==KeyEvent.KEYCODE_ENTER){
            Einbuchen.setEnabled(true);
            Ausbuchen.setEnabled(true);
            VibrateDevice(150);
        }
        return false;
    }
Bei leerer ListView klappt alles wie gewollt.
Bei gefüllter ListView gehe ich mit den auf/ab Tasten die Liste rauf und runter. Mit {enter} wird ein Clickereigniss ausgelöst als hätte man auf dem Display geklickt. Der hier beschriebene Code wird dabei größtenteils solange ignoriert, bis ich mich mit den Tasten ganz nach oben oder unter durchgeklickt habe und es nicht weiter geht. Dann werden die Ereignisse hier ausgelöst. Die Tasten links/rechts werden hier immer erfasst. Auf {enter} wird hier garnicht reagiert.

Frage: gibt es eine Möglichkeit, wie ich einstellen kann, dass ListView auf keine Taste, sondern nur auf Touchclicks reagiert? Das ".setOnItemClickListener" Ereigniss muss aber funktionieren, da ich mit den angeklickten Werten weiter arbeiten will.

Mit der SuFu bin ich weder Google noch hier weiter gekommen.
Danke 🙂
 
In dem KeyEventListener solltest du prüfen von wo das Event kommt. Welche View gerade den Fokus hat. Ist es die ListView dann überspringst du einfach deine Tasten.
 
Hallo "Jw456"
Danke für deine Antwort.
Ich habe die benutzerdefinierte ListView anhand von verschiedenen Beispielen aus dem Netz erstellt.
Bin grad nicht sicher was du meinst, da ich noch alle Begriffe kenne.
Mit dem Code hier kann ich mir den angeklickten Listeneintrag oder gedrückte Taste anzeigen lassen.
Java:
DetailListe.setOnKeyListener((v, keyCode, event)->{
    char pressedKey = (char) event.getUnicodeChar();
    Toast.makeText(MainActivity.this, "KeyCode: "+keyCode,Toast.LENGTH_SHORT).show();
    return false;
});

DetailListe.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    //@Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Toast.makeText(MainActivity.this, "Zeile 1: "+ String.valueOf(xZeile1.get(position)) + " ; Zeile 2: " + String.valueOf(xZeile2.get(position)),Toast.LENGTH_SHORT).show();
    }
});

Scheint, als hätte die ListView (DetailListe) den Focus dauerhaft.

Die ListView wird über den folgenden Adapter gefüttert.
Java:
    class myListViewAdapter extends ArrayAdapter<String> {
        Context context; String rZeile1[]; String rZeile2[];
        myListViewAdapter (Context c, ArrayList<String> Zeile1, ArrayList<String> Zeile2) {
            super(c, R.layout.listeneintrag, R.id.txtZeile1, Zeile2);
            this.context = c;
            this.rZeile1 = Zeile1.toArray(new String[0]);
            this.rZeile2 = Zeile2.toArray(new String[0]);
        }

        @Override
        public View getView(int position,  View convertView,  ViewGroup parent) {
            LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View row = layoutInflater.inflate(R.layout.listeneintrag, parent, false);

            TextView Zeile1 = row.findViewById(R.id.txtZeile1);
            TextView Zeile2 = row.findViewById(R.id.txtZeile2);
            Zeile1.setText(rZeile1[position]);
            Zeile2.setText(rZeile2[position]);
            return row;
        }
    }

Aufruf erfolgt über
Java:
        myListViewAdapter AdapterListe = new myListViewAdapter(this, xZeile1, xZeile2);
        DetailListe.setAdapter(AdapterListe);

xZeile1 und xZeile2 sind beide gefüllte "ArrayList"
 
Estmal eins Klassen schreibt man Groß Variablen klein.
"myListViewAdapter AdapterListe = new myListViewAdapter(this, xZeile1, xZeile2);"
Die Kasse "MyListView" bitte Groß und die Variable "adapterListe" kein erleichtert das lesen.
Auch das „DetailListe“ ist bestimmt das Objekt von der ListView und nicht die Klasse.



Für was setzt du einen Klicklistener auf die ListView?
„DtailListe.setOnKeyListener((v, keyCode, event)->{„
Ohne den Listener, kann die Liste auch mit den HW Tasten gesteuert werden.

Da wird der ich sage mal defaultlister der Activity nicht aufgerufen. „onKeyDown“
Damit hast du zwei Listener auf das Objekt gesetzt.

PS bevor jetzt wider Einwände von Usern wegen der Begrifflichkeit
„Default Listener Activity“ kommt ich weiß das dis nicht der richtige Ausdruck ist erschien mir hier aber doch sinnvoll.


Außer du bist in der Liste ganz oben drückst nach oben dann wird der default aufgerufen. Am ende der Liste das gleiche.
 
Hallo Jw456,
danke für deine Antwort.
Das mit der Groß/kleinschreibung ist ne persöhnliche Sache. Bringe das Programmiere mir selbst bei. Meinen Code liest außer mir keiner.
Habe da nicht besonders drauf geachtet. Bin aber für Tips immer offen, wenns etwas erleichtert. Werde versuchen darauf zu achten. 🙂
„DtailListe.setOnKeyListener((v, keyCode, event)->{„ hatte ich nur temporär gemacht um zu sehen ob das Objekt auf Tastenevents reagiert. Kann praktisch weg.

Ich habe jetzt diesen Code hier geschrieben, der in die richtige Richtung geht.
Wenn "DetailListe" Tastenanschläge erkennt, werden diese an den zuerst geposteten Code übergeben und alles weitere abgebrochen. Allerdings wird der erste Eintrag in der Liste markiert.
Außerdem wird der "onKeyDown" zwei Mal hintereinander schnell durchlaufen was bewirkt dass mein auf/abzähler das doppelte addiert/subtrahiert.
Java:
        DetailListe.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                onKeyDown(keyEvent.getKeyCode(), keyEvent);
                return true;
            }
        });
Wenn ich "onKeyDown" weg lasse, werden alle Tastenanschläge ignoriert :-(
 
Der listener wird beim Taste down Taste up durchlaufen. Du musst schon das Event auswerten nicht nur den Tasten Code. Im Event ist der Tasten Code und ob die Taste gedrückt oder losgelassen wird.
 
Ich weiß jest nicht genau wenn du true zurück gibst wird glaube auch der cursor der Liste eins hoch oder runter gesetzt oder war es false musst du testen.
 
Also wenn ich auch das Event auswerte und zwar so:
Java:
        DetailListe.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                 if(keyEvent.getKeyCode()==KeyEvent.KEYCODE_DPAD_DOWN || keyEvent.getKeyCode()==KeyEvent.KEYCODE_DPAD_UP||keyEvent.getKeyCode()==KeyEvent.KEYCODE_ENTER)
                {
                    //onKeyDown(keyEvent.getKeyCode(), keyEvent);
                    return true;
                }
                return false;
            }
        });
werden die Tasten auf/ab und enter komplett ignoriert. Der Cursor geht die Liste auch nicht mehr auf/ab. Das blöde ist, dass auch der ganz am Anfang gepostete Code "OnKeyDown" nicht abgearbeitet wird. Das brauch ich aber, da dort auf die besagten Tasten reagiert werden soll.
Wenn ich in dem auskommentiertem Code hier den Aufruf "onKeyDown" wieder aktiviere, wird er anscheinend gleich zwei Mal hintereinander durchlaufen.
Im aktuellen Fall werden alle anderen Tasten bis auf die besagten abgearbeitet z.B. links/rechts. Da wird das "onKeyDown" abgearbeitet. Je ein Mal beim Drücken. Genau wie gewoll. Die Liste interessiert links/rechts natürlich nicht.
Wenn die ListView noch nicht gefüllt ist, funktionieren auch die Tasten auf/ab/enter wie gewollt.
 
Zu deinem letzten Code.
Das ist ja der Listener der von die Listview bei einem KeyEvent aufgerufen wird.
In diesem rufst du ja deinen Default listnener auf. in der auskommentierten Zeile 6.
Du leidest eigentlich das empfangene Event einfach wieder an den Globalen Listener.
Da du in Zeile 7 gibst du True zurück das heißt für dieLlistView das sich schon um das Event gekümmert wurde und es den Listen Cursor nicht setzen muss .

Wie ich schon sagte ist es vollkommen normal das die Callback Methode zweimal aufgerufen wird einmal beim Drücken der Taste und einmal beim Loslassen der Taste.

Du solltest prüfen welche Action in dem Event gesetzt ist und vielleicht nur bei einen ACTION_DOWN reagieren. Das würde ich in dem globalen Listener machen denn den willst du ja auch benutzen wenn du nicht in der ListView bist. Auch wenn du nicht in der Liste bist wird bei einem Tastenklick der Listener zweimal aufgerufen
Java:
 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            {
                if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
                    if (StückZahl < 999) {
                        VibrateDevice(150);
                        StückZahl++;
                        AnzahlEingabe.setText(String.valueOf(StückZahl));
                    }
                }
                ......



die Zeile 6 solltest du wieder activiren.
 
Hallo und Danke nochmal,
das sieht sehr gut aus. Ich muss noch weiter Verständnis für Java enwickeln. In .NET läufts etwas anders.
Jetzt wird nicht mehr durch die Listeneinträge geklickt und es gibt auch keine Doppelklicks mehr. Super 🙂

Was jetz etwas stört ist, dass wenn die Liste zum ersten Mal gefüllt wird und ich links/rechts oder enter drücke, der erste (oder angeklickte) Listeneintrag markiert(etwas dunklerer Hintergrund) wird und sonst nix passiert. Erst beim zweiten Tastenklick wird rauf/runter gezählt oder auf enter reagiert.
Der erste Eintrag in der Liste bleibt solange "markiert" bis ich auf dem Display irgendwohin drücke. Dann wird die Markierung (Focus) für immer aufgehoben, egal was danach passiert.
 

Zurück
Oben