2017-11-26 1 views
0

検索フィールドとリストビューを持つAndroid Appがあります。ユーザーが最初の文字を入力すると、アプリケーションは、指定された文字で最初の項目までスムーススクロールし、項目を強調表示します。ユーザーが入力を削除した場合、アプリケーションは強調表示せずに最初の項目にスムーズにスクロールします。アイテムを検索するときにListViewのハイライトでスクロールが正しく行われない

多くのことを読んで多くを読んだ後、私はいくつかの助けが必要だと思います。 Androidの初心者として私がしたことは、正しい方法では機能しません。アプリがスクロールしている - しかし、行動は一種の奇妙です:

  • 間違った項目は、(E)に二度目を試した後

enter image description here

  • を強調されている2つの間違ったアイテムをしていますハイライト表示

enter image description here

  • 削除検索入力と、これは他のいくつかの奇妙なことがあります

enter image description here

が起こっはすべてここに文書化することができないが起こりました。例えば。アプリが最後に表示されたアイテムの後ろをスクロールしていて、スクロールしているときは、位置0の最初のアイテムはハイライトされず、2番目のアイテムはスクロールされません。もう一度スクロールして2番目と3番目の項目を強調表示します。

また、強調表示されているのは間違っています。戻ってきて項目を強調したくありません。

インデックス管理に何か問題があると思います。私が説明できないことは全く間違っています。

は、ここに私のプロジェクト構造である:私は自分のクラスItemsTaskを使用するリストについては

enter image description here

- それは、問題のためあまり問題ではないはず。リストの項目アダプタはToDoListAdapterです。

プロジェクト全体にはさらに多くのことがありますが、ここではリスト内のスクロールだけの解決策を見つけるためにここを短くしたいと考えています。

> 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()); 
       } 
      }); 


    } 
}; 

リストのデータは外部のXMLファイルから来ている: ここMainActivity.javaです。

そして、これは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; 
     } 
} 

1が知っておくべきもう一つの重要なポイントがあります:

私は、ユーザー入力の結果を得るためにフィルタを使用しないでください。私はちょうどlistitemにジャンプしたい。私が見る限り、私は同様の質問のために多くの投稿に見たように、onClickイベントを使用することはできません。これは私の状況では役に立たないでしょう。

私はちょうど前後にいくつかのスクロールを試み、これに気付きました:リストを前後にスクロールして(入力フィールドを削除しないで!)、アプリケーションは常にいくつかの異なるリスト項目を強調表示しました。私にとっては、それについて論理的なスキーマは見えません。

+0

ListViewはアイテムビューをリサイクルします。アイテムビューを直接変更しないと、スクロール後に問題が発生します。変数selectedItemをアダプタに移動してみてください。アダプタのgetView()で、selectedItem ==の位置を確認し、選択した背景色を使用します。それ以外の場合はデフォルトの色を使用します。また、選択した位置を受け取るためのパブリックメソッドが必要であり、アダプタ内でnotifyDataSetChanged()を呼び出す必要があります。 onQueryTextChangeで、そのpublicメソッドを呼び出してListViewを更新し、次にsmoothScrollToPositionFromTopを更新します。私のブログが役立つかもしれません:http://programandroidlistview.blogspot.com/ –

+0

こんにちはI_A_Mok - これはとても興味深いですね。しかし、私はあなたが示唆したことにあまりよく似ていません。私は次の日にそれを設定し、フィードバックを与えようとします。また、あなたのブログは非常に面白く見え、私は次の日について読んでいます。本当にありがとうございました –

答えて

1

はこれを試してみてください:

アダプタ:

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; 
} 

を役に立てば幸い!

+0

うわー - 私は感銘を受けた。これは私が探している解決策でした!どうもありがとう。 ArrayAdapterの理解を向上させるのにも役立ちます。良い一日を! –

関連する問題