快速滚动显示的问题ListAdapter和SectionIndexer [英] Fast Scroll display problem with ListAdapter and SectionIndexer

查看:179
本文介绍了快速滚动显示的问题ListAdapter和SectionIndexer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有被月份和年份分隔的事件列表(2010年6月,2010年7月等)。我已经启用快速滚动,因为名单是很长的。我也实现SectionIndexer使人们可以看到什么年月,他们向下滚动时的事件列表的速度正在查看。

I have a list of events which are seperated by month and year (Jun 2010, Jul 2010 etc.). I have enabled fast scrolling because the list is really long. I've also implemented SectionIndexer so that people can see what month and year they are currently viewing when scrolling down the list of events at speed.

我没有任何问题的实施,信息是如何显示。快速滚动与SectionIndexer似乎才真正能够支持一个标签与一个字母。如果列表中alphabetised这将是完美的,但是我希望它显示一些文本。

I don't have any problem with the implementation, just how the information is shown. Fast scrolling with SectionIndexer seems to only really be able to support a label with a single letter. If the list was alphabetised this would be perfect, however I want it to display a bit more text.

如果你看一下截图波纹管,你会看到我有这个问题。

If you look at the screenshot bellow you'll see the problem I'm having.

我想知道的是:是否有可能改变如何在屏幕中央的文字显示方式。我能以某种方式改变它,使它看起来正确的(与背景涵盖了所有的文字)。

What I want to know is: is it possible to change how the text in the centre of the screen is displayed. Can I change it somehow to make it look right (with the background covering all of the text).

在此先感谢。如果你需要任何澄清,或code就问我。

Thanks in advance. If you need any clarification, or code just ask.

推荐答案

编辑:全部样品code为这种解决方案提供的这里

Full sample code for this solution available here.

我有同样的问题 - 我需要显示在叠加的矩形全文,而不仅仅是单个字符。我设法使用下面的code为例来解决这个问题:<一href="http://$c$c.google.com/p/apps-for-android/source/browse/trunk/RingsExtended/src/com/example/android/rings_extended/FastScrollView.java">http://$c$c.google.com/p/apps-for-android/source/browse/trunk/RingsExtended/src/com/example/android/rings_extended/FastScrollView.java

I had this same problem - I needed to display full text in the overlay rectangle rather than just a single character. I managed to solve it using the following code as an example: http://code.google.com/p/apps-for-android/source/browse/trunk/RingsExtended/src/com/example/android/rings_extended/FastScrollView.java

笔者说,这是从联系人应用程序,这显然使用它自己的实现,而不是只设置复制 fastScrollEnabled =真正的的ListView 。我改变一点点,让你可以自定义覆盖的矩形宽度,覆盖矩形的高度,叠加文字大小和滚动拇指宽。

The author said that this was copied from the Contacts app, which apparently uses its own implementation rather than just setting fastScrollEnabled="true" on the ListView. I altered it a little bit so that you can customize the overlay rectangle width, overlay rectangle height, overlay text size, and scroll thumb width.

有关的记录,最后的结果是这样的:<一href="http://nolanwlawson.files.word$p$pss.com/2011/03/pokedroid_1.png">http://nolanwlawson.files.word$p$pss.com/2011/03/pokedroid_1.png

For the record, the final result looks like this: http://nolanwlawson.files.wordpress.com/2011/03/pokedroid_1.png

所有你需要做的就是这些值添加到您的RES /价值/ attrs.xml:

All you need to do is add these values to your res/values/attrs.xml:

<declare-styleable name="CustomFastScrollView">

    <attr name="overlayWidth" format="dimension"/>
    <attr name="overlayHeight" format="dimension"/>
    <attr name="overlayTextSize" format="dimension"/>
    <attr name="overlayScrollThumbWidth" format="dimension"/>

</declare-styleable>

和再使用,而不是一个在这个链接CustomFastScrollView:

And then use this CustomFastScrollView instead of the one in the link:

public class CustomFastScrollView extends FrameLayout 
        implements OnScrollListener, OnHierarchyChangeListener {

    private Drawable mCurrentThumb;
    private Drawable mOverlayDrawable;

    private int mThumbH;
    private int mThumbW;
    private int mThumbY;

    private RectF mOverlayPos;

    // custom values I defined
    private int mOverlayWidth;
    private int mOverlayHeight;
    private float mOverlayTextSize;
    private int mOverlayScrollThumbWidth;

    private boolean mDragging;
    private ListView mList;
    private boolean mScrollCompleted;
    private boolean mThumbVisible;
    private int mVisibleItem;
    private Paint mPaint;
    private int mListOffset;

    private Object [] mSections;
    private String mSectionText;
    private boolean mDrawOverlay;
    private ScrollFade mScrollFade;

    private Handler mHandler = new Handler();

    private BaseAdapter mListAdapter;

    private boolean mChangedBounds;

    public static interface SectionIndexer {
        Object[] getSections();

        int getPositionForSection(int section);

        int getSectionForPosition(int position);
    }

    public CustomFastScrollView(Context context) {
        super(context);

        init(context, null);
    }


    public CustomFastScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init(context, attrs);
    }

    public CustomFastScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        init(context, attrs);
    }

    private void useThumbDrawable(Drawable drawable) {
        mCurrentThumb = drawable;
        mThumbW = mOverlayScrollThumbWidth;//mCurrentThumb.getIntrinsicWidth();
        mThumbH = mCurrentThumb.getIntrinsicHeight();
        mChangedBounds = true;
    }

    private void init(Context context, AttributeSet attrs) {

        // set all attributes from xml
        if (attrs != null) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs,
                    R.styleable.CustomFastScrollView);
            mOverlayHeight = typedArray.getDimensionPixelSize(
                    R.styleable.CustomFastScrollView_overlayHeight, 0);
            mOverlayWidth = typedArray.getDimensionPixelSize(
                    R.styleable.CustomFastScrollView_overlayWidth, 0);
            mOverlayTextSize = typedArray.getDimensionPixelSize(
                    R.styleable.CustomFastScrollView_overlayTextSize, 0);
            mOverlayScrollThumbWidth = typedArray.getDimensionPixelSize(
                    R.styleable.CustomFastScrollView_overlayScrollThumbWidth, 0);

        }

        // Get both the scrollbar states drawables
        final Resources res = context.getResources();
        Drawable thumbDrawable = res.getDrawable(R.drawable.scrollbar_handle_accelerated_anim2);
        useThumbDrawable(thumbDrawable);

        mOverlayDrawable = res.getDrawable(android.R.drawable.alert_dark_frame);

        mScrollCompleted = true;
        setWillNotDraw(false);

        // Need to know when the ListView is added
        setOnHierarchyChangeListener(this);

        mOverlayPos = new RectF();
        mScrollFade = new ScrollFade();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(mOverlayTextSize);
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    }

    private void removeThumb() {
        mThumbVisible = false;
        // Draw one last time to remove thumb
        invalidate();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        if (!mThumbVisible) {
            // No need to draw the rest
            return;
        }

        final int y = mThumbY;
        final int viewWidth = getWidth();
        final CustomFastScrollView.ScrollFade scrollFade = mScrollFade;

        int alpha = -1;
        if (scrollFade.mStarted) {
            alpha = scrollFade.getAlpha();
            if (alpha < ScrollFade.ALPHA_MAX / 2) {
                mCurrentThumb.setAlpha(alpha * 2);
            }
            int left = viewWidth - (mThumbW * alpha) / ScrollFade.ALPHA_MAX;
            mCurrentThumb.setBounds(left, 0, viewWidth, mThumbH);
            mChangedBounds = true;
        }

        canvas.translate(0, y);
        mCurrentThumb.draw(canvas);
        canvas.translate(0, -y);

        // If user is dragging the scroll bar, draw the alphabet overlay
        if (mDragging && mDrawOverlay) {
            mOverlayDrawable.draw(canvas);
            final Paint paint = mPaint;
            float descent = paint.descent();
            final RectF rectF = mOverlayPos;
            canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2,
                    (int) (rectF.bottom + rectF.top) / 2 + descent, paint);
        } else if (alpha == 0) {
            scrollFade.mStarted = false;
            removeThumb();
        } else {
            invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH);            
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mCurrentThumb != null) {
            mCurrentThumb.setBounds(w - mThumbW, 0, w, mThumbH);
        }
        final RectF pos = mOverlayPos;
        pos.left = (w - mOverlayWidth) / 2;
        pos.right = pos.left + mOverlayWidth;
        pos.top = h / 10; // 10% from top
        pos.bottom = pos.top + mOverlayHeight;
        mOverlayDrawable.setBounds((int) pos.left, (int) pos.top,
                (int) pos.right, (int) pos.bottom);
    }

    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
            int totalItemCount) {


        if (totalItemCount - visibleItemCount > 0 && !mDragging) {
            mThumbY = ((getHeight() - mThumbH) * firstVisibleItem) / (totalItemCount - visibleItemCount);
            if (mChangedBounds) {
                final int viewWidth = getWidth();
                mCurrentThumb.setBounds(viewWidth - mThumbW, 0, viewWidth, mThumbH);
                mChangedBounds = false;
            }
        }
        mScrollCompleted = true;
        if (firstVisibleItem == mVisibleItem) {
            return;
        }
        mVisibleItem = firstVisibleItem;
        if (!mThumbVisible || mScrollFade.mStarted) {
            mThumbVisible = true;
            mCurrentThumb.setAlpha(ScrollFade.ALPHA_MAX);
        }
        mHandler.removeCallbacks(mScrollFade);
        mScrollFade.mStarted = false;
        if (!mDragging) {
            mHandler.postDelayed(mScrollFade, 1500);
        }
    }


    private void getSections() {
        Adapter adapter = mList.getAdapter();
        if (adapter instanceof HeaderViewListAdapter) {
            mListOffset = ((HeaderViewListAdapter)adapter).getHeadersCount();
            adapter = ((HeaderViewListAdapter)adapter).getWrappedAdapter();
        }
        if (adapter instanceof SectionIndexer) {
            mListAdapter = (BaseAdapter) adapter;
            mSections = ((SectionIndexer) mListAdapter).getSections();
        }
    }

    public void onChildViewAdded(View parent, View child) {
        if (child instanceof ListView) {
            mList = (ListView)child;

            mList.setOnScrollListener(this);
            getSections();
        }
    }

    public void onChildViewRemoved(View parent, View child) {
        if (child == mList) {
            mList = null;
            mListAdapter = null;
            mSections = null;
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mThumbVisible && ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (ev.getX() > getWidth() - mThumbW && ev.getY() >= mThumbY &&
                    ev.getY() <= mThumbY + mThumbH) {
                mDragging = true;
                return true;
            }            
        }
        return false;
    }

    private void scrollTo(float position) {
        int count = mList.getCount();
        mScrollCompleted = false;
        final Object[] sections = mSections;
        int sectionIndex;
        if (sections != null && sections.length > 1) {
            final int nSections = sections.length;

            int section = (int) (position * nSections);
            if (section >= nSections) {
                section = nSections - 1;
            }
            sectionIndex = section;
            final SectionIndexer baseAdapter = (SectionIndexer) mListAdapter;
            int index = baseAdapter.getPositionForSection(section);

            // Given the expected section and index, the following code will
            // try to account for missing sections (no names starting with..)
            // It will compute the scroll space of surrounding empty sections
            // and interpolate the currently visible letter's range across the
            // available space, so that there is always some list movement while
            // the user moves the thumb.
            int nextIndex = count;
            int prevIndex = index;
            int prevSection = section;
            int nextSection = section + 1;
            // Assume the next section is unique
            if (section < nSections - 1) {
                nextIndex = baseAdapter.getPositionForSection(section + 1);
            }

            // Find the previous index if we're slicing the previous section
            if (nextIndex == index) {
                // Non-existent letter
                while (section > 0) {
                    section--;
                     prevIndex = baseAdapter.getPositionForSection(section);
                     if (prevIndex != index) {
                         prevSection = section;
                         sectionIndex = section;
                         break;
                     }
                }
            }
            // Find the next index, in case the assumed next index is not
            // unique. For instance, if there is no P, then request for P's 
            // position actually returns Q's. So we need to look ahead to make
            // sure that there is really a Q at Q's position. If not, move 
            // further down...
            int nextNextSection = nextSection + 1;
            while (nextNextSection < nSections &&
                    baseAdapter.getPositionForSection(nextNextSection) == nextIndex) {
                nextNextSection++;
                nextSection++;
            }
            // Compute the beginning and ending scroll range percentage of the
            // currently visible letter. This could be equal to or greater than
            // (1 / nSections). 
            float fPrev = (float) prevSection / nSections;
            float fNext = (float) nextSection / nSections;
            index = prevIndex + (int) ((nextIndex - prevIndex) * (position - fPrev) 
                    / (fNext - fPrev));
            // Don't overflow
            if (index > count - 1) index = count - 1;

            mList.setSelectionFromTop(index + mListOffset, 0);
        } else {
            int index = (int) (position * count);
            mList.setSelectionFromTop(index + mListOffset, 0);
            sectionIndex = -1;
        }

        if (sectionIndex >= 0) {
            String text = mSectionText = sections[sectionIndex].toString();
            mDrawOverlay = (text.length() != 1 || text.charAt(0) != ' ') &&
                    sectionIndex < sections.length;
        } else {
            mDrawOverlay = false;
        }
    }

    private void cancelFling() {
        // Cancel the list fling
        MotionEvent cancelFling = MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0);
        mList.onTouchEvent(cancelFling);
        cancelFling.recycle();
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
        if (me.getAction() == MotionEvent.ACTION_DOWN) {
            if (me.getX() > getWidth() - mThumbW
                    && me.getY() >= mThumbY 
                    && me.getY() <= mThumbY + mThumbH) {

                mDragging = true;
                if (mListAdapter == null && mList != null) {
                    getSections();
                }

                cancelFling();
                return true;
            }
        } else if (me.getAction() == MotionEvent.ACTION_UP) {
            if (mDragging) {
                mDragging = false;
                final Handler handler = mHandler;
                handler.removeCallbacks(mScrollFade);
                handler.postDelayed(mScrollFade, 1000);
                return true;
            }
        } else if (me.getAction() == MotionEvent.ACTION_MOVE) {
            if (mDragging) {
                final int viewHeight = getHeight();
                mThumbY = (int) me.getY() - mThumbH + 10;
                if (mThumbY < 0) {
                    mThumbY = 0;
                } else if (mThumbY + mThumbH > viewHeight) {
                    mThumbY = viewHeight - mThumbH;
                }
                // If the previous scrollTo is still pending
                if (mScrollCompleted) {
                    scrollTo((float) mThumbY / (viewHeight - mThumbH));
                }
                return true;
            }
        }

        return super.onTouchEvent(me);
    }

    public class ScrollFade implements Runnable {

        long mStartTime;
        long mFadeDuration;
        boolean mStarted;
        static final int ALPHA_MAX = 200;
        static final long FADE_DURATION = 200;

        void startFade() {
            mFadeDuration = FADE_DURATION;
            mStartTime = SystemClock.uptimeMillis();
            mStarted = true;
        }

        int getAlpha() {
            if (!mStarted) {
                return ALPHA_MAX;
            }
            int alpha;
            long now = SystemClock.uptimeMillis();
            if (now > mStartTime + mFadeDuration) {
                alpha = 0;
            } else {
                alpha = (int) (ALPHA_MAX - ((now - mStartTime) * ALPHA_MAX) / mFadeDuration); 
            }
            return alpha;
        }

        public void run() {
            if (!mStarted) {
                startFade();
                invalidate();
            }

            if (getAlpha() > 0) {
                final int y = mThumbY;
                final int viewWidth = getWidth();
                invalidate(viewWidth - mThumbW, y, viewWidth, y + mThumbH);
            } else {
                mStarted = false;
                removeThumb();
            }
        }
    }
}

您也可以调整使用ALPHA_MAX滚动滑块的透明度。

You can also tweak the translucency of the scroll thumb using ALPHA_MAX.

然后把这样的事情在你的布局XML文件:

Then put something like this in your layout xml file:

    <com.myapp.CustomFastScrollView android:layout_width="wrap_content"
            android:layout_height="fill_parent" 
            myapp:overlayWidth="175dp" myapp:overlayHeight="110dp" myapp:overlayTextSize="36dp"
            myapp:overlayScrollThumbWidth="60dp" android:id="@+id/fast_scroll_view">
        <ListView android:id="@android:id/list" android:layout_width="wrap_content"
            android:layout_height="fill_parent"/>
        <TextView android:id="@android:id/empty"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:text="" />
    </com.myapp.CustomFastScrollView>   

不要忘了申报该布局XML文件中的属性,以及:

Don't forget to declare your attributes in that layout xml file as well:

 ... xmlns:myapp= "http://schemas.android.com/apk/res/com.myapp" ... 

您还将需要获取 R.drawable.scrollbar_handle_accelerated_anim2 可绘制从Android源$ C ​​$ C。以上只是该链接包含MDPI之一。

You'll also need to grab the R.drawable.scrollbar_handle_accelerated_anim2 drawables from that Android source code. The link above only contains the mdpi one.

这篇关于快速滚动显示的问题ListAdapter和SectionIndexer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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