快速滚动大字母拇指预览未出现
Posted
技术标签:
【中文标题】快速滚动大字母拇指预览未出现【英文标题】:Fast scroll large letter thumb preview not appearing 【发布时间】:2015-09-28 01:58:26 【问题描述】:我试图让包含大字母的快速滚动弹出窗口在我的列表中出现快速滚动功能时出现(如下图所示),但由于某种原因它不会出现。我已经查阅了各种教程,但它似乎仍然不起作用 + 我不确定是否缺少代码或某些代码位于错误的位置。我们将不胜感激。
strings.xml
<resources>
<string name="app_name">World</string>
<string name="action_search">Search</string>
<string name="search_hint">Continent name</string>
<string name="item0">Azerbaijan</string>
<string name="item1">Bosnia & Herzegovina</string>
<string name="item2">Brazil</string>
<string name="item3">China</string>
<string name="item4">Denmark</string>
<string name="item5">France</string>
<string name="item6">Hungary</string>
<string name="item7">Italy</string>
<string name="item8">Japan</string>
<string name="item9">Lithuania</string>
<string name="item10">Luxembourg</string>
<string name="item11">Malta</string>
<string name="item12">Monaco</string>
<string name="item13">Norway</string>
<string name="item14">Portugal</string>
<string name="item15">Thailand</string>
<string name="item16">Singapore</string>
<string name="item17">South Korea</string>
<string name="item18">Sweden</string>
<string name="item19">United Kingdom</string>
<string name="item20">United States</string>
<string name="item0_description">Item 0 description</string>
<string name="item1_description">Item 1 description</string>
<string name="item2_description">Item 2 description</string>
<string name="item3_description">Item 3 description</string>
<string name="item4_description">Item 4 description</string>
<string name="item5_description">Item 5 description</string>
<string name="item6_description">Item 6 description</string>
<string name="item7_description">Item 7 description</string>
<string name="item8_description">Item 8 description</string>
<string name="item9_description">Item 9 description</string>
<string name="item10_description">Item 10 description</string>
<string name="item11_description">Item 11 description</string>
<string name="item12_description">Item 12 description</string>
<string name="item13_description">Item 13 description</string>
<string name="item14_description">Item 14 description</string>
<string name="item15_description">Item 15 description</string>
<string name="item16_description">Item 16 description</string>
<string name="item17_description">Item 17 description</string>
<string name="item18_description">Item 18 description</string>
<string name="item19_description">Item 19 description</string>
<string name="item20_description">Item 20 description</string>
<string-array name="items">
//item 0 <item>@string/item0</item>
//item 1 <item>@string/item1</item>
//item 2 <item>@string/item2</item>
//item 3 <item>@string/item3</item>
//item 4 <item>@string/item4</item>
//item 5 <item>@string/item5</item>
//item 6 <item>@string/item6</item>
//item 7 <item>@string/item7</item>
//item 8 <item>@string/item8</item>
//item 9 <item>@string/item9</item>
//item 10 <item>@string/item10</item>
//item 11 <item>@string/item11</item>
//item 12 <item>@string/item12</item>
//item 13 <item>@string/item13</item>
//item 14 <item>@string/item14</item>
//item 15 <item>@string/item15</item>
//item 16 <item>@string/item16</item>
//item 17 <item>@string/item17</item>
//item 18 <item>@string/item18</item>
//item 19 <item>@string/item19</item>
//item 20 <item>@string/item20</item>
</string-array>
<string-array name="item_descriptions">
//item 0 <item>@string/item0_description</item>
//item 1 <item>@string/item1_description</item>
//item 2 <item>@string/item2_description</item>
//item 3 <item>@string/item3_description</item>
//item 4 <item>@string/item4_description</item>
//item 5 <item>@string/item5_description</item>
//item 6 <item>@string/item6_description</item>
//item 7 <item>@string/item7_description</item>
//item 8 <item>@string/item8_description</item>
//item 9 <item>@string/item9_description</item>
//item 10 <item>@string/item10_description</item>
//item 11 <item>@string/item11_description</item>
//item 12 <item>@string/item12_description</item>
//item 13 <item>@string/item13_description</item>
//item 14 <item>@string/item14_description</item>
//item 15 <item>@string/item15_description</item>
//item 16 <item>@string/item16_description</item>
//item 17 <item>@string/item17_description</item>
//item 18 <item>@string/item18_description</item>
//item 19 <item>@string/item19_description</item>
//item 20 <item>@string/item20_description</item>
</string-array>
</resources>
FragmentCountries.java
public class FragmentCountries extends ListFragment implements SearchView.OnQueryTextListener
private CountriesListAdapter mAdapter;
public FragmentCountries()
// Required empty constructor
public static FragmentCountries newInstance()
return new FragmentCountries();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
View view = inflater.inflate(R.layout.fragment_countries, container, false);
setHasOptionsMenu(true);
initialize(view);
return view;
List<Countries> list = new ArrayList<Countries>();
private void initialize(View view)
String[] items = getActivity().getResources().getStringArray(R.array.country_names);
String[] itemDescriptions = getActivity().getResources().getStringArray(R.array.country_descriptions);
for (int n = 0; n < items.length; n++)
Countries countries = new Countries();
countries.setID();
countries.setName(items[n]);
countries.setDescription(itemDescriptions[n]);
list.add(countries);
mAdapter = new CountriesListAdapter(list, getActivity());
setListAdapter(mAdapter);
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
// Set up search view
inflater.inflate(R.menu.menu_countries, menu);
MenuItem item = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setIconifiedByDefault(true);
searchView.clearAnimation();
searchView.setOnQueryTextListener(this);
searchView.setQueryHint(getResources().getString(R.string.search_hint));
View close = searchView.findViewById(R.id.search_close_btn);
close.setBackgroundResource(R.drawable.ic_action_content_clear);
@Override
public boolean onQueryTextSubmit(String newText)
return false;
@Override
public boolean onQueryTextChange(String newText)
mAdapter.getFilter().filter(newText);
return false;
@Override
public int getPositionForSection(int section)
return alphaIndexer.get(sections[section]);
@Override
public int getSectionForPosition(int position)
return 0;
@Override
public Object[] getSections()
return sections;
CountriesListAdapter.java
public class CountriesListAdapter extends BaseAdapter implements Filterable, SectionIndexer
private String mSections = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private List<Countries> mData;
private List<Countries> mFilteredData;
private LayoutInflater mInflater;
private ItemFilter mFilter;
public CountriesListAdapter (List<Countries> data, Context context)
mData = data;
mFilteredData = new ArrayList(mData);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@Override
public int getCount()
return mFilteredData.size();
@Override
public String getItem(int position)
return mFilteredData.get(position).getName();
@Override
public long getItemId(int position)
return position;
@Override
public View getView(int position, View convertView, ViewGroup parent)
ViewHolder holder;
if (convertView == null)
convertView = mInflater.inflate(R.layout.list_item_dualline, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.item_name);
holder.description = (TextView) convertView.findViewById(R.id.item_description);
convertView.setTag(holder);
else
holder = (ViewHolder) convertView.getTag();
holder.title.setText(mFilteredData.get(position).getName());
holder.description.setText(mFilteredData.get(position).getDescription());
return convertView;
@Override
public Filter getFilter()
if (mFilter == null)
mFilter = new ItemFilter();
return mFilter;
/**
* View holder
*/
static class ViewHolder
private TextView title;
private TextView description;
private class ItemFilter extends Filter
@Override
protected FilterResults performFiltering(CharSequence constraint)
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint))
results.count = mData.size();
results.values = new ArrayList(mData);
else
//Create a new list to filter on
List<Countries> resultList = new ArrayList<Countries>();
for (Countries str : mData)
if (str.getName().toLowerCase().contains(constraint.toString().toLowerCase()))
resultList.add(str);
results.count = resultList.size();
results.values = resultList;
return results;
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
if (results.count == 0)
mFilteredData.clear();
notifyDataSetInvalidated();
else
mFilteredData = (ArrayList<Countries>)results.values;
notifyDataSetChanged();
@Override
public int getPositionForSection(int section)
return alphaIndexer.get(sections[section]);
@Override
public int getSectionForPosition(int position)
return 0;
@Override
public Object[] getSections()
String[] sections = new String[mSections.length()];
for (int i = 0; i < mSections.length(); i++)
sections[i] = String.valueOf(mSections.charAt(i));
return sections;
Main.java
public class Main
public Main()
private String continent;
private String description;
private boolean selected;
public String getContinent()
return continent;
public void setContinent(String continent)
this.continent = continent;
public String getDescription()
return description;
public void setDescription(String description)
this.description = description;
private int _id;
public void getID(int _id)
this._id = _id;
public int setID()
return _id;
public boolean isSelected()
return selected;
public void setSelected(boolean selected)
this.selected = selected;
drawable/orange_fastscroll_thumb.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="44dp"
android:topRightRadius="44dp"
android:bottomLeftRadius="44dp" />
<padding
android:paddingLeft="22dp"
android:paddingRight="22dp" />
<solid android:color="@color/orange" />
</shape>
清单
<activity
android:name="OrangeActivity"
android:label="@string/orange_title"
android:theme="@style/OrangeTheme" >
</activity>
<style name="OrangeTheme" parent="AppBaseTheme">
<item name="android:fastScrollThumbDrawable">@drawable/orange_fastscroll_thumb</item>
<item name="android:fastScrollOverlayPosition">atThumb</item>
<item name="android:fastScrollTextColor">@color/white</item>
<item name="android:fastScrollTrackDrawable">@drawable/fastscroll_thumb_pressed</item>
</style>
xml 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical"
android:id="@+id/fragmentorange">
<ListView
android:id="@android:id/list"
android:layout_
android:layout_
android:fastScrollEnabled="true"
android:scrollbarStyle="outsideInset">
</ListView>
<TextView
android:layout_
android:layout_
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/no_results"
android:visibility="invisible"
android:gravity="center_horizontal"
android:id="@android:id/empty"
android:layout_marginTop="100dp"
android:textColor="@color/white"/>
</LinearLayout>
MainListAdapter
public class MainListAdapter extends BaseAdapter implements Filterable, SectionIndexer
private List<Main> mData;
private List<Main> mFilteredData;
private LayoutInflater mInflater;
private ItemFilter mFilter;
private Object[] mSections;
private int[] mSectionsIndexedByPosition;
private int[] mPositionsIndexedBySection;
public MainListAdapter (List<Main> data, Context context)
mData = data;
mFilteredData = new ArrayList(mData);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setupSections();
@Override
public int getCount()
return mFilteredData.size();
@Override
public Main getItem(int position)
return mFilteredData.get(position);
@Override
public long getItemId(int position)
return position;
@Override
public View getView(int position, View convertView, ViewGroup parent)
ViewHolder holder;
if (convertView == null)
convertView = mInflater.inflate(R.layout.list_item, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.item);
holder.description = (TextView) convertView.findViewById(R.id.item_description);
convertView.setTag(holder);
else
holder = (ViewHolder) convertView.getTag();
Main main = getItem(position);
holder.title.setText(main.getContinent());
holder.description.setText(main.getDescription());
if (main.isSelected())
convertView.setBackgroundColor(Color.parseColor("#1C3F96"));
holder.title.setTextColor(Color.parseColor("#FFFFFF"));
holder.description.setTextColor(Color.parseColor("#FFFFFF"));
else
convertView.setBackgroundColor(Color.TRANSPARENT);
holder.title.setTextColor(Color.parseColor("#FFFFFF"));
holder.description.setTextColor(Color.parseColor("#B5B5B5"));
holder.title.setText(mFilteredData.get(position).getContinent());
holder.description.setText(mFilteredData.get(position).getDescription());
return convertView;
@Override
public Filter getFilter()
if (mFilter == null)
mFilter = new ItemFilter();
return mFilter;
/**
* View holder
*/
static class ViewHolder
private TextView title;
private TextView description;
/**
* Filter for filtering list items
*/
/**
* <p>An array filter constrains the content of the array adapter with
* a prefix. Each item that does not start with the supplied prefix
* is removed from the list.</p>
*/
private class ItemFilter extends Filter
@Override
protected FilterResults performFiltering(CharSequence constraint)
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint))
results.count = mData.size();
results.values = new ArrayList(mData);
else
//Create a new list to filter on
List<Main> resultList = new ArrayList<Main>();
for (Main str : mData)
if (str.getContinent().toLowerCase().contains(constraint.toString().toLowerCase()))
resultList.add(str);
results.count = resultList.size();
results.values = resultList;
return results;
/**
* Runs on ui thread
* @param constraint the constraint used for the result
* @param results the results to display
*/
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results)
if (results.count == 0)
mFilteredData.clear();
notifyDataSetInvalidated();
else
mFilteredData = (ArrayList<Main>)results.values;
notifyDataSetChanged();
setupSections();
@Override
public int getPositionForSection(int section)
return mPositionsIndexedBySection[section];
@Override
public int getSectionForPosition(int position)
return mSectionsIndexedByPosition[position];
@Override
public Object[] getSections()
return mSections;
private void setupSections()
String initial = "\0";
List<String> sections = new ArrayList<String>();
mSectionsIndexedByPosition = new int[mFilteredData.size()];
mPositionsIndexedBySection = new int[mFilteredData.size()]; // yes it's bigger than necessary
int section = 0;
for (int pos = 0; pos < mFilteredData.size(); pos++)
Main country = mFilteredData.get(pos);
if (initial.charAt(0) != country.getContinent().charAt(0))
initial = country.getContinent().substring(0, 1);
sections.add(initial);
mPositionsIndexedBySection[section] = pos;
mSectionsIndexedByPosition[pos] = section;
section++;
else
mSectionsIndexedByPosition[pos] = section;
mSections = sections.toArray();
mPositionsIndexedBySection = Arrays.copyOf(mPositionsIndexedBySection, section);
【问题讨论】:
你永远不会分配alphaIndexer
...
忘记这个...让 CountryListAdapter 实现 SectionIndexer ... 现在 getSections()
应该返回 String[] "*", "A" ,... "Z" ... getSectionForPosition
应该根据项目数据返回字母的索引(由 getSections() 返回的数组中 mFilteredData.get(position).getName()[0] 的索引 ... 和 getPositionForSection ... 你应该在 mFilteredData 返回索引第一个带字母的国家出现在哪里
@Selvin 我已经在适配器类中获得了implements Filterable
,那么我应该如何包含implements SectionIndexer
呢?
implements SectionIndexer
而不是, SectionIndexer
但是是的......然后会有困难的部分实施......但我在上一篇评论中给了你一些提示......你可以做它(看起来像一个基本的编程练习)
@Selvin 我已经更新了我的代码
【参考方案1】:
将MainListAdapter
中的setupSections()
替换为以下代码:
private void setupSections()
String initial = "\0";
List<String> sections = new ArrayList<String>();
mSectionsIndexedByPosition = new int[mFilteredData.size()];
mPositionsIndexedBySection = new int[mFilteredData.size()];
int section = 0;
for (int pos = 0; pos < mFilteredData.size(); pos++)
Main country = mFilteredData.get(pos);
if (initial.charAt(0) != country.getContinent().charAt(0))
initial = country.getContinent().substring(0, 1);
section = sections.size();
sections.add(initial);
mPositionsIndexedBySection[section] = pos;
mSectionsIndexedByPosition[pos] = section;
else
mSectionsIndexedByPosition[pos] = section;
mSections = sections.toArray();
mPositionsIndexedBySection = Arrays.copyOf(mPositionsIndexedBySection, mSections.length);
关于索引字母的背景,您将 预览背景 与 thumb 混淆了。拇指是沿轨道移动的元素。您调用orange_fastscroll_thumb.xml
的文件实际上是预览背景而不是拇指。如果你把名字改成orange_fastscroll_preview_bg
,你可以这样设置:
<style name="OrangeTheme" parent="AppTheme">
<item name="android:fastScrollPreviewBackgroundRight">@drawable/orange_fastscroll_preview_bg</item>
<item name="android:fastScrollOverlayPosition">atThumb</item>
</style>
显然,谷歌编码快速滚动代码的方式,你不能直接设置拇指和轨道的样式。您可以在this question.中尝试一些建议
【讨论】:
好的,现在我看到你夸大了一个视图,你是说它有一个 ListView? ListFragment 已经拥有自己的 ListView,您可以在其中设置适配器。您应该做的是扩展 Fragment 而不是 ListFragment 并将适配器设置在正确的 ListView 上。 请更改您的答案以更好地回答问题 使用您的代码后return mFilteredData.get(position).getContinent();
变为红色下划线并返回此错误:Required: 'com.apptacularapps.world.data.Main' Found: 'java.lang.String'
Main.java 类已添加。截图:tiikoni.com/tis/view/?id=f790a24
那是因为getContinent()
返回一个字符串,但是你定义getItem()
返回Main
。要么将public Main getItem(int position)
更改为public String getItem(int position)
- 要么-- 通过取消getContinent()
将return mFilteredData.get(position).getContinent();
更改为return mFilteredData.get(position);
您的第二个建议是我做的,因为它是更好的选择,但是在部署期间滚动列表后,我在public int getPositionForSection(int section)
中收到return mPositionsIndexedBySection[section];
这一行的java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 at com.apptacularapps.world.adapters.MainListAdapter.getPositionForSection(MainListAdapter.java:160)
错误以上是关于快速滚动大字母拇指预览未出现的主要内容,如果未能解决你的问题,请参考以下文章