使用ListAdapter和SectionIndexer快速滚动显示问题

我有一个按月份和年份分列的事件列表(2010年6月,2010年7月等)。 我已经启用了快速滚动,因为列表很长。 我还实现了SectionIndexer,以便人们可以快速查看当前正在查看的月份和年份。

我没有任何实施的问题,只是如何显示信息。 使用SectionIndexer快速滚动似乎只能真正支持单个字母的标签。 如果列表是字母表,这将是完美的,但是我希望它显示更多的文字。

如果你看下面的截图,你会看到我遇到的问题。

该问题的屏幕截图http://sofzh.miximages.com/android/mattoakes.net

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

提前致谢。 如果您需要任何澄清或代码只是问。

Solutions Collecting From Web of "使用ListAdapter和SectionIndexer快速滚动显示问题"

编辑:此解决scheme的完整示例代码可在这里 。

我有这个相同的问题 – 我需要在覆盖矩形显示全文,而不是一个单一的字符。 我设法解决它使用下面的代码作为例子: http : //code.google.com/p/apps-for-android/source/browse/trunk/RingsExtended/src/com/example/android/rings_extended/FastScrollView的.java

作者说,这是从通讯录应用程序,这显然使用自己的实现,而不是只是在ListView上设置fastScrollEnabled="true" 。 我改变了一点点,这样你就可以自定义覆盖矩形的宽度,覆盖矩形的高度,覆盖的文字大小和滚动的拇指宽度。

为了logging,最终结果如下所示: http : //nolanwlawson.files.wordpress.com/2011/03/pokedroid_1.png

您只需将这些值添加到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而不是链接中的一个:

 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调整滚动条的半透明度。

然后把这样的东西放在你的layout xml文件中:

  <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> 

不要忘记在这个layout xml文件中声明你的属性:

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

您还需要从Android源代码中获取R.drawable.scrollbar_handle_accelerated_anim2可绘制对象。 上面的链接只包含mdpi之一。

FastScroller小部件负责绘制覆盖图。 你应该看看它的来源:
https://android.googlesource.com/platform/frameworks/base/+/gingerbread-release/core/java/android/widget/FastScroller.java

search评论:

 // If user is dragging the scroll bar, draw the alphabet overlay