Android 如何使用 fastscroll 和 albhabet 索引器实现 ListView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12559843/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:59:06  来源:igfitidea点击:

How to implement a ListView with fastscroll and albhabet indexer

androidandroid-layoutandroid-intentandroid-emulatorandroid-widget

提问by Rao's

Please help I am struck in this for 2 days.I would like to implement a ListView with fastscroll and albhabet indexer as in the contacts application/below image. I'm using a SimpleAdapter to populate the ListView. As seen from the image, by selecting a letter from the alphabet indexer at the right, the listView selection goes to the corresponding ListItem. Please share some examples. Thank u In advance. EX: Below is my code it is just sorting the alphabet and when i onclick on E alphabet data related to E is gng to diaplay..But it is not showing E textbox in middle when i on touch of alphabet.

请帮助我对此感到震惊 2 天。我想实现一个带有 fastscroll 和 albhabet 索引器的 ListView,如联系人应用程序/下图所示。我正在使用 SimpleAdapter 来填充 ListView。从图中可以看出,通过从右侧的字母索引器中选择一个字母,listView 选择将转到相应的 ListItem。请分享一些例子。提前谢谢你。例如:下面是我的代码,它只是对字母表进行排序,当我点击与 E 相关的 E 字母表数据时,它会显示出来..但是当我触摸字母表时,它没有在中间显示 E 文本框。

enter image description here

在此处输入图片说明

How to display E text box in middle..When i touch fastscroll middle text box must show.

如何在中间显示 E 文本框..当我触摸 fastscroll 中间文本框时必须显示。

MainActivity.java

主活动.java

   public class MainActivity extends Activity implements SearchView.OnQueryTextListener,SearchView.OnCloseListener {

private ListView listView;
private SearchView search;
EfficientAdapter objectAdapter;
EfficientAdapter2 objectAdapter1;
int textlength=0;
private CheckBox checkStat, checkRoutine, checkTat;
 private GestureDetector mGestureDetector;

    // x and y coordinates within our side index
    private static float sideIndexX;
    private static float sideIndexY;

    // height of side index
    private int sideIndexHeight;

    // number of items in the side index
    private int indexListSize;

    // list with items for side index
    private ArrayList<Object[]> indexList = null;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   setContentView(R.layout.homempleb);
   Log.i("scan"," txtScanResult ");

   Arrays.sort(CountriesList.name);
ActionItem nextItem     = new ActionItem(); 
final QuickAction quickAction = new QuickAction(this, QuickAction.VERTICAL);
quickAction.addActionItem(nextItem);
quickAction.setOnDismissListener(new QuickAction.OnDismissListener()           {            
    @Override
    public void onDismiss() {
        Toast.makeText(getApplicationContext(), "Dismissed", Toast.LENGTH_SHORT).show();
    }
});


listView = (ListView) findViewById(R.id.homelistView);
listView.setTextFilterEnabled(true);
objectAdapter = new EfficientAdapter(this);
 mGestureDetector = new GestureDetector(this, new SideIndexGestureListener());
listView.setAdapter(objectAdapter);


}
 @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        if (mGestureDetector.onTouchEvent(event))
        {
            return true;
        } else
        {
            return false;
        }
    }

    private ArrayList<Object[]> createIndex(String[] strArr)
    {
        ArrayList<Object[]> tmpIndexList = new ArrayList<Object[]>();
        Object[] tmpIndexItem = null;

        int tmpPos = 0;
        String tmpLetter = "";
        String currentLetter = null;
        String strItem = null;

        for (int j = 0; j < strArr.length; j++)
        {
            strItem = strArr[j];
            currentLetter = strItem.substring(0, 1);

            // every time new letters comes
            // save it to index list
            if (!currentLetter.equals(tmpLetter))
            {
                tmpIndexItem = new Object[3];
                tmpIndexItem[0] = tmpLetter;
                tmpIndexItem[1] = tmpPos - 1;
                tmpIndexItem[2] = j - 1;

                tmpLetter = currentLetter;
                tmpPos = j + 1;

                tmpIndexList.add(tmpIndexItem);
            }
        }

        // save also last letter
        tmpIndexItem = new Object[3];
        tmpIndexItem[0] = tmpLetter;
        tmpIndexItem[1] = tmpPos - 1;
        tmpIndexItem[2] = strArr.length - 1;
        tmpIndexList.add(tmpIndexItem);

        // and remove first temporary empty entry
        if (tmpIndexList != null && tmpIndexList.size() > 0)
        {
            tmpIndexList.remove(0);
        }

        return tmpIndexList;
    }
    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);

        final ListView listView = (ListView) findViewById(R.id.homelistView);
        LinearLayout sideIndex = (LinearLayout) findViewById(R.id.sideIndex);
        sideIndexHeight = sideIndex.getHeight();
        sideIndex.removeAllViews();

        // TextView for every visible item
        TextView tmpTV = null;

        // we'll create the index list
        indexList = createIndex(CountriesList.name);

        // number of items in the index List
        indexListSize = indexList.size();

        // maximal number of item, which could be displayed
        int indexMaxSize = (int) Math.floor(sideIndex.getHeight() / 20);

        int tmpIndexListSize = indexListSize;

        // handling that case when indexListSize > indexMaxSize
        while (tmpIndexListSize > indexMaxSize)
        {
            tmpIndexListSize = tmpIndexListSize / 2;
        }

        // computing delta (only a part of items will be displayed to save a
        // place)
        double delta = indexListSize / tmpIndexListSize;

        String tmpLetter = null;
        Object[] tmpIndexItem = null;

        // show every m-th letter
        for (double i = 1; i <= indexListSize; i = i + delta)
        {
            tmpIndexItem = indexList.get((int) i - 1);
            tmpLetter = tmpIndexItem[0].toString();
            tmpTV = new TextView(this);
            tmpTV.setText(tmpLetter);
            tmpTV.setGravity(Gravity.CENTER);
            tmpTV.setTextSize(20);
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 1);
            tmpTV.setLayoutParams(params);
            sideIndex.addView(tmpTV);
        }

        // and set a touch listener for it
        sideIndex.setOnTouchListener(new OnTouchListener()
        {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                // now you know coordinates of touch
                sideIndexX = event.getX();
                sideIndexY = event.getY();

                // and can display a proper item it country list
                displayListItem();

                return false;
            }
        });
    }

    class SideIndexGestureListener extends
    GestureDetector.SimpleOnGestureListener
 {
   @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2,
        float distanceX, float distanceY)
{
    // we know already coordinates of first touch
    // we know as well a scroll distance
    sideIndexX = sideIndexX - distanceX;
    sideIndexY = sideIndexY - distanceY;

    // when the user scrolls within our side index
    // we can show for every position in it a proper
    // item in the country list
    if (sideIndexX >= 0 && sideIndexY >= 0)
    {
        displayListItem();
    }

    return super.onScroll(e1, e2, distanceX, distanceY);
}
  }

    public void displayListItem()
    {
    // compute number of pixels for every side index item
    double pixelPerIndexItem = (double) sideIndexHeight / indexListSize;

    // compute the item index for given event position belongs to
    int itemPosition = (int) (sideIndexY / pixelPerIndexItem);

    // compute minimal position for the item in the list
    int minPosition = (int) (itemPosition * pixelPerIndexItem);

    // get the item (we can do it since we know item index)
    Object[] indexItem = indexList.get(itemPosition);

    // and compute the proper item in the country list
    int indexMin = Integer.parseInt(indexItem[1].toString());
    int indexMax = Integer.parseInt(indexItem[2].toString());
    int indexDelta = Math.max(1, indexMax - indexMin);

    double pixelPerSubitem = pixelPerIndexItem / indexDelta;
    int subitemPosition = (int) (indexMin + (sideIndexY - minPosition) / pixelPerSubitem);

    ListView listView = (ListView) findViewById(R.id.homelistView);
    listView.setSelection(subitemPosition);
    }

EfficientAdapter.java

高效适配器.java

 public class EfficientAdapter extends BaseAdapter {
 private LayoutInflater mInflater;
  private Context context;

  public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
this.context=context;

  }


 public int getCount() {
return CountriesList.name.length;
 }

     public Object getItem(int position) {

return position;
 }

      public long getItemId(int position) {
return position;
   }

         public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
    convertView = mInflater.inflate(R.layout.homemplebrowview, null);
    holder = new ViewHolder();
    holder.text1 = (TextView) convertView
            .findViewById(R.id.name);
    holder.text2 = (TextView) convertView
            .findViewById(R.id.mrn);
    holder.text3 = (TextView) convertView
            .findViewById(R.id.date);
    holder.text4 = (TextView) convertView
            .findViewById(R.id.age);
    holder.text5 = (TextView) convertView
            .findViewById(R.id.gender);
    holder.text6 = (TextView) convertView
            .findViewById(R.id.wardno);
    holder.text7 = (TextView) convertView
            .findViewById(R.id.roomno);
    holder.text8 = (TextView) convertView
            .findViewById(R.id.bedno);                  
    holder.btnList = (Button)convertView.findViewById(R.id.listbutton);
 //   holder.btnList.setOnClickListener(this);

    holder.btnList.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {                       
            Intent next=new Intent(context, SeviceDetails.class);
            context.startActivity(next);
        }
    });


    convertView.setTag(holder);
} else {
    holder = (ViewHolder) convertView.getTag();
}

holder.text1.setText(CountriesList.name[position]);
holder.text2.setText(CountriesList.mrn[position]);
holder.text3.setText(CountriesList.actualstart[position]);
holder.text4.setText(CountriesList.age[position]);
holder.text5.setText(CountriesList.gender[position]);
holder.text6.setText(CountriesList.wardNo[position]);
holder.text7.setText(CountriesList.roomNo[position]);
holder.text8.setText(CountriesList.bedNo[position]);

return convertView;
     }
     static class ViewHolder {
public Button btnList;
public TextView text8;
public TextView text7;
public TextView text6;
public TextView text5;
public TextView text4;
public TextView text1;
public TextView text2;
public TextView text3;
     }

  @Override
     public void notifyDataSetChanged()
  {
super.notifyDataSetChanged();
      }


    }

回答by Sackurise

Here is the Simple Code for alphabet indexing in ListView, which uses 2 java program files

这是ListView中字母索引的简单代码,它使用了2个java程序文件

1.The MainActivity file where we handling the indexing of listview

1.我们处理listview索引的MainActivity文件

2.The CustomAdapter.java file which is the subclass of BaseAdapter for listing the elements.

2.CustomAdapter.java 文件,它是 BaseAdapter 的子类,用于列出元素。

MainActivity.java

public class MainActivity extends Activity implements View.OnClickListener
{
    private Map<String, Integer> mapIndex;
    private String[] fruits;
    private ListView fruitsList;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        fruitsList.setAdapter(new CustomAdapter(this, Arrays.asList(fruits)));

        getIndexList(fruits);
        displayIndex();
    }

    private void init()
    {
        fruitsList = (ListView)findViewById(R.id.list_fruits);
        fruits = getResources().getStringArray(R.array.fruits_array);
        Arrays.sort(fruits);
    }

    private void getIndexList(String[] fruits)
    {
        mapIndex = new LinkedHashMap<String, Integer>();
        for(int i=0; i<fruits.length; i++)
        {
            String fruit = fruits[i];
            String index = fruit.substring(0,1);

            if(mapIndex.get(index) == null)
                mapIndex.put(index, i);
        }
    }

    private void displayIndex()
    {
        LinearLayout indexLayout = (LinearLayout)findViewById(R.id.side_index);
        List<String> indexList = new ArrayList<String>(mapIndex.keySet());

        TextView textView;
        for(String index : indexList)
        {
            textView = (TextView) getLayoutInflater().inflate(R.layout.alphabetindicator, null);
            textView.setText(index);
            textView.setOnClickListener(this);
            indexLayout.addView(textView);
        }
    }

    @Override
    public void onClick(View v) {
        TextView selectedTextView  = (TextView) v;
        fruitsList.setSelection(mapIndex.get(selectedTextView.getText()));
    }
}

CustomAdaper.java

自定义适配器.java

public class CustomAdapter extends BaseAdapter
{
    private Context context;
    private List<String> listItem;
    private LayoutInflater layoutInflater;

    CustomAdapter(Context context, List<String> listItem) {
        this.context = context;
        this.listItem = listItem;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.indexindicator, parent, false);
            viewHolder.textView = (TextView) convertView.findViewById(R.id.listitem);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(listItem.get(position));
        return convertView;
    }

    static class ViewHolder {
        TextView textView;
    }

    @Override
    public int getCount() {
        return listItem.size();
    }

    @Override
    public Object getItem(int position) {
        return listItem.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }
}

activity_main.xml

活动_main.xml

<LinearLayout>
    <ListView
        android:id="@+id/list_fruits"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:scrollbars="none">
    </ListView>

    <LinearLayout
        android:id="@+id/side_index"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:background="@color/white"
        android:gravity="center_horizontal"
        android:orientation="vertical" >
    </LinearLayout>
</LinearLayout>

alphabetIndicator.xml

字母指示器.xml

<?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/side_list_item"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:padding="3dp"
        android:textSize="14sp" />

IndexIndicator.xml

索引指示器.xml

<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/listitem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="left"
        android:padding="3dp"
        android:textColor="#000000"
        android:textSize="14sp" />
</LinearLayout>

Finally, Include a string array in strings.xml file (Replace / Increase the item based on your needs)

最后,在strings.xml文件中包含一个字符串数组(根据需要替换/增加项目)

<string-array name="fruits_array">
        <item>Cantalope</item>
        <item>Date</item>
        <item>Grape</item>
        <item>Gooseberry</item>
        <item>Guava</item>
        <item>Honeydew melon</item>
        <item>Elderberry</item>
        <item>Fig</item>
        <item>Grapefruit</item>
</string-array>

回答by Samet

In fact it is really simple to do. Here is how I've done it in my app. You can add your proper parameters, it is simple and easy to understand.

其实做起来真的很简单。这是我在我的应用程序中完成它的方式。您可以添加适当的参数,简单易懂。

// charsContainer is a linear layout which contains all your characters that you will touch on. They fit automatically in the linear layout so they are all visible because of the weight value you associate on chars TextView later

// charsContainer 是一个线性布局,其中包含您将要接触的所有字符。它们自动适合线性布局,因此它们都可见,因为您稍后在字符 TextView 上关联的权重值

final LinearLayout charsContainer = (LinearLayout) findViewById(R.id.charsContainer);

// alphabetical_index is a framelayout which contains charsContainer and alphabetical_index_indicator, this is for the indicator to be visible over selected character.

final FrameLayout alphabetical_index = (FrameLayout) findViewById(R.id.alphabetical_index);

// alphabetical_index_indicator is an image displayed when your finger touches a character and move up and down 

final ImageView alphabetical_index_indicator = (ImageView) findViewById(R.id.alphabetical_index_indicator);

for (int i = 0; i < chars.size() ; i++) {

    TextView charTextView = new TextView(this);
    charTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 0, 1));
    charTextView.setText(chars.get(i).toString());
    charTextView.setTextColor(Color.GRAY);
    charTextView.setTextSize(11);
    charTextView.setPadding(convertValueToDP(4), 0, convertValueToDP(4), 0);
    charsContainer.addView(charTextView);


}

alphabetical_index.setOnTouchListener(new View.OnTouchListener() {

    @Override

    public boolean onTouch(View v, MotionEvent event) {

        int alphabetical_index_top = (int) alphabetical_index.getTop();
        int alphabetical_index_bottom = (int) alphabetical_index.getBottom();

        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);

        if(hasBackKey || hasHomeKey){
            alphabetical_index_bottom = ((int) alphabetical_index.getY()) + alphabetical_index.getHeight();
        }else{
            alphabetical_index_bottom = ((int) alphabetical_index.getY()) + alphabetical_index.getHeight() - convertValueToDP(36);
        }

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:

                // Do
                getListView().setVerticalScrollBarEnabled(false);
                break;

            case MotionEvent.ACTION_MOVE:

                int x = (int) event.getX();
                int y = (int) event.getY();

                if(alphabetical_index_indicator.getVisibility() == View.GONE){
                    alphabetical_index_indicator.setVisibility(View.VISIBLE);
                    getListView().setVerticalScrollBarEnabled(false);
                    Animation anim = AnimationUtils.loadAnimation(MyActivity.this, R.anim.fadein);
                    alphabetical_index_indicator.startAnimation(anim);
                }

                if (y > alphabetical_index_top && (y - charsContainer.getChildAt(0).getHeight()) > alphabetical_index_top && y < alphabetical_index_bottom) {
                    alphabetical_index_indicator.setY(y - charsContainer.getChildAt(0).getHeight());
                }
                for (int i = 0; i < charsContainer.getChildCount(); i++) {

                    View child = charsContainer.getChildAt(i);

                    if (y > child.getTop() && y < child.getBottom()) {

                        Character character = ((TextView) child).getText().toString().charAt(0);

                        for (int j = 0; i < listViewStringArray.size(); j++) {
                            if (listViewStringArray.get(j).toUpperCase(Locale.getDefault()).charAt(0) == character) {
                                getListView().setSelection(j);
                                break;
                            }
                        }

                    }

                }

                // Do
                break;

            case MotionEvent.ACTION_CANCEL:
                // Do
                getListView().setVerticalScrollBarEnabled(true);
                break;

            case MotionEvent.ACTION_UP:

                Animation anim = AnimationUtils.loadAnimation(MyActivity.this,R.anim.fadeout);
                anim.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {

                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        alphabetical_index_indicator.setVisibility(View.GONE);
                        getListView().setVerticalScrollBarEnabled(true);
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {

                    }
                });
                alphabetical_index_indicator.startAnimation(anim);

                break;
        }
        return true;
    }
});


public static int convertValueToDP(float dp){

    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return (int)px;
}