Here's my function that detect end off RecyclerView that will be use in pagination later.
private fun setOnScrollListener(categoryRecyclerView: RecyclerView, categoryPresenter: EntertainmentPresenter){
categoryRecyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val totalItemCount:Int = categoryLayoutManager.itemCount
val firstVisibleItemPosition:Int = categoryLayoutManager.findFirstVisibleItemPosition()
val visibleItemCount:Int
val lastVisibleItemPosition: Int = categoryLayoutManager.findLastVisibleItemPosition()
visibleItemCount = lastVisibleItemPosition - firstVisibleItemPosition
Log.e("q", lastVisibleItemPosition.toString())
Log.e("q", dy.toString())
if (loading) {
if (totalItemCount > previousTotal) {
loading = false
previousTotal = totalItemCount
}
}
if (!loading && totalItemCount - visibleItemCount <= firstVisibleItemPosition) {
Log.e("q", lastVisibleItemPosition.toString())
loading = true
}
}
})
}
I used it before on RecyclerView that has linear LayoutManger and every thing was great.
But when I used it with RecyclerView that has GridLayoutManager, things got weird.
It implemented only once and doesn't work when i scroll.
Last visible item position return totalItemCount-1.
Last thing: this I call this function in onCreate and I tried it with RecyclerView that has linear layout manager and everything was great
Here's my logcat,
2018-10-06 06:10:15.919 11033-11033/com.example.karem.moviesdatabase E/q: 0
2018-10-06 06:10:15.919 11033-11033/com.example.karem.moviesdatabase E/q: 18
It only called once and nothing happen when I scroll.
my RecyclerView height was set to match_parent
but after i change height to be 500dp everything works well
i don't know why but anyway here's my old layout
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/layoutBackground"
tools:context=".fragments.AllItemsFragment">
<android.support.v7.widget.RecyclerView
android:id="#+id/categoryRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/entertainment_recycler_view_item" />
<ProgressBar
android:id="#+id/loadingCategoryList"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/categoryRecyclerView"
app:layout_constraintEnd_toEndOf="#+id/categoryRecyclerView"
app:layout_constraintStart_toStartOf="#+id/categoryRecyclerView"
app:layout_constraintTop_toTopOf="#+id/categoryRecyclerView" />
</android.support.constraint.ConstraintLayout>
i only change recyclerview height to 500dp and it works
answer more weird than the question
Related
Good Afternoon, I have been trying to add my extended floating button to change to a normal floating button when scrolling but nothing happen and it stays extended and im not sure when:
my orderdetail (Where I call the extension):
recyclerView.addOnScrollListener(FabExtendingOnScrollListener(extended_fab))
where it should do extend or squish:
class FabExtendingOnScrollListener(
private val floatingActionButton: ExtendedFloatingActionButton
) : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE
&& !floatingActionButton.isExtended
&& recyclerView.computeVerticalScrollOffset() == 0
) {
floatingActionButton.extend()
}
super.onScrollStateChanged(recyclerView, newState)
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (dy != 0 && floatingActionButton.isExtended) {
floatingActionButton.shrink()
}
super.onScrolled(recyclerView, dx, dy)
}
}
My xml file(Added only area that matters):
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/btnContainer">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/extended_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_margin="16dp"
android:layout_marginEnd="275dp"
app:icon="#drawable/ic_hourglass"
android:text="Delay order"
android:backgroundTint="#color/standardOrange"
android:layout_marginBottom="667dp">
</com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
</layout>
So this helps to show the button but however it doesnt shrink or extend at all
please use
floatingActionButton.shrink();
I made a viewpager2 which has two Fragments, inside each Fragment there is a Recyclerview. The viewpager itself is inside a Nestedscrollview in order to hide the toolbar when scroll up. Here is my code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways">
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
app:tabGravity="fill"
app:tabMode="fixed"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<include layout="#layout/material_design_floating_action_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
As I said the viewPager2 have two fragment each of them have a recyclerview. Here problem is, fragment 2 recyclerView take the same height of fragment 1 recyclerView though both recyclerView have different list items and their height should be depends on the list items. I mean, I am expecting these recyclerViews height should act separately based on the list. How can I solve this issue? Please let me know if you need fragment code.
Edit:
Activity code which holds the viewPager2
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initToolbar();
init();
viewPager.setAdapter(createCardAdapter());
new TabLayoutMediator(tabLayout, viewPager,
new TabLayoutMediator.TabConfigurationStrategy() {
#Override public void onConfigureTab(#NonNull TabLayout.Tab tab, int position) {
//tab.setText("Tab " + (position + 1));
if(position == 0){
tab.setText("Home");
}else if(position == 1){
tab.setText("Events");
}
}
}).attach();
RunnTimePermissions.requestForAllRuntimePermissions(this);
showNotifyDialog();
}
ViewPager Adapter Code:
public class ViewPagerAdapter extends FragmentStateAdapter {
private static final int CARD_ITEM_SIZE = 2;
public ViewPagerAdapter(#NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
}
#NonNull #Override public Fragment createFragment(int position) {
switch (position){
case 0:
return HomeFragment.newInstance("abc","abc");
// break;
case 1:
return EventListFragment.newInstance("abc","abc");
// break;
}
return HomeFragment.newInstance("abc","abc");
}
#Override public int getItemCount() {
return CARD_ITEM_SIZE;
}
}
Fragment 1 layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragment.EventListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_event_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginTop="16dp"
/>
</FrameLayout>
Fragment 2 layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragment.MedicineListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_medicine_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginTop="16dp"
/>
</FrameLayout>
Alright buddy. I did it! I have the solution to this issue.
First off, here's the official response from Google after I opened an issue.
https://issuetracker.google.com/issues/188474850?pli=1
Anyway, on to the fix. Replace the NestedScrollView with this class:
https://gist.github.com/AfzalivE/fdce03eeee8e16203bcc37ba26d7abf3
The idea is to basically create a very light-weight version of NestedScrollView. Instead of messing with child heights, we listen to the children's scroll and either let them scroll, or forward the scrolling to the BottomSheetBehavior. For example when the RecyclerView has been scrolled all the way to the top, then it doesn't consume any of the scrolling, so we can forward that to the bottom sheet so it can scroll. And we only allow the RecyclerView to scroll when the Bottom sheet is expanded.
Also, I must add that this scenario works out of the box with Jetpack Compose + Accompanist-pager so just do that if you really need perfect functionality.
class BottomSheetScrollView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs),
NestedScrollingParent2 {
private val TAG = "NestedScroll3"
private val childHelper = NestedScrollingChildHelper(this).apply {
isNestedScrollingEnabled = true
}
private var behavior: BottomSheetBehavior<*>? = null
var started = false
var canScroll = false
var pendingCanScroll = false
var dyPreScroll = 0
init {
ViewCompat.setNestedScrollingEnabled(this, true)
}
private val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
onNextScrollStop(newState == BottomSheetBehavior.STATE_EXPANDED)
Log.d(
"BottomSheet",
"Can scroll CHANGED to: $canScroll, because bottom sheet state is ${
getBottomSheetStateString(newState)
}"
)
}
override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
}
fun onNextScrollStop(canScroll: Boolean) {
pendingCanScroll = canScroll
}
override fun onStartNestedScroll(child: View, target: View, axes: Int, type: Int): Boolean {
// ViewPager2's RecyclerView does not participate in this nested scrolling.
// This allows it to show it's overscroll indicator.
if (target is RecyclerView) {
val layoutManager = target.layoutManager as LinearLayoutManager
if (layoutManager.orientation == LinearLayoutManager.HORIZONTAL) {
target.isNestedScrollingEnabled = false
}
}
if (!started) {
Log.d(TAG, "started nested scroll from $target")
childHelper.startNestedScroll(axes, type)
started = true
}
return true
}
override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) {
Log.d(TAG, "accepted nested scroll from $target")
}
override fun onStopNestedScroll(target: View, type: Int) {
if (started) {
childHelper.stopNestedScroll(type)
started = false
Log.d(
TAG,
"stopped nested scroll from $target, changing canScroll from $canScroll to $pendingCanScroll"
)
canScroll = pendingCanScroll
}
}
override fun onNestedScroll(
target: View,
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
type: Int
) {
Log.d(
TAG,
"onNestedScroll: dxC: $dxConsumed, dyC: $dyConsumed, dxU: $dxUnconsumed, dyU: $dyUnconsumed"
)
if (dyUnconsumed == dyPreScroll && dyPreScroll < 0) {
canScroll = false
Log.d(TAG, "Can scroll CHANGED to: $canScroll, because scrolled to the top of the list")
}
}
override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
Log.d(
TAG,
"onNestedPreScroll: dx: $dx, dy: $dy, consumed: [ ${consumed.joinToString(", ")} ]"
)
if (!canScroll) {
childHelper.dispatchNestedPreScroll(dx, dy, consumed, null, type)
// Ensure all dy is consumed to prevent premature scrolling when not allowed.
consumed[1] = dy
} else {
dyPreScroll = dy
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
behavior = findBottomSheetBehaviorParent(parent) as BottomSheetBehavior<*>?
behavior?.addBottomSheetCallback(bottomSheetCallback)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
behavior?.removeBottomSheetCallback(bottomSheetCallback)
}
private fun findBottomSheetBehaviorParent(parent: ViewParent?): CoordinatorLayout.Behavior<*>? {
if (parent !is View) {
throw IllegalArgumentException(
"None of this view's ancestors are associated with BottomSheetBehavior"
)
}
val layoutParams = parent.layoutParams
return if (layoutParams is CoordinatorLayout.LayoutParams && layoutParams.behavior != null) {
layoutParams.behavior
} else {
findBottomSheetBehaviorParent((parent as View).parent)
}
}
private fun getBottomSheetStateString(state: Int): String {
return when (state) {
1 -> "STATE_DRAGGING"
2 -> "STATE_SETTLING"
3 -> "STATE_EXPANDED"
4 -> "STATE_COLLAPSED"
5 -> "STATE_HIDDEN"
6 -> "STATE_HALF_EXPANDED"
else -> "0"
}
}
}
I do not understand why you have recyclerview inside FrameLayout .
Here problem is, fragment 2 recyclerView take the same height of
fragment 1 recyclerView though both recyclerView have different list
items and their height should be depends on the list items
RecyclerView generally always depends on the item_layout until we have not fixed its height n width to match_parent.
In your case you have fixed RecyclerView android:layout_width and android:layout_width to match_parent in both the Fragment .
Try this:
Fragment 1
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragment.EventListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_event_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
/>
</FrameLayout>
Fragment 2
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".fragment.MedicineListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_medicine_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
/>
</FrameLayout>
P.S: assuming each reacyclerView's item_layout would be having height as wrap_content
I have a problem with scrolling, AppBarLayout not fully scrolls to out of screen.
How can i to continue scroll to statusbar height?
But if i set to root layout (CoordinatorLayout) fitsSystemWIndows=false, no problem with scroll, but status bar becomes without alpha channel.
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/search_appbar"
android:layout_width="match_parent"
android:layout_height="50dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
...
other layouts here
...
</LinearLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Add Scrolling behaviour to your Toolbar which is inside AppbarLayout.
app:layout_scrollFlags="scroll|enterAlways"
EDIT:- Replace scrolling behaviour of CollapsingToolbarLayout with below code.
app:layout_scrollFlags="scroll|exitUntilCollapsed"
I found solution.
Maybe someone it helps.
create package: com.google.android.material.appbar
create class which extend AppBarLayout.Behavior
Result in the image
package com.google.android.material.appbar
import ...
class OffsetBehavior(c: Context, a: AttributeSet) : AppBarLayout.Behavior(c, a)
{
private var mOffset = 0
fun setOffset(value: Int) {
mOffset = value
}
// completely copy the method onNestedPreScroll from AppBarLaout.Behavior
// and add some changes
override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: AppBarLayout, target: View, dx: Int, dy: Int, consumed: IntArray, type: Int)
{
if (dy != 0) {
val min: Int
val max: Int
// scroll down
if (dy < 0) {
min = -(child.totalScrollRange + mOffset)
max = min + child.downNestedPreScrollRange + mOffset
}
// scroll up
else {
min = -(child.upNestedPreScrollRange + mOffset)
max = 0
}
if (min != max) {
consumed[1] = scroll(coordinatorLayout, child, dy, min, max)
}
}
if (child.isLiftOnScroll) {
child.setLiftedState(child.shouldLift(target))
}
}
}
and then set it to AppBarLayout in XML
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/search_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.OffsetBehavior">
...
</com.google.android.material.appbar.AppBarLayout>
in the Activity:
(1) add fun
// getting statusbar height
// my phone with Android9 = 96px
// my phone with Android7 = 72px
fun getStatusBarHeight(): Int {
val id = resources.getIdentifier("status_bar_height", "dimen", "android")
return if (id > 0) {
resources.getDimensionPixelSize(id)
} else {
0
}
}
(2) in onCreate()
val lp = search_appbar?.layoutParams as? CoordinatorLayout.LayoutParams
val bh = lp?.behavior as? com.google.android.material.appbar.OffsetBehavior
bh?.setOffset(getStatusBarHeight())
Result:
https://i.stack.imgur.com/pNeze.gif
I am working on chat app so I want time TextView to be like whats app it's constraint can change depend on the text
So I tried the view tree observer in the message layout and it somehow worked but there something missing
private fun adjustTimeTextView() {
var freeSpace: Float
var lines: Int
val messageViewObserver = messageView.messageLayout.viewTreeObserver
messageViewObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
messageView.messageLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
val viewWidth = messageView.messageLayout.width
Log.e("message view width", viewWidth.toString())
val layout = messageView.messageTextTextView.layout
if (layout != null) {
lines = layout.lineCount
Log.e("line", lines.toString())
val offset = layout.getLineWidth(lines - 1)
freeSpace = viewWidth - offset
if (freeSpace < 220) {
Log.e("minmum", "low free space")
val constraintSet = ConstraintSet()
constraintSet.clone(messageView.messageLayout)
constraintSet.clear(messageView.messageLayout.messageTimeTextView.id, ConstraintSet.TOP)
constraintSet.clear(messageView.messageLayout.messageTimeTextView.id, ConstraintSet.BOTTOM)
constraintSet.clear(messageView.messageLayout.messageTimeTextView.id, ConstraintSet.START)
constraintSet.connect(
messageView.messageLayout.messageTimeTextView.id,
ConstraintSet.TOP,
messageView.messageLayout.messageTextTextView.id,
ConstraintSet.BOTTOM
)
constraintSet.applyTo(messageView.messageLayout)
} else {
if (lines > 1) {
val constraintSet = ConstraintSet()
constraintSet.clone(messageView.messageLayout)
constraintSet.clear(
messageView.messageLayout.messageTimeTextView.id,
ConstraintSet.START
)
constraintSet.applyTo(messageView.messageLayout)
}
}
}
}
})
}
and here is my layout xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.constraint.Guideline
android:id="#+id/endGuideline"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent="0.65"/>
<android.support.constraint.Guideline
android:id="#+id/startGuideline"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent="0.35"/>
<android.support.constraint.ConstraintLayout
android:id="#+id/messageLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constrainedWidth="true"
android:padding="4dp"
app:layout_constraintEnd_toStartOf="#+id/endGuideline"
android:background="#drawable/sender_message_background"
android:orientation="vertical"
app:layout_constraintWidth_default="wrap"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toBottomOf="#+id/messageDateTextView" android:layout_marginTop="8dp">
<TextView
android:id="#+id/messageTextTextView"
tools:text="hi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" android:layout_marginEnd="8dp"/>
<TextView
android:id="#+id/messageTimeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12:34 pm"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="#+id/messageTextTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/messageTextTextView"
app:layout_constraintStart_toEndOf="#+id/messageTextTextView"
android:layout_marginStart="8dp" app:layout_constraintVertical_bias="0.51"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
The problem is that when I open an existing chat the constraint as first image appear didn't work as expected in the long message but as soon as I click on type a message edit text the constraint changed for the screen chat not for all chat so if i scrolled the constraints of chat on screen is unchanged unless i click on type a message edit text and so on.
am i missing listener or request focus or something else or what is missing
Here is picture one
Here is picture two
In my opinion, the solution here is to use app:layout_constrainedWidth="true". Requesting layout is a heavy task and should not be performed on scroll.
it worked by make recyclerView request layout
i added this code to recyclerview adapter
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener(){
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
recyclerView.requestLayout()
}
})
}
I'm trying to implement the same behaviour than the CollapsingToolbarLayout for a view above my recyclerview that collapses to a minimum height on downscrolling and restores to its normal height when the scroll reaches the top. This header is not a Toolbar, hence the custom view.
I managed to do it, but when scrolling up it restores the height but the whole view starts flickering.
This is the header layout, I am trying to make the Textview disappear while keeping the inner linear layout visible at all times:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="#+id/welcome_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="welcome"/>
<LinearLayout
android:id="#+id/always_show"
android:layout_width="match_parent"
android:layout_height="36dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_margin="12dp">
...
</LinearLayout>
</LinearLayout>
And this is the code
var maxHeight: Int = 0
var initialSize = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
header.getViewTreeObserver().addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (initialSize)
return
initialSize = true
maxHeight = header.measuredHeight
}
})
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
//scroll down
val params = header.layoutParams as LinearLayout.LayoutParams
params.topMargin = Math.max(params.topMargin-dy, -maxHeight/2)
header.layoutParams = params
} else if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
//top
val params = header.layoutParams as LinearLayout.LayoutParams
params.topMargin = 0
header.layoutParams = params
}
}
})
}
Any ideas on how to make this animation more natural, closest to the CollapsingToolbarLayout behaviour.