Заметил особенность в отлове события OnScrollChanged на старых девайсах с
Android 2.x (проблема также может относиться к 3.x; нет возможности проверить).
Суть заключается в том, что scroll-слушатель не работает, если добавлять его
до того, как layout впервые будет пересчитан. Например, если делать это в
onCreate
:
public class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
println(myView.getViewTreeObserver().isAlive()) // true
myView.getViewTreeObserver().addOnScrollChangedListener {
// will never fire
}
}
}
То же самое относится к методам onStart
, onResume
, onPostResume
,
onAttachedToWindow
.
Таким образом, если вы поддерживаете API<15 (ICS), то не добавляйте OnScrollChangedListener в указанных методах. Причину такого поведения назвать затрудняюсь. В документации об условиях добавления scroll-слушателя ничего не сказано. Единственное – Observer должен быть Alive, что выполняется, как видно из примера выше.
Когда же добавлять слушатель?
1. Либо по какому-то пользовательскому событию, когда layout уже построен.
2. Либо при первом срабатывании OnGlobalLayoutListener:
val layoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
myView.getViewTreeObserver().removeGlobalOnLayoutListener(this)
myView.getViewTreeObserver().addOnScrollChangedListener(scrollListener)
}
}
myView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener)
3. Либо, что иногда более удобно, в onWindowFocusChanged
:
public class MainActivity : AppCompatActivity()
{
private var isScrollListenerAdded = false
override fun onCreate(savedInstanceState: Bundle?) {
// ...
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus && !isScrollListenerAdded) {
myView.getViewTreeObserver().addOnScrollChangedListener(scrollListener)
isScrollListenerAdded = true
}
}
override fun onPause() {
myView.getViewTreeObserver().removeOnScrollChangedListener(scrollListener)
isScrollListenerAdded = false
super.onPause()
}
}
Стоит отметить, что onWindowFocusChanged(false)
не срабатывает в
некоторых случаях (например, при смене ориентации он
вызван не будет, зато повторно сработает onWindowFocusChanged(true)
), поэтому
удаление слушателя нужно производить в onPause
или onStop
.
PS
Кстати, на данный момент (сентябрь 2015), согласно статистике Google Play, доля устройств с API<15 в категории «Книги и справочники» – чуть более 7%.
Android 5.x 18.05% Android 4.x 74.72% Android 3.x 0.31% Android 2.x 6.75%