gpt4 book ai didi

android - PinnedHeaderListView 滚动和标题问题

转载 作者:太空狗 更新时间:2023-10-29 13:21:49 24 4
gpt4 key购买 nike

背景

我试图模仿 Lollipop 的联系人应用程序显示联系人首字母的固定标题的方式,正如我所写的 here .

问题

由于原始代码(位于“PinnedHeaderListViewSample”文件夹中的 here 中)没有显示除英文以外的字母,因此我不得不稍微更改代码,但这还不够。标题本身也是如此,它现在必须在左侧,而不是在行上方。

一切正常,直到我在 RTL 语言(在我的情况下是希伯来语)上对其进行了测试,而设备的语言环境也更改为 RTL 语言(在我的情况下是希伯来语)。

出于某种原因,滚动和标题本身都变得非常奇怪,奇怪的是它发生在某些设备/版本的 Android 上。

例如,在带有 Kitkat 的 Galaxy S3 上,滚动和滚动条完全错误(我滚动到顶部,但滚动条的位置在中间)。

在装有 Android 4.2.2 的 LG G2 上,它也有这个问题,但它也没有显示标题(固定标题除外),尤其是希伯来语中的标题。

在 Galaxy S4 和 Huwawei Ascend P7(都运行 Kitkat)上,无论我做什么,一切正常。

简而言之,特殊情况是:

  • 使用 pinnedHeaderListView
  • 让设备使用 RTL 语言环境,或通过开发人员设置
  • 进行设置
  • 有英语和希伯来语的 ListView 项目
  • 设置 listView 以显示快速滚动条。
  • 使用快速滚动器滚动 listView 或像没有它一样滚动。

  • 编码

    代码量非常大,加上我做了 2 个 POC,其中一个与我开始使用的代码有很大不同(使其看起来像在 Lollipop 上)。所以我会尽量显示最小的数量。

    编辑:大 POC 代码可在 Github 上获得, here .

    "PinnedHeaderActivity.java"

    我在“名称”字段的顶部添加了 2 个希伯来语项目:
            "אאא",
    "בבב",

    在“setupListView”方法中,我使快速滚动条可见:
        listView.setFastScrollEnabled(true);

    在“NamesAdapter”CTOR 中,我让它支持的不仅仅是英文字母:
        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());
    }

    "StringArrayAlphabetIndexer.java"

    在“getSectionForPosition”方法中,我将其更改为:
    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;
    }
    }

    list_item.xml
    <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>

    list_item_header.xml
    <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" />

    这是两张截图,一张看起来不太好,另一张看起来还不错:

    Galaxy S3 kitkat 和 LG G2 4.2.2 - 不显示希伯来语标题,并且在底部附近有奇怪的滚动(与其余滚动相比,滚动到底部非常快):

    enter image description here

    Galaxy S4 kitkat - 显示标题很好,但底部的滚动很奇怪:

    enter image description here
    出于某种原因,尽管我在开发人员选项中选择了 Galaxy S4,但它并没有像应有的那样镜像 UI,所以这也可能是它显示标题正常的原因。

    我试过的

    除了尝试我制作的 2 个 POC(一个更类似于 Material 设计风格并且更复杂的 POC),我尝试了各种使用布局的方法,还尝试使用 LayoutDirection 来强制要显示的标题。

    更难的问题是解决快速滚动条,它在更复杂的 POC 上非常奇怪,在简单的 POC 上有点奇怪(在底部附近快速滚动)。

    问题

    解决这些问题的正确方法是什么?

    为什么 RTL 对这种类型的 UI 有问题?

    编辑:似乎即使是 Google 的示例也不能在简单的 ListView 上很好地处理 RTL 项目:
    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);
    }

    }


    }

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

    }

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

    IndexedPinnedHeaderListViewAdapter
    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&&sections.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/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com