Reputation: 6187
My app has an Activity
that's declared with:
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
adjustResize
is set and in that activity I have a RecyclerView
and an EditText
as in a chat like app.
The problem I'm facing is that when the keyboard shows up the layout is resized as intented but it also scrolls up the RecyclerView
contents.
The behavior desired is that the scroll stays put.
I've tried using LayoutManager#onSaveInstanceState()
and it's counterpart LayoutManager#onRestoreInstanceState()
with no avail.
I know many had similar/same issues but I couldn't find a good solutions for this.
Upvotes: 0
Views: 2728
Reputation: 320
use addOnscrollListener to check weather currently recyclerview is at bottom or not if yes then use the method provided in accepted answer by doing it youe recycler only scroll when last item is visible else it wont scroll
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
cannotScrollVertically = !recyclerView.canScrollVertically(1);//use a Boolean variable
}
});
Upvotes: 0
Reputation: 6187
Ok, amazing how a clear head and a sudden glimpse of thought makes wonders.
I don't know about everyone but I haven't found a solution for this simple problem this way, and it works for me. Sharing:
recyclerView.addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
val y = oldBottom - bottom
val firstVisibleItem = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
if (y.absoluteValue > 0 && !(y < 0 && firstVisibleItem == 0)) {
recycler_view.scrollBy(0, y)
}
}
Only drawback so far is that when you're scrolled to the second item and you hide the soft keyboard, it scrolls to the very end but no big deal for me.
Hope it helps someone.
EDIT: Here's how I solved without any drawbacks now:
private var verticalScrollOffset = AtomicInteger(0)
recyclerView.addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
val y = oldBottom - bottom
if (y.absoluteValue > 0) {
// if y is positive the keyboard is up else it's down
recyclerView.post {
if (y > 0 || verticalScrollOffset.get().absoluteValue >= y.absoluteValue) {
recyclerView.scrollBy(0, y)
} else {
recyclerView.scrollBy(0, verticalScrollOffset.get())
}
}
}
}
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
var state = AtomicInteger(RecyclerView.SCROLL_STATE_IDLE)
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
if (!state.compareAndSet(RecyclerView.SCROLL_STATE_SETTLING, newState)) {
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
}
}
RecyclerView.SCROLL_STATE_DRAGGING -> {
state.compareAndSet(RecyclerView.SCROLL_STATE_IDLE, newState)
}
RecyclerView.SCROLL_STATE_SETTLING -> {
state.compareAndSet(RecyclerView.SCROLL_STATE_DRAGGING, newState)
}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (state.get() != RecyclerView.SCROLL_STATE_IDLE) {
verticalScrollOffset.getAndAdd(dy)
}
}
})
EDIT2: This can be easily converted to Java if that's your poison.
Upvotes: 4