Проблема с быстрым прокруткой с помощью ListAdapter и SectionIndexer

У меня есть список событий, которые отделяются по месяцам и годам (июнь 2010, июль 2010 и т. Д.). Я включил быструю прокрутку, потому что список действительно длинный. Я также внедрил SectionIndexer, чтобы люди могли видеть, какой месяц и год они просматривают в настоящее время при прокрутке списка событий на скорости.

У меня нет никаких проблем с реализацией, как показано на рисунке. Быстрая прокрутка с помощью SectionIndexer, по-видимому, действительно может поддерживать ярлык с единственной буквой. Если список был в алфавитном порядке, это было бы идеально, но я хочу, чтобы он отображал немного больше текста.

Если вы посмотрите на снимок экрана, вы увидите проблему, с которой я столкнулся.

Снимок экрана описанной проблемы http://sofru.miximages.com/android/mattoakes.net

Я хочу знать: возможно ли изменить текст в центре экрана. Могу ли я изменить его каким-то образом, чтобы он выглядел правильно (с фоном, охватывающим весь текст).

Заранее спасибо. Если вам нужны какие-либо разъяснения или код, просто спросите.

EDIT: полный образец кода для этого решения, доступного здесь .

У меня была такая же проблема – мне нужно было отображать полный текст в прямоугольнике наложения, а не только один символ. Мне удалось решить это, используя следующий код в качестве примера: http://code.google.com/p/apps-for-android/source/browse/trunk/RingsExtended/src/com/example/android/rings_extended/FastScrollView .Ява

Автор сказал, что это было скопировано из приложения «Контакты», которое, по-видимому, использует свою собственную реализацию, а не просто устанавливает fastScrollEnabled="true" в ListView . Я немного изменил его, чтобы вы могли настроить ширину прямоугольника перекрытия, высоту прямоугольника наложения, размер текста наложения и ширину большого пальца прокрутки.

Для записи окончательный результат выглядит следующим образом: http://sofru.miximages.com/android/pokedroid_1.png

Все, что вам нужно сделать, это добавить эти значения к вашим res / values ​​/ attrs.xml:

       

И затем используйте этот 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.

Затем поместите что-то подобное в ваш XML-файл макета:

      

Не забудьте также объявить свои атрибуты в этом XML-файле макета:

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

Вам также потребуется захватить R.drawable.scrollbar_handle_accelerated_anim2 из этого исходного кода Android. Ссылка выше содержит только mdpi.

Виджет FastScroller отвечает за рисование наложения. Вероятно, вам стоит взглянуть на его источник:
https://android.googlesource.com/platform/frameworks/base/+/gingerbread-release/core/java/android/widget/FastScroller.java

Поиск комментария:

 // If user is dragging the scroll bar, draw the alphabet overlay 
  • Просмотр Android-видео в полноэкранном режиме
  • Как показать кнопку в конце Android ListView
  • как настроить listview row android
  • Android: использование WebView вне контекста активности
  • Показывать пустое представление, когда ListView пуст
  • TextView с различным textSize
  • setEmptyView в ListView не показывает его вид в приложении для Android?
  • Как динамически удалять элементы из списка ListView при нажатии кнопки?
  • Как обновить список просмотров Android?
  • Android: переключения экранов с новой активностью или просто изменение содержимого
  • Как установить блок для Paint.setTextSize ()
  • Interesting Posts

    Сопоставьте значения в кадре данных со значениями в другом кадре данных и замените прежний соответствующим шаблоном из другого кадра данных

    Как эта стратегия резервного копирования работает?

    Срок службы сеанса symfony2

    VRAM на рабочей станции 11 только 64 МБ

    Работает ли Tomcat?

    Передача пустого массива в качестве значения по умолчанию для необязательного параметра

    Просмотр с горизонтальным и вертикальным панорамированием / drag and dropм и усилением

    Как автоматически форматировать код в Eclipse?

    Загрузка Windows 7 из загруженного .iso

    Как инициализировать массив до 0 в C?

    Rails – использовать тип столбца без STI?

    Добавить верхний и нижний колонтитулы для PDF с помощью iTextsharp

    Как заставить VMWare Workstation использовать несколько окон для виртуальных машин вместо отображения с вкладками?

    MongoDB – аргумент $ size должен быть массивом, но имеет тип: EOO

    constexpr инициализирует статический член, используя статическую функцию

    Давайте будем гением компьютера.