- Русские Блоги
- RecyclerView.smoothScrollToPosition
- предисловие
- Каков видимый диапазон?
- 1. Проблемы, возникающие при фактическом использовании
- Если текущая позиция прокрутки находится в пределах видимого диапазона, прокрутка не произойдет
- 2. Если текущая позиция прокрутки находится за видимым диапазоном, она прокручивается вниз
- 3. Если текущая позиция прокрутки находится перед видимым диапазоном, она будет прокручиваться вверх
- Во-вторых, анализ исходного кода RecyclerView smoothScrollToPosition
Русские Блоги
RecyclerView.smoothScrollToPosition
предисловие
Недавно я столкнулся с требованием в разработке, которое требует, чтобы RecyclerView прокручивал до указанной позиции и затем отображал ее сверху. Когда я столкнулся с этой проблемой, моей первой реакцией было непосредственное использование метода RecyclerView smoothScrollToPosition () для достижения плавной прокрутки соответствующей позиции. Однако при реальном использовании было обнаружено, что в конечном итоге эффекта не было. Я хотел быть ленивым и напрямую копировать из Интернета, но обнаружил, что эффект был не очень хорошим. Поэтому я пошел изучать исходный код сам.
Эта серия статей разделена на две статьи.
- Если вы хотите понять его внутреннюю реализацию, пожалуйста, посмотрите эту статью,
- Если вы хотите решить проблему прокрутки до верха с помощью smoothScrollToPosition или изменить ускорение прокрутки, посмотритеRecyclerView положение прокрутки, настройка скорости прокрутки
Каков видимый диапазон?
Прежде чем приступить к пониманию метода smoothScrollToPosition в RecyclerView, нужно кое-что узнать, я думаю, что это необходимо рассказать всем, поскольку проблемы, возникающие при использовании smoothScrollToPosition, связаны с видимым диапазоном.
Упомянутый здесь видимый диапазон — это диапазон между позицией первого видимого элемента RecyclerView и позицией последнего видимого элемента.
1. Проблемы, возникающие при фактическом использовании
Если текущая позиция прокрутки находится в пределах видимого диапазона, прокрутка не произойдет
Текущий видимый диапазон RecyclerView — от 0 до 9. Когда мы хотим прокрутить до позиции 1, мы обнаруживаем, что текущий RecyclerView не прокручивается.
2. Если текущая позиция прокрутки находится за видимым диапазоном, она прокручивается вниз
Текущий видимый диапазон RecyclerView — от 0 до 9. Когда мы хотим прокрутить до позиции 10, мы обнаруживаем, что RecyclerView прокручивается, и представление, соответствующее текущей позиции, находится внизу RecyclreView.
3. Если текущая позиция прокрутки находится перед видимым диапазоном, она будет прокручиваться вверх
Здесь мы прокручиваем RecyclerView так, чтобы видимый диапазон составлял от 10 до 19, когда мы прокручиваем на 1, 3 позиции, прокручиваем RecyclerView. И представление, соответствующее текущей позиции, находится в верхней части RecyclerView.
Во-вторых, анализ исходного кода RecyclerView smoothScrollToPosition
Здесь мы обнаруживаем, что внутренняя обработка RecyclerView различна для разных ситуаций, поэтому, чтобы решить реальную проблему, важно взглянуть на исходный код, а затем мы будем следовать исходному коду вместе. Давайте посмотрим на конкретную реализацию прокрутки RecyclerView. (Я должен напомнить всем здесь, что я использовал здесьLinearLayoutManager, Эта статья основана на анализе LinearLayoutManager)
Метод mRecycler.smoothScrollToPosition (), внутренне вызывает метод smoothScrollToPosition LayoutManager, smoothScrollToPosition в LayoutManager не реализован, конкретная реализация находится в его подклассе, здесь мы используемLinearLayoutManagerИтак, давайте посмотрим, как это реализовано внутри.
Здесь мы видим, что именно LinearSmoothScroller вызывает скольжение RecyclerView, а родительским классом LinearSmoothScroller является RecyclerView.SmoothScroller. Я считаю, что каждый будет чувствовать себя немного знакомым с этим, потому что, когда мы перемещаем содержимое в элементе управления, мы будем использовать Для класса это Scroller. Здесь RecyclerView также настраивает скользящий скроллер. Это должно быть связано с скольжением его внутреннего вида.
Продолжайте startSmoothScroll, метод внутренне решает, что если он вычисляет значение координаты, он останавливается, а затем вызывает метод start (), чтобы перезапустить вычисление значения координаты. Затем начните смотреть на метод start ().
В методе запуска он идентифицирует текущее состояние выполнения скроллера и в то же время находит соответствующее целевое представление в соответствии с позицией прокрутки. Здесь важно напомнить, что метод findViewByPosition () будет запрашивать, существует ли представление, соответствующее целевой позиции, в видимом диапазоне Recycler. Например, теперь видимый диапазон RecyclerView равен 1-9, а целевая позиция равна 10, затем mTargetView = ноль, если видимый диапазон 9-20, а целевая позиция 1, тогда mTargetView = ноль.
Наконец, вызовите метод postOnAnimation () для внутреннего класса RecyclerView ViewFlinger.
Здесь мы обнаружили, что ViewFlinger на самом деле является Runnable, и Runnable отправляется внутри postOnAnimation (). Тогда нам нужно только заботиться о методе run () ViewFlinger.
Внутренняя реализация метода run () в ViewFlinger более сложна. Когда метод выполняется в первый раз, он будет выполнен, если (scroller.computeScrollOffset ()), где scroller — это ссылка на атрибут mScroller в ViewFlinger, где mScroller будет создан в ViewFlinger Объект инициализируется по умолчанию. Затем первое суждение, поскольку расчет еще не начался, поэтому он не будет вводить этот блок оператора, тогда будет непосредственно принят следующий оператор:
Наконец, я обнаружил, что я просто пошел на анимацию (0,0) и продолжил идти методом.
В методе onAnimation оценивается, является ли целевой вид пустым, все должны помнить выше, мы ищем целевой вид. Если текущая позиция находится за пределами видимого диапазона, то mTargetView = null не вернется к соответствующему суждению. Продолжить просмотр onSeekTargetStep ().
Непосредственно через код я обнаружил, что не понимаю, какую работу нужно выполнить для изменения функции. Здесь мы только знаем, что когда произойдет первая прокрутка, mInterimTargetDx = 0 и mInterimTargetDy = 0, тогда будет использован метод updateActionForInterimTarget ().
В соответствии с официальным переводом документа: когда представление, соответствующее целевой позиции прокрутки, не находится в видимом диапазоне RecyclerView, этот метод вычисляет вектор направления к представлению и запускает плавную прокрутку. Расстояние прокрутки по умолчанию составляет 12000 (единица измерения: px),(То есть, чтобы прокрутить до целевой позиции, Recycler будет прокручивать максимум 12000 пикселей)。
Так как этот метод вычисляет время, мы посмотрим на метод CalculayTimeForScrolling (). По названию метода мы должны понимать, что этот метод предназначен для вычисления времени, которое необходимо прокрутить на заданном расстоянии со скоростью по умолчанию.
MILLISECONDS_PER_PX будет создан при инициализации LinearSmoothScroller.
Проверьте метод calculateSpeedPerPixel ()
Другими словами, текущая скорость прокрутки связана с плотностью пикселей экрана.Получив плотность пикселей на дюйм текущего экрана мобильного телефона и время, необходимое для перемещения на дюйм, разделите время, необходимое для перемещения на дюйм, на плотность пикселей Вы можете рассчитать время, необходимое для перемещения на одну плотность пикселей. Хорошо, теперь, когда мы вычислили время, необходимое для перемещения плотности пикселей, затем умножим его прямо на пиксель, чтобы вычислить время, необходимое для перемещения этого пикселя.
Теперь, когда мы рассчитали время, нам нужно только позаботиться о том, что делает метод update () в Action.
Здесь мы обнаружили, что Action — это просто класс, который хранит скользящую информацию о SmoothScroller, а затем первоначально сохраняет горизонтальное и вертикальное расстояние скольжения (12000px), время скольжения, интерполятор. В то же время запись состояния текущих данных изменений.
Теперь, когда мы закончили метод onSeekTargetStep Движения, затем, далее, мы продолжаем смотреть на метод runIfNeeded () действия.
TNND, переданный туда и обратно, и, наконец, переданный хранящейся в Action информации в метод SmoothScrollBy () ViewFlinger. Обратите внимание:После вызова этого метода для mChanged будет установлено значение false, и в следующий раз, когда вы снова введете этот метод, скользящий метод ViewFlinger вызываться не будет.
После того, как mScroller получает скользящую информацию от Acttion и начинает скользить. Наконец, вызывается postOnAnimation (), и отсылается метод runFi (ViewFiinger). В итоге мы вернулись к методу run () в ViewFiinger.
Здесь скроллер (получает информацию о расстоянии скольжения, переданную предыдущим действием) начал скользить, поэтому, если условие (scroller.computeScrollOffset ()) имеет значение true, тогда скроллер получает текущее вертикальное значение и запускает прокрутку RecyclerView, а также Это код mLayout.scrollVerticallyBy (dy, mRecycler, mState), затем пусть smoothScroller выполняет метод onAnimation (). Входящий параметр — это расстояние, которое прокручивает RecyclerView. Затем мы продолжим изучать метод onAnimation.
Теперь код понятен. RecylerView определит, появился ли целевой вид при прокрутке. Если он не появляется, он вызовет onSeekTargetStep, чтобы сохранить текущее расстояние прокрутки RecylerView, затем определит, нужно ли RecyclerView скользить, а затем отправит ViewFlinger через postOnAnimation (). вне. Тогда он не остановится, пока не будет найден целевой вид.
При каких обстоятельствах целевое представление не является пустым, фактически, при прокрутке внутри RecylerView. Определит, существует ли целевое представление, если есть операция присваивания mTargetView. Из-за нехватки места поиск целевого представления здесь не будет представлен. Заинтересованные друзья могут взглянуть на исходный код.
Затем, если мы нашли целевое представление, тогда программа перейдет к методу onTargetFound ().
Когда целевой вид найден, он вычисляет горизонтальные и вертикальные расстояния, которые целевой экран должен перемещать в пределах видимого диапазона. И посчитайте, сколько времени это займет. Затем позвольте RecyclerView снова прокрутить расстояние.
Здесь мы сосредоточимся на вычислении DyToMakeVisible.
Здесь мы будем в соответствии с информацией координат верхней и нижней части текущего вида, а также начала и конца текущего макета,Затем вызывается метод CalculateDtToFit (). Сейчас самое главное, и это причина наших трех проблем! !
Мы вычислим соответствующее расстояние в соответствии со значением, соответствующим snapPreference, и определенным значением snapPreference и getVerticalSnapPreference (здесь мы вертикальные), поэтому мы рассмотрим этот метод.
Среди них mTargetVector связан с layoutManager.computeScrollVectorForPosition.
Другими словами, когда LinerlayoutManager находится в вертикальном положении, по умолчанию snapPreference имеет значение SNAP_ANY, тогда мы можем получить следующие три случая.
- Когда положение прокрутки находится в пределах видимого диапазона
boxStart — viewStart 0
Расстояние прокрутки равно 0, поэтому оно не будет прокручиваться - Когда положение прокрутки находится перед видимым диапазоном
boxStart — viewStart> 0
Тогда фактическое расстояние прокрутки будет положительным, а содержимое прокручивается вверх, поэтому его можно прокрутить только до самого верха. - Когда положение прокрутки находится за пределами видимого диапазона
boxEnd — viewEnd
Источник