Ответ 1
tl; dr Нет, вы ничего не пропустили. Но вы можете получить значения, необходимые в getItemOffsets
, хотя это кажется мне немного грязным.
В основном существует только один вариант получения украшенной высоты, отличной от управления украшениями: LayoutManager.getDecoratedTop();
OnDraw
В onDraw
вы получаете весь холст recyclerView, c.getClipBounds()
не содержит никакой информации. Хотя javadoc добавления декораций говорит, что украшения должны просто рисовать с их границами.
Кроме того, получение parent.getLayoutManager().getDecoratedTop()
даст вам одинаковые значения в каждом украшении, так как уже слишком поздно здесь эти значения предназначены для макетирования.
Мы слишком поздно, макетирование сделано, и мы его пропустили.
getItemOffsets
Обратите внимание, что я тестировал следующее с
LinearLayoutManager
, и он мог бы также не работать с другими (наиболее определенно не с большинством пользовательских). Поскольку я полагаюсь на измерение происходящего между этими вызовами, которое не задокументировано, данное решение может сломаться с некоторой будущей версией.
Я просто почувствовал, что мне нужен этот отказ. Я нашел рабочее решение (смотри mOffset
):
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
mOffset = parent.getLayoutManager().getTopDecorationHeight(view);
outRect.set(0, 10, 0, 0);
}
Это работает, потому что recyclerview при вычислении общей вставки дочернего элемента обновляет локальную переменную LayoutParams пакета представлений. Хотя мы не можем получить доступ к самой переменной параметра layout, вызов getTopDecorationHeight фактически использует (в настоящее время) грязную вставку, что дает нам правильное значение.
Следовательно, вы можете получить смещение предыдущих украшений, прежде чем применять свои собственные!
Чтобы применить его, просто удалите другие декорации при рисовании украшения:
c.drawRect(child.getLeft() + child.getTranslationX(),
mOffset + layoutManager.getDecoratedTop(child) + child.getTranslationY(),
child.getRight() + child.getTranslationX(),
child.getBottom() + child.getTranslationY(), paint);
Это фактически применит другое смещение украшений, а затем нарисует ваше собственное из верного верха.
Некоторые проблемы
Теперь это базовое, работающее решение для стандартного usecase. НО. Если у вас есть разные смещения в зависимости от элемента VIEW_TYPE или позиции адаптера, все становится сложным.
Вы будете либо дублировать свою логику, либо выполнять различные смещения для разных типов просмотров, либо вам нужно сохранить/получить смещение для каждого вида или вида.
Чтобы сделать это, вы можете либо добавить какой-либо пользовательский тег с помощью view.setTag(key, object)
, либо сделать что-то подобное с объектом RecyclerView.State
, который будет передан.