I have a Jetpack Compose App that uses a Horizontal Pager. The behavior I am seeing is that when I swipe to my next page it moves smooth, but when I swipe back the screen advances about 3/4 of the way and pauses and then if I wait it completes the swipe.
Question:
Is this normal and controlled by the Fling Behavior?
Or could it be my implementation?
Has anyone else experienced this?
It depends on the content in horizontal pager.When I use a simple coil image, it works fine.But when I have vertical pager/lazy column inside a horizontal pager, it lags.
Also mentioned here:
How to optimise laggy JetPack Compose layout
Related
Background
I have created a Composable that contains a TopAppBar and a WebView which recreates the enterAlways collapsing-toolbar behavior that Xml has.
The way it works is by applying Modifier.offset {..} to the composables. The offset is calculated whenever the WebView is scrolled.
For example, if I'm at the top of the page, and I scroll towards the bottom of the page (swipe from bottom to top), the Y offset for both the WebView & TopAppBar decreases at the same time.
Problem
The problem is that it is very jittery whenever the TopAppBar is expanding or collapsing. I think this is because the offset for the WebView is changing while I'm still scrolling. In the previous example, the WebView moves up to take the place of the collapsing-toolbar, but my finger is still pressed on the screen while that happens, which may cause the device to interpret that as an upward scroll (swiping from top to bottom).
Basic Outline of Code:
Column {
TopAppBar(
Modifier.offset { IntOffset(0, state.toolbarOffsetHeightPx) },
...
)
WebView(
Modifier.offset { IntOffset(0, state.toolbarOffsetHeightPx) },
onWebPageScrolled = /** Update state.toolbarOffsetHeightPx */
...
)
}
What I tried
One potential solution I thought of involves reading the scrolls (like I currently am) and also consuming them.
When the toolbar is collapsing or expanding, I realized that I should probably only adjust the offset during that time, and I should ensure that the WebView does not scroll its content.
Since the WebView's height is the screen height, when the TopAppBar is collapsing, the part of the WebView which was hidden at the bottom of the screen now comes into view, and to the user, the offset of the WebView changing would make it look like they are scrolling. Therefore, I should force the WebView to not scroll during this time.
--
The problem with this approach is that I'm getting the data about WebView scrolls from the onScrollChangedListener, so if I disable WebView scrolling while the TopAppBar is expanding or collapsing, then I also lose the ability to keep expanding/collapsing the TopAppBar...
Some solutions I came up for this are:
Have a wrapper Composable around the WebView which can receive the scrolls.
I could not figure out how to implement this. It looks like there is a nestedScrolling Modifier which allows capturing scrolls, so I wrapped my WebView in a Box which had that Modifier, but even though I was consuming the scrolls in the NestedScrollConnection the WebView was still receiving scrolls normally..
Use onTouchListener to receive scroll events rather than onScrollListener.
This gets a little complicated because onTouchListener is not only called for scrolls. I tried only running my TopAppBar/WebView offset logic if the onTouchListener was called for MotionEvent.ACTION_DOWN, but the results were very strange.
I did manage to replicate the original expanding/collapsing w/ the TopAppBar & WebView, but rather than expanding/collapsing while I'm scrolling, the entire expanding/collapsing would complete before I even started dragging my finger - just pressing my finger and twisting it up or down completely expanded/collapsed the TopAppBar.
The desired behavior is that the expanding/collapsing should happen linearly with the webpage scrolling, so this did not work.
I really appreciate any help. I've created a simple app on a GitHub repo if you would like to test the behavior.
I want to create my own version of ViewPager2 so that I can control the animation design and orientation capabilities. Basically, I'm trying to have a scrolling up and down load new users while left and right would be more information about that user.
I tried using custom animations with swipe gestures, which works exactly as I wanted, except I don't get the control of dynamically animating the swiping direction. Essentially, it still works like a button animation - you might swipe in the direction you want but the animation speed/feel/etc is always the same animation vs. ViewPager2's ability to move with the gesture.
I experimented with OnDragListeners which do give me the "Tinder card movement" animation effect but I don't want to allow for animations in all directions. I was able to use a ViewPager2 for the horizontal direction while using the OnDragListener to override the swiping (using OnLongClick). When you drag up or down it has the same issue of the transition animation being the same speed/feel/etc everytime instead of the nice ViewPager2 slide on touch effect.
I only need 4 fragments for each user so my next idea was to try a horizontalscrollview in a recyclerview but that's working either.
Any suggestions for an approach I might not have considered?
I need to emulate the behavior of Instagram's Reels which scrolls to the next or previous page when the current page is scrolled more than 50% upwards or downwards respectively and the finger goes up. ViewPager2's default behavior isn't satisfactory for this and I don't think I can change it without changing the PagerSnapHelper inside ViewPager2.
Is there any other way I can implement a custom Snap behavior for ViewPager2 then?
I'm trying to figure out the best approach to design a horizontal scrollview from android >= 2.1 with some text over the image that when scroll if end is reached it starts showing the first items again hence carousel behavior.
You can continue scrolling horizontally, forever, and the first item shows up again when the end is reached, for example when scrolling swiping to the left. It can be a view pager with an adapter, a carousel but not horizontal scrollview as it does not support some android device.
Any suggestions would be greatly appreciated.
Why not use a ViewPager? As it is available in the Support Library. I would insist to use ViewPager instead of HorizontalScrollView or Gallery. You can check an example for ViewPager from my github.
UPDATE
To show multiple views inside a Fragment you can use getPageWidth(). Check here for reference.
For future people looking for this, here's an excellent library that fit my needs for a similar problem!
https://github.com/sparrow007/CarouselRecyclerview
I've made an activity that looks a lot like the level select screen from angry birds: there is a grid of button, and you can scroll through pages of them by swiping right or left.
I built it by creating a layout of the buttons, and then adding those layout to a Gallery view.
The problem is the animation is jerky, even if you swipe extra slowly, the content jumps ahead. Even when you fling the gallery page, it skips and jumps along its way to its destination.
I am wondering how to fix this: Maybe the complex layout it making it non responsive during the inflate?
Do you know how to fix this, or of a good way to do a workaround using some other approach that will let me have 3 or more screens smoothly swiping from page to page?
You should be using ViewPager. This is available in android support packages. Gallery Widget will not be smooth if you add components into it which has a lot of touch actions.
http://android-developers.blogspot.in/2011/08/horizontal-view-swiping-with-viewpager.html