搜索项目时ListView中的高亮显示滚动错误 [英] Wrong scrolling with highliting in ListView when searching item

查看:88
本文介绍了搜索项目时ListView中的高亮显示滚动错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带搜索字段和列表视图的Android应用.当用户键入第一个字符时,应用程序应平滑滚动到具有给定字符的第一个项目并突出显示该项目.如果用户删除了输入,则应用程序应平滑滚动回第一项而不突出显示它.

I have an Android App with a search field and a listview. When the user types in the first character the application should smooth scroll to the first item with the given character and highlight the item. If the user remove the input the application should smooth scroll back to the first item without highlighting it.

经过大量尝试和阅读后,我认为我需要一些帮助.我作为Android初学者所做的工作无法以正确的方式进行.该应用正在滚动-但行为有点奇怪:

After trying a lot and reading a lot I think I need some help. What I did as a Android beginner does not work in the right way. The app is scrolling - but the behaviour is kind of strange:

  • 突出显示了错误的项目

  • 第二次尝试(to e)后,两个错误的项目被突出显示

  • 删除搜索输入,然后发生

发生了一些其他奇怪的事情,在这里无法全部记录.例如.当应用程序滚动到最后查看的项目后面并且我向后滚动时,位置0的第一个项目不是高位显示,而是第二个.再次向下滚动并返回,第二和第三项将突出显示.

There are some other strange things happened which can not be documented all here. E.g. when the app is scrolling behind the last viewed item and I scroll back then not the first item at position 0 is highlithed but the second. Scrolling down and back again and the second and the third item are highlighted.

并且将它们突出显示是错误的,因为我不想突出显示任何项目.

And it is also wrong that they are highlighted coz with going back I do not want to highlight any item.

我认为索引管理存在问题-或我无法解释的其他问题完全是错误的.

I think something is wrong with my index management - or something else which I can not explain is totally wrong.

这是我的项目结构:

对于列表,我使用一个自己的类ItemsTask-但这对问题应该没有太大的影响.列表的项目适配器是ToDoListAdapter.

For the list I use an own class ItemsTask - but that should not matter too much for the problem. And the item adapter for the list is the ToDoListAdapter.

整个项目还有很多工作要做,但我想在此简短说明一下,因为它只为列表中的滚动找到了解决方案. 这是MainActivity.java:

The whole project does a lot of more but I want to keep it short here due to find a solution only for the scrolling in the list. Here is the 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());
                }
            });


    }
}; 

该列表的数据来自外部xml文件.

The data for the list comes from an external xml-file.

这是ToDoListAdapter:

And this is the 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;
        }
}

还有一个重要的一点应该知道:

There is one more important point one should know:

我不使用过滤器来获取用户输入的结果.我只想跳到列表项.据我所知,我不能使用任何onClick事件,就像我在许多帖子中看到的类似问题一样.因此这对我的情况无济于事.

I do not use a filter to get the result of the users input. I just want to jump to the listitem. As far as I can see I can not use any onClick event like I have seen in many post for a similar question. So this will not help in my situation.

我只是尝试了一些来回滚动,并注意到了这一点:通过来回滚动列表(不删除输入字段!),该应用程序始终突出显示了一些不同的列表项.对我来说,我看不到任何逻辑模式.

I just tried some scrolling back and forth and noticed this: with scrolling through the list back and forth (not deleting the input field!) the app highlighted always some different list items. For me I can not see any logical schema for that.

推荐答案

尝试一下:

适配器:

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:

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

希望有帮助!

这篇关于搜索项目时ListView中的高亮显示滚动错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆