2017-11-26 3 views
0

Ich habe eine Android App mit einem Suchfeld und einem Listenansicht. Wenn der Benutzer das erste Zeichen eintippt, sollte die Anwendung sanft zum ersten Element mit dem angegebenen Zeichen blättern und das Element hervorheben. Wenn der Benutzer die Eingabe entfernt, sollte die Anwendung zum ersten Objekt zurück blättern, ohne es hervorzuheben.Falsches Scrollen mit Highliting in ListView bei der Suche nach Artikel

Nachdem ich viel versucht habe und viel gelesen habe, denke ich, dass ich etwas Hilfe brauche. Was ich als Android-Anfänger gemacht habe, funktioniert nicht richtig. Die App ist Scrolling - aber das Verhalten ist irgendwie seltsam:

  • die falschen Artikel

enter image description here

  • nach ein zweites Mal (bis e) zwei falsche Einzelteile sind, die versuchen wird hervorgehoben
  • hervorgehoben

enter image description here

  • löschen Sucheingabe und dies geschah

enter image description here

Es gibt einige andere seltsame Dinge geschehen, die alle hier nicht dokumentiert. Z.B. Wenn die App hinter dem zuletzt angezeigten Objekt scrollt und ich zurück blättern kann, wird nicht das erste Objekt an Position 0 hochgezündet, sondern das zweite. Scrollen nach unten und zurück und der zweite und der dritte Punkt sind hervorgehoben.

Und es ist auch falsch, dass sie hervorgehoben sind, da ich zurückgehen möchte, möchte ich kein Element hervorheben.

Ich denke, dass etwas mit meiner Indexverwaltung nicht stimmt - oder etwas anderes, was ich nicht erklären kann, ist völlig falsch.

Hier ist meine Projektstruktur:

enter image description here

Für die Liste ich eine eigene Klasse ItemsTask verwenden - aber das sollte keine Rolle, zu viel für das Problem. Und der Objektadapter für die Liste ist der ToDoListAdapter.

Das ganze Projekt macht viel mehr, aber ich möchte es hier kurz halten, um eine Lösung nur für das Scrollen in der Liste zu finden. Hier ist die MainActivity.java:

> package com.wbapps.ListScrolling; 

/** 
* Created by Andreas on 9/4/2017. 
*/ 

import android.app.SearchManager; 
import android.content.Context; 
import android.graphics.Color; 
import android.support.v7.app.ActionBar; 
import android.os.Bundle; 
import android.os.Environment; 
import android.support.v7.app.AppCompatActivity; 
import android.view.View; 
import android.widget.ListView; 
import android.widget.SearchView; 
import org.xmlpull.v1.XmlPullParserException; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class MainActivity extends AppCompatActivity implements 
     SearchView.OnQueryTextListener,SearchView.OnCloseListener { 
    private SearchView search; 
    /* object for the ListView from activity_main.xml*/ 
    ListView list_view; 
    /*wb, 04Oct2017: List for the shopping items */ 
    List<ItemsTask> list_items; 
    /*wb, 04Oct2017: adapter for items */ 
    TodoListAdapter items_adapter; 
    /* wb, 04Oct2017: there must be a parser for the items-xml and another one for the categories-xml */ 
    XmlParser xmlparser; 
    /* wb, 04Oct2017: create the two xml files for the shopping items and the categories */ 
    File file_shoppingItems; 
    ActionBar actionBar; 

    /* wb, 06Nov Declaration of variables used for the AlertBuilder multiItemsChecked*/ 
    ArrayList<Integer> mSelectedItems; 

    /* wb, 09Nov Declaration of variables used for the AlertBuilder of singleItemsChecked*/ 
    String theChoice; 
    /* wb, 23Nov2017: no more filter 
    wb, 10Nov2017: Flag if filter is set or not 
    boolean filtered = false; 
    */ 
    Integer searchedItem = 0; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); 
     search = (SearchView) findViewById(R.id.search); 
     search.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); 
     search.setIconifiedByDefault(false); 
     search.setOnQueryTextListener(this); 
     //search.setOnCloseListener(this); 

     file_shoppingItems = new File(Environment.getExternalStorageDirectory(), "shoppingItems.xml"); 

     xmlparser = new XmlParser(); 
     list_items = new ArrayList<ItemsTask>(); 

     if (file_shoppingItems.exists()) { 
      try { 
       list_items = xmlparser.read(file_shoppingItems); 
       if (list_items.isEmpty()) { 
        //Toast.makeText(this, "File exist but empty", Toast.LENGTH_SHORT).show(); 
        file_shoppingItems.delete(); 
        file_shoppingItems.createNewFile(); 
       } else { 
        sortList(); 
       } 

      } catch (XmlPullParserException ex) { 
       Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (FileNotFoundException ex) { 
       //Toast.makeText(this, "Error 2", Toast.LENGTH_SHORT).show(); 
       Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex); 
      } catch (IOException ex) { 
       //Toast.makeText(this, "Error 3", Toast.LENGTH_SHORT).show(); 
       Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } else { 
      try { 
       //Toast.makeText(this, "File does not exist - will be created", Toast.LENGTH_SHORT).show(); 
       file_shoppingItems.createNewFile(); 
      } catch (IOException ex) { 
       //Toast.makeText(this, "Error 4", Toast.LENGTH_SHORT).show(); 
       Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 

     /* id list_view identifies the listview from the activity_main.xmll */ 
     list_view = (ListView) findViewById(R.id.list_view); 
     registerForContextMenu(list_view); 
     items_adapter = new TodoListAdapter(list_items, this); 
     list_view.setAdapter(items_adapter); 

     //To swipe away an item from the list 
     SwipeDismissListViewTouchListener touchListener = 
       new SwipeDismissListViewTouchListener(
         list_view, 
         new SwipeDismissListViewTouchListener.DismissCallbacks() 
         { 
          /*wb,11Nov2017: Method "canDismiss" is required when calling 
          new SwipeDismissListViewTouchListener.DismissCallbacks() 
          but here not used */ 
          @Override 
          public boolean canDismiss(int position) {return true;} 

          @Override 
          public void onDismiss(ListView listView, int[] reverseSortedPositions) { 
           for (int position : reverseSortedPositions) { 
            list_items.remove(position); 
            items_adapter.notifyDataSetChanged(); 
           } 
          } 
         }); 
     list_view.setOnTouchListener(touchListener); 
    } 


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

    @Override 
    public boolean onQueryTextSubmit(String query) { 
     return true; 
    } 

    @Override 
    public boolean onQueryTextChange(String query) { 
     int duration = 300; //miliseconds 
     int offset = 0;  //fromListTop 
     searchedItem = -1; 
     if (query.isEmpty()) { 
      if (searchedItem > -1) { 
       list_view.getChildAt(searchedItem); 
       View v = (View) findViewById(R.id.list_task_view); 
       v.setBackgroundColor(Color.rgb(176,233,249)); 
       searchedItem = -1; 
      } 
      for (int i=0; i < list_items.size();i++) { 
       View v = (View) findViewById(R.id.list_task_view); 
       v.setBackgroundColor(Color.rgb(176,233,249)); 
      } 
      list_view.smoothScrollToPositionFromTop(0, offset, duration); 
     } 
     else 
     { 
      for (int i=0; i < list_items.size();i++) { 
       //v.setBackgroundColor(Color.rgb(176,233,249)); 
       if (list_items.get(i).getTaskContent().toUpperCase().charAt(0) == query.toUpperCase().charAt(0)) { 
        searchedItem = i; 
        list_view.smoothScrollToPositionFromTop(i, offset, duration); 
        //list_view.setSelection(i); 
        View v = (View) findViewById(R.id.list_task_view); 
        v.setBackgroundColor(Color.rgb(238, 202, 197)); 
        break; 
       } 
      } 

     } 

     return true; 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     //wb, Sep 13, 2017: 
     //before doing something else - like calling a new activity - write the list to 
     //the data sourc file list_items.xml file 
     try { 
      xmlparser.write(list_items, file_shoppingItems); 
     } catch (IOException ex) { 
      Logger.getLogger(MainActivity.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 


    /* wb, 18Sep2017: sort the list_items list */ 
    public void sortList() { 
      Collections.sort(list_items, new Comparator<ItemsTask>() { 
       @Override 
       public int compare(ItemsTask content1, ItemsTask content2) { 
       /* ignore case sentsitivity */ 
        return content1.getTaskContent().compareToIgnoreCase(content2.getTaskContent()); 
       } 
      }); 


    } 
}; 

Die Daten für die Liste stammt von einer externen XML-Datei.

Und das ist der ToDoListAdapter:

/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package com.wbapps.ListScrolling; 

import android.content.Context; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.BaseAdapter; 
import android.widget.CheckBox; 
import android.widget.CompoundButton; 
import android.widget.TextView; 

import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 

public class TodoListAdapter extends BaseAdapter { 
    private List<ItemsTask> listItemsTasks; 
    private List<ItemsTask> savedItemsTasks; 
    private final LayoutInflater inflater; 
    ItemsTask itemsTask; 

    /* wb, 04Oct2017: may be no more! */ 
    String MyStr, MySubStr; 

    TodoListAdapter.ViewHolder holder; 

    public TodoListAdapter(List<ItemsTask> itemsTasks, Context context) { 
     this.listItemsTasks = itemsTasks; 
     inflater = LayoutInflater.from(context); 
    } 

    public int getCount() { 
     return listItemsTasks.size(); 
    } 

    public Object getItem(int position) { 
     return listItemsTasks.get(position); 
    } 
    public long getItemId(int position) {return position;} 

    public View getView(final int position, View convertView, ViewGroup parent) { 
     if (convertView == null) { 
       convertView = inflater.inflate(R.layout.list_layout, parent, false); 

       holder = new TodoListAdapter.ViewHolder(); 

       View v = convertView.findViewById(R.id.list_checkbox); 

       holder.task_view = (TextView) convertView.findViewById(R.id.list_task_view); 
       holder.done_box = (CheckBox) convertView.findViewById(R.id.list_checkbox); 
       convertView.setTag(holder); 
     } else { 
      holder = (TodoListAdapter.ViewHolder) convertView.getTag(); 
     } 

     itemsTask = (ItemsTask) getItem(position); 

     /* wb, 15Sep,2017: Show checkbox only in MainActivity */ 
      holder.done_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
        listItemsTasks.get(position).setIsDone(isChecked); 

        if (isChecked) { 
         //wb,21Sep2017: No strike out neccessary 
         //holder.task_view.setPaintFlags(holder.task_view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); 
         holder.task_view.setPaintFlags(holder.task_view.getPaintFlags()); 
        } else { 
         holder.task_view.setPaintFlags(0); 
        } 
       } 
      }); 

      holder.task_view.setText(itemsTask.getTaskContent()); 
      holder.done_box.setChecked(itemsTask.isDone()); 

      return convertView; 
     } 

    /* wb, 18Sep2017: sort the list_items list */ 
    public void sortList() { 
     Collections.sort(listItemsTasks, new Comparator<ItemsTask>() { 
      @Override 
      public int compare(ItemsTask content1, ItemsTask content2) { 
       /* return o1.getTaskContent().compareTo(o2.getTaskContent()); */ 
       /* ignore case sentsitivity */ 
       return content1.getTaskContent().compareToIgnoreCase(content2.getTaskContent()); 
      } 
     }); 
    } 

    static class ViewHolder { 
      TextView spin_view; 
      TextView task_view; 
      CheckBox done_box; 
      TextView sl_task; 
      TextView sl_category; 
     } 
} 

Es ist ein wichtiger Punkt sollte man wissen:

Ich habe keinen Filter verwenden, um das Ergebnis der Benutzer Eingabe zu erhalten. Ich möchte nur zum Listeneintrag springen. Soweit ich sehen kann, kann ich kein onClick-Event verwenden, wie ich es in vielen Posts für eine ähnliche Frage gesehen habe. Also wird das in meiner Situation nicht helfen.

Ich habe gerade ein paar Scrolling probiert und habe dies bemerkt: Mit dem Scrollen durch die Liste hin und her (nicht das Eingabefeld löschen!) Hat die App immer einige verschiedene Listenpunkte markiert. Für mich sehe ich dafür kein logisches Schema.

+0

ListView recycelt seine Objektansicht, also ändern Sie nicht direkt die Objektansicht, sonst treten Probleme nach dem Scrollen auf. Versuchen Sie, die Variable selectedItem in den Adapter zu verschieben. Überprüfen Sie im Adapter getView(), ob selectedItem == position, verwenden Sie die ausgewählte Hintergrundfarbe oder verwenden Sie die Standardfarbe. Sie benötigen außerdem eine öffentliche Methode, um die ausgewählte Position zu empfangen und notifyDataSetChanged() innerhalb des Adapters aufzurufen. Rufen Sie in Ihrer onQueryTextChange diese öffentliche Methode auf, um ListView und dann smoothScrollToPositionFromTop zu aktualisieren. Mein Blog kann helfen: http://programandroidlistview.blogspot.com/ –

+0

Hallo I_A_Mok - das klingt sehr interessant. Aber ich bin nicht sehr vertraut mit dem, was Sie vorgeschlagen haben. Ich werde versuchen, es in den nächsten Tagen einzurichten und Feedback zu geben. Auch dein Blog sieht sehr interessant aus und ich werde über die nächsten Tage lesen. Vielen Dank in der Tat al jetzt –

Antwort

1

Versuchen Sie folgendes:

Adapter:

public class TodoListAdapter extends BaseAdapter { 
private List<ItemsTask> listItemsTasks; 
private List<ItemsTask> savedItemsTasks; 
private final LayoutInflater inflater; 
ItemsTask itemsTask; 

private int searchedItem = -1; 

/* wb, 04Oct2017: may be no more! */ 
String MyStr, MySubStr; 

TodoListAdapter.ViewHolder holder; 

public TodoListAdapter(List<ItemsTask> itemsTasks, Context context) { 
    this.listItemsTasks = itemsTasks; 
    inflater = LayoutInflater.from(context); 
} 

public int getCount() { 
    return listItemsTasks.size(); 
} 

public Object getItem(int position) { 
    return listItemsTasks.get(position); 
} 
public long getItemId(int position) {return position;} 

public View getView(final int position, View convertView, ViewGroup parent) { 
    if (convertView == null) { 
     convertView = inflater.inflate(R.layout.list_layout, parent, false); 

     holder = new TodoListAdapter.ViewHolder(); 

     View v = convertView.findViewById(R.id.list_checkbox); 

     holder.task_view = (TextView) convertView.findViewById(R.id.list_task_view); 
     holder.done_box = (CheckBox) convertView.findViewById(R.id.list_checkbox); 
     convertView.setTag(holder); 
    } else { 
     holder = (TodoListAdapter.ViewHolder) convertView.getTag(); 
    } 

    itemsTask = (ItemsTask) getItem(position); 

    /* wb, 15Sep,2017: Show checkbox only in MainActivity */ 
    holder.done_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 
     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
      listItemsTasks.get(position).setIsDone(isChecked); 

      if (isChecked) { 
       //wb,21Sep2017: No strike out neccessary 
       //holder.task_view.setPaintFlags(holder.task_view.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); 
       holder.task_view.setPaintFlags(holder.task_view.getPaintFlags()); 
      } else { 
       holder.task_view.setPaintFlags(0); 
      } 
     } 
    }); 

    holder.task_view.setText(itemsTask.getTaskContent()); 
    holder.done_box.setChecked(itemsTask.isDone()); 

    if(position == searchedItem){ 
     convertView.setBackgroundColor(Color.rgb(238, 202, 197)); 
    }else{ 
     convertView.setBackgroundColor(Color.rgb(176,233,249)); 
    } 

    return convertView; 
} 

/* wb, 18Sep2017: sort the list_items list */ 
public void sortList() { 
    Collections.sort(listItemsTasks, new Comparator<ItemsTask>() { 
     @Override 
     public int compare(ItemsTask content1, ItemsTask content2) { 
      /* return o1.getTaskContent().compareTo(o2.getTaskContent()); */ 
      /* ignore case sentsitivity */ 
      return content1.getTaskContent().compareToIgnoreCase(content2.getTaskContent()); 
     } 
    }); 
} 

public void setSearchedItem(Integer position){ 
    this.searchedItem = position; 
    notifyDataSetChanged(); 
} 

static class ViewHolder { 
    TextView spin_view; 
    TextView task_view; 
    CheckBox done_box; 
    TextView sl_task; 
    TextView sl_category; 
} 
} 

onQueryTextChange:

@Override 
public boolean onQueryTextChange(String query) { 
    int duration = 300; //miliseconds 
    int offset = 0;  //fromListTop 
    if (query.isEmpty()) { 
     items_adapter.setSearchedItem(-1); 
     list_view.smoothScrollToPositionFromTop(0, offset, duration); 
    } 
    else 
    { 
     for (int i=0; i < list_items.size();i++) { 
      if (list_items.get(i).getTaskContent().toUpperCase().charAt(0) == query.toUpperCase().charAt(0)) { 
       items_adapter.setSearchedItem(i); 
       list_view.smoothScrollToPositionFromTop(i, offset, duration); 
       break; 
      } 
     } 

    } 

    return true; 
} 

Hoffnung, die hilft !!

+0

Wow - ich bin beeindruckt. Das war die Lösung, die ich suche !! Danke vielmals. Es hilft auch, mein Verständnis von ArrayAdapter zu verbessern. Einen schönen Tag noch! –

Verwandte Themen