- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
背景
我试图模仿 Lollipop 的联系人应用程序显示联系人首字母的固定标题的方式,正如我所写的 here .
问题
由于原始代码(位于“PinnedHeaderListViewSample”文件夹中的 here 中)没有显示除英文以外的字母,因此我不得不稍微更改代码,但这还不够。标题本身也是如此,它现在必须在左侧,而不是在行上方。
一切正常,直到我在 RTL 语言(在我的情况下是希伯来语)上对其进行了测试,而设备的语言环境也更改为 RTL 语言(在我的情况下是希伯来语)。
出于某种原因,滚动和标题本身都变得非常奇怪,奇怪的是它发生在某些设备/版本的 Android 上。
例如,在带有 Kitkat 的 Galaxy S3 上,滚动和滚动条完全错误(我滚动到顶部,但滚动条的位置在中间)。
在装有 Android 4.2.2 的 LG G2 上,它也有这个问题,但它也没有显示标题(固定标题除外),尤其是希伯来语中的标题。
在 Galaxy S4 和 Huwawei Ascend P7(都运行 Kitkat)上,无论我做什么,一切正常。
简而言之,特殊情况是:
"אאא",
"בבב",
listView.setFastScrollEnabled(true);
public NamesAdapter(Context context, int resourceId, int textViewResourceId, String[] objects) {
super(context, resourceId, textViewResourceId, objects);
final SortedSet<Character> set = new TreeSet<Character>();
for (final String string : objects) {
final String trimmed = string == null ? "" : string.trim();
if (!TextUtils.isEmpty(trimmed))
set.add(Character.toUpperCase(trimmed.charAt(0)));
else
set.add(' ');
}
final StringBuilder sb = new StringBuilder();
for (final Character character : set)
sb.append(character);
this.mIndexer = new StringArrayAlphabetIndexer(objects, sb.toString());
}
public int getSectionForPosition(int position) {
try {
if (mArray == null || mArray.length == 0)
return 0;
final String curName = mArray[position];
// Linear search, as there are only a few items in the section index
// Could speed this up later if it actually gets used.
// TODO use binary search
for (int i = 0; i < mAlphabetLength; ++i) {
final char letter = mAlphabet.charAt(i);
if (TextUtils.isEmpty(curName) && letter == ' ')
return i;
final String targetLetter = Character.toString(letter);
if (compare(curName, targetLetter) == 0)
return i;
}
return 0; // Don't recognize the letter - falls under zero'th section
} catch (final Exception ex) {
return 0;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/list_item_header" />
<include
layout="@android:layout/simple_list_item_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp" />
</FrameLayout>
<View
android:id="@+id/list_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@android:drawable/divider_horizontal_dark" />
</LinearLayout>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/header_text"
android:layout_width="25dip"
android:layout_height="25dip"
android:textStyle="bold"
android:background="@color/pinned_header_background"
android:textColor="@color/pinned_header_text"
android:textSize="14sp"
android:paddingLeft="6dip"
android:gravity="center" />
http://developer.android.com/training/contacts-provider/retrieve-names.html
最佳答案
好的,我不知道谷歌在那里做了什么,因为代码非常不可读,所以我自己做了一个类,它工作正常。
您必须记住的唯一一件事是在将项目发送到我的类(class)之前对其进行排序,如果您希望标题只有大写字母,则必须相应地对项目进行排序(以便所有以特定字母开头的项目将在同一个 block 中,不管它是否大写)。
该解决方案在 GitHub 上可用,这里:
https://github.com/AndroidDeveloperLB/ListViewVariants
这是代码:
StringArrayAlphabetIndexer
public class StringArrayAlphabetIndexer extends SectionedSectionIndexer
{
/**
* @param items each of the items. Note that they must be sorted in a way that each chunk will belong to
* a specific header. For example, chunk with anything that starts with "A"/"a", then a chunk
* that all of its items start with "B"/"b" , etc...
* @param useOnlyUppercaseHeaders whether the header will be in uppercase or not.
* if true, you must order the items so that each chunk will have its items start with either the lowercase or uppercase letter
*/
public StringArrayAlphabetIndexer(String[] items,boolean useOnlyUppercaseHeaders)
{
super(createSectionsFromStrings(items,useOnlyUppercaseHeaders));
}
private static SimpleSection[] createSectionsFromStrings(String[] items,boolean useOnlyUppercaseHeaders)
{
//get all of the headers of the sections and their sections-items:
Map<String,ArrayList<String>> headerToSectionItemsMap=new HashMap<String,ArrayList<String>>();
Set<String> alphabetSet=new TreeSet<String>();
for(String item : items)
{
String firstLetter=TextUtils.isEmpty(item)?" ":useOnlyUppercaseHeaders?item.substring(0,1).toUpperCase(Locale.getDefault()):
item.substring(0,1);
ArrayList<String> sectionItems=headerToSectionItemsMap.get(firstLetter);
if(sectionItems==null)
headerToSectionItemsMap.put(firstLetter,sectionItems=new ArrayList<String>());
sectionItems.add(item);
alphabetSet.add(firstLetter);
}
//prepare the sections, and also sort each section's items :
SimpleSection[] sections=new SimpleSection[alphabetSet.size()];
int i=0;
for(String headerTitle : alphabetSet)
{
ArrayList<String> sectionItems=headerToSectionItemsMap.get(headerTitle);
SimpleSection simpleSection=new AlphaBetSection(sectionItems);
simpleSection.setName(headerTitle);
sections[i++]=simpleSection;
}
return sections;
}
public static class AlphaBetSection extends SimpleSection
{
private ArrayList<String> items;
private AlphaBetSection(ArrayList<String> items)
{
this.items=items;
}
@Override
public int getItemsCount()
{
return items.size();
}
@Override
public String getItem(int posInSection)
{
return items.get(posInSection);
}
}
}
public class SectionedSectionIndexer implements SectionIndexer {
private final SimpleSection[] mSectionArray;
public SectionedSectionIndexer(final SimpleSection[] sections) {
mSectionArray = sections;
//
int previousIndex = 0;
for (int i = 0; i < mSectionArray.length; ++i) {
mSectionArray[i].startIndex = previousIndex;
previousIndex += mSectionArray[i].getItemsCount();
mSectionArray[i].endIndex = previousIndex - 1;
}
}
@Override
public int getPositionForSection(final int section) {
final int result = section < 0 || section >= mSectionArray.length ? -1 : mSectionArray[section].startIndex;
return result;
}
/** given a flat position, returns the position within the section */
public int getPositionInSection(final int flatPos) {
final int sectionForPosition = getSectionForPosition(flatPos);
final SimpleSection simpleSection = mSectionArray[sectionForPosition];
return flatPos - simpleSection.startIndex;
}
@Override
public int getSectionForPosition(final int flatPos) {
if (flatPos < 0)
return -1;
int start = 0, end = mSectionArray.length - 1;
int piv = (start + end) / 2;
while (true) {
final SimpleSection section = mSectionArray[piv];
if (flatPos >= section.startIndex && flatPos <= section.endIndex)
return piv;
if (piv == start && start == end)
return -1;
if (flatPos < section.startIndex)
end = piv - 1;
else
start = piv + 1;
piv = (start + end) / 2;
}
}
@Override
public SimpleSection[] getSections() {
return mSectionArray;
}
public Object getItem(final int flatPos) {
final int sectionIndex = getSectionForPosition(flatPos);
final SimpleSection section = mSectionArray[sectionIndex];
final Object result = section.getItem(flatPos - section.startIndex);
return result;
}
public Object getItem(final int sectionIndex, final int positionInSection) {
final SimpleSection section = mSectionArray[sectionIndex];
final Object result = section.getItem(positionInSection);
return result;
}
public int getRawPosition(final int sectionIndex, final int positionInSection) {
final SimpleSection section = mSectionArray[sectionIndex];
return section.startIndex + positionInSection;
}
public int getItemsCount() {
if (mSectionArray.length == 0)
return 0;
return mSectionArray[mSectionArray.length - 1].endIndex + 1;
}
// /////////////////////////////////////////////
// Section //
// //////////
public static abstract class SimpleSection {
private String name;
private int startIndex, endIndex;
public SimpleSection() {
}
public SimpleSection(final String sectionName) {
this.name = sectionName;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public abstract int getItemsCount();
public abstract Object getItem(int posInSection);
@Override
public String toString()
{
return name;
}
}
}
public abstract class BasePinnedHeaderListViewAdapter extends BaseAdapter implements SectionIndexer, OnScrollListener,
PinnedHeaderListView.PinnedHeaderAdapter
{
private SectionIndexer _sectionIndexer;
private boolean mHeaderViewVisible = true;
public void setSectionIndexer(final SectionIndexer sectionIndexer) {
_sectionIndexer = sectionIndexer;
}
/** remember to call bindSectionHeader(v,position); before calling return */
@Override
public abstract View getView(final int position, final View convertView, final ViewGroup parent);
public abstract CharSequence getSectionTitle(int sectionIndex);
protected void bindSectionHeader(final TextView headerView, final View dividerView, final int position) {
final int sectionIndex = getSectionForPosition(position);
if (getPositionForSection(sectionIndex) == position) {
final CharSequence title = getSectionTitle(sectionIndex);
headerView.setText(title);
headerView.setVisibility(View.VISIBLE);
if (dividerView != null)
dividerView.setVisibility(View.GONE);
} else {
headerView.setVisibility(View.GONE);
if (dividerView != null)
dividerView.setVisibility(View.VISIBLE);
}
// move the divider for the last item in a section
if (dividerView != null)
if (getPositionForSection(sectionIndex + 1) - 1 == position)
dividerView.setVisibility(View.GONE);
else
dividerView.setVisibility(View.VISIBLE);
if (!mHeaderViewVisible)
headerView.setVisibility(View.GONE);
}
@Override
public int getPinnedHeaderState(final int position) {
if (_sectionIndexer == null || getCount() == 0 || !mHeaderViewVisible)
return PINNED_HEADER_GONE;
if (position < 0)
return PINNED_HEADER_GONE;
// The header should get pushed up if the top item shown
// is the last item in a section for a particular letter.
final int section = getSectionForPosition(position);
final int nextSectionPosition = getPositionForSection(section + 1);
if (nextSectionPosition != -1 && position == nextSectionPosition - 1)
return PINNED_HEADER_PUSHED_UP;
return PINNED_HEADER_VISIBLE;
}
public void setHeaderViewVisible(final boolean isHeaderViewVisible) {
mHeaderViewVisible = isHeaderViewVisible;
}
public boolean isHeaderViewVisible() {
return this.mHeaderViewVisible;
}
@Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount,
final int totalItemCount) {
((PinnedHeaderListView) view).configureHeaderView(firstVisibleItem);
}
@Override
public void onScrollStateChanged(final AbsListView arg0, final int arg1) {
}
@Override
public int getPositionForSection(final int sectionIndex) {
if (_sectionIndexer == null)
return -1;
return _sectionIndexer.getPositionForSection(sectionIndex);
}
@Override
public int getSectionForPosition(final int position) {
if (_sectionIndexer == null)
return -1;
return _sectionIndexer.getSectionForPosition(position);
}
@Override
public Object[] getSections() {
if (_sectionIndexer == null)
return new String[] { " " };
return _sectionIndexer.getSections();
}
@Override
public long getItemId(final int position) {
return position;
}
}
public abstract class IndexedPinnedHeaderListViewAdapter extends BasePinnedHeaderListViewAdapter
{
private int _pinnedHeaderBackgroundColor;
private int _pinnedHeaderTextColor;
public void setPinnedHeaderBackgroundColor(final int pinnedHeaderBackgroundColor)
{
_pinnedHeaderBackgroundColor=pinnedHeaderBackgroundColor;
}
public void setPinnedHeaderTextColor(final int pinnedHeaderTextColor)
{
_pinnedHeaderTextColor=pinnedHeaderTextColor;
}
@Override
public CharSequence getSectionTitle(final int sectionIndex)
{
return getSections()[sectionIndex].toString();
}
@Override
public void configurePinnedHeader(final View v,final int position,final int alpha)
{
final TextView header=(TextView)v;
final int sectionIndex=getSectionForPosition(position);
final Object[] sections=getSections();
if(sections!=null&§ions.length!=0)
{
final CharSequence title=getSectionTitle(sectionIndex);
header.setText(title);
}
if(VERSION.SDK_INT<VERSION_CODES.HONEYCOMB)
if(alpha==255)
{
header.setBackgroundColor(_pinnedHeaderBackgroundColor);
header.setTextColor(_pinnedHeaderTextColor);
}
else
{
header.setBackgroundColor(Color.argb(alpha,Color.red(_pinnedHeaderBackgroundColor),
Color.green(_pinnedHeaderBackgroundColor),Color.blue(_pinnedHeaderBackgroundColor)));
header.setTextColor(Color.argb(alpha,Color.red(_pinnedHeaderTextColor),
Color.green(_pinnedHeaderTextColor),Color.blue(_pinnedHeaderTextColor)));
}
else
{
header.setBackgroundColor(_pinnedHeaderBackgroundColor);
header.setTextColor(_pinnedHeaderTextColor);
header.setAlpha(alpha/255.0f);
}
}
}
关于android - PinnedHeaderListView 滚动和标题问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27676367/
如果附加了 'not-scroll' 类,我希望我的 body 不滚动,否则它应该正常工作。 我已经搜索这个问题两天了,但找不到任何适合我的解决方案。 我想要的是向 body 添加一个 class,并
我发现似乎是 iOS Safari 中的错误(我正在 iOS 8 上进行测试)。当绝对定位的 iFrame 漂浮在一段可滚动内容上方时,滚动 iFrame 也会滚动下面的内容。以下 HTML (ava
我有以下代码来显示一系列投资组合图片,这些图片以 SVG 格式存储在滚动 div 中: 在 Safari 中滚动使用两根手指或鼠标滚轮当光标位于 SVG 之一上时不起作用。 该页
我想用 javascript 做的是: 一旦你向下滚动页面,将#sidebar-box-fixed 的位置从 position: relative; 更改为定位:固定;。改回position:rela
我对 Elasticsearch 的滚动功能有点困惑。在 elasticsearch 中,每当用户在结果集上滚动时,是否可以每次调用搜索 API?来自文档 "search_type" => "scan
我试图做到这一点,以便当我向上或向下滚动页面时,它会运行不同的相应功能。我发现了一个类似的问题here但我已经尝试了他们的答案并且没有运气。 注意:此页面没有正常显示的滚动条。没有地方可以滚动。 bo
(C语言,GTK库) 在我的表单上,我有一个 GtkDrawingArea 小部件,我在上面使用 Cairo 绘制 GdkPixbufs(从文件加载)。我想要完成的是能够在窗口大小保持固定的情况下使用
最近我一直在尝试创建一个拉到(刷新,加载更多)swiftUI ScrollView !!,灵感来自 https://cocoapods.org/pods/SwiftPullToRefresh 我正在努
我正在开发一个应用程序,其中有两个带有可放置区域的列表和一个带有可拖动项目的侧面菜单。 当我滚动屏幕时,项目的位置困惑。 我试图在谷歌上寻找一些东西,最后得到了这个问题:jQuery draggabl
我在 UIWebView 中加载了一个 HTML 表单,而我的 UIWebView 恰好从 View 的中间开始并扩展。我必须锁定此 webView 不滚动并将其放在 ScrollView 之上以允许
如何在每个元素而不是整个元素上应用淡入淡出(与其高度相比)? HTML: CSS: * { padding: 0; margin: 0; box-sizing: border
我想使用带有垂直轴的 PageView 并使用鼠标滚动在页面之间移动,但是当我使用鼠标滚动时页面不滚动...仅页面单击并向上/向下滑动时滚动。 有什么办法吗? 我想保留属性 pageSnapping:
我制作这个程序是为了好玩,但我被卡住了,因为程序在屏幕外运行。如何在不完全更改代码的情况下实现滚动条。 public static void main(String args[]) throws IO
我想使用带有垂直轴的 PageView 并使用鼠标滚动在页面之间移动,但是当我使用鼠标滚动时页面不滚动...仅页面单击并向上/向下滑动时滚动。 有什么办法吗? 我想保留属性 pageSnapping:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
使用 jquery 技术从 css-tricks.com 获得滚动/跟随侧边栏,如果您不知道我在说什么,这里是代码: $(function() { var $sidebar = $
我是 jQuery Mobile 新手。我需要向我的应用程序添加 Facebook 滑动面板功能。 我经历了 sliding menu panel ,它工作正常,但我在菜单面板中的内容超出了窗口大小,
有没有办法在 js 或 jQuery 或任何其他工具中检测 ctrl + 滚动。我正在尝试执行一些动态布局代码,我需要检测不同分辨率下的屏幕宽度,我通过使用 setTimeout() 的计时器实现了这
我有一部分html代码:
我想控制 RichTextBox 滚动,但在控件中找不到任何方法来执行此操作。 这样做的原因是我希望当鼠标光标位于 RichTextBox 控件上时鼠标滚轮滚动有效(它没有事件焦点:鼠标滚轮事件由表单
我是一名优秀的程序员,十分优秀!