改变ViewPager2以编程方式滑动时的滚动速度 您所在的位置:网站首页 安卓viewpager滑动冲突 改变ViewPager2以编程方式滑动时的滚动速度

改变ViewPager2以编程方式滑动时的滚动速度

2023-04-21 17:17| 来源: 网络整理| 查看: 265

百度翻译此文   有道翻译此文 问题描述

I know there is way to change animation duration of ViewPager programmatical slide (here).

But its not working on ViewPager2

I tried this:

try { final Field scrollerField = ViewPager2.class.getDeclaredField("mScroller"); scrollerField.setAccessible(true); final ResizeViewPagerScroller scroller = new ResizeViewPagerScroller(getContext()); scrollerField.set(mViewPager, scroller); } catch (Exception e) { e.printStackTrace(); }

IDE gives me warning on "mScroller":

Cannot resolve field 'mScroller'

If we Run This code thats not going to work and give us Error below:

No field mScroller in class Landroidx/viewpager2/widget/ViewPager2; (declaration of 'androidx.viewpager2.widget.ViewPager2' appears in /data/app/{packagename}-RWJhF9Gydojax8zFyFwFXg==/base.apk)

So how we can acheive this functionality?

推荐答案

Based on this issue ticket Android team is not planning to support such behavior for ViewPager2, advise from the ticket is to use ViewPager2.fakeDragBy(). Disadvantage of this method is that you have to supply page width in pixels, although if your page width is the same as ViewPager's width then you can use that value instead.

Here's sample implementation

fun ViewPager2.setCurrentItem( item: Int, duration: Long, interpolator: TimeInterpolator = AccelerateDecelerateInterpolator(), pagePxWidth: Int = width // Default value taken from getWidth() from ViewPager2 view ) { val pxToDrag: Int = pagePxWidth * (item - currentItem) val animator = ValueAnimator.ofInt(0, pxToDrag) var previousValue = 0 animator.addUpdateListener { valueAnimator -> val currentValue = valueAnimator.animatedValue as Int val currentPxToDrag = (currentValue - previousValue).toFloat() fakeDragBy(-currentPxToDrag) previousValue = currentValue } animator.addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator?) { beginFakeDrag() } override fun onAnimationEnd(animation: Animator?) { endFakeDrag() } override fun onAnimationCancel(animation: Animator?) { /* Ignored */ } override fun onAnimationRepeat(animation: Animator?) { /* Ignored */ } }) animator.interpolator = interpolator animator.duration = duration animator.start() }

To support RTL you have to flip the value supplied to ViewPager2.fakeDragBy(), so from above example instead of fakeDragBy(-currentPxToDrag) use fakeDragBy(currentPxToDrag) when using RTL.

Few things to keep in mind when using this, based on official docs:

negative values scroll forward, positive backward (flipped with RTL)

before calling fakeDragBy() use beginFakeDrag() and after you're finished endFakeDrag()

this API can be easily used with onPageScrollStateChanged from ViewPager2.OnPageChangeCallback, where you can distinguish between programmatical drag and user drag thanks to isFakeDragging() method sample implementation from above doesn't have security checks if the given item is correct. Also consider adding cancellation capabilities for UI's lifecycle, it can be easily achieved with RxJava. 其他推荐答案

ViewPager2 team made it REALLY hard to change the scrolling speed. If you look at the method setCurrentItemInternal, they instantiate their own private ScrollToPosition(..) object. along with state management code, so this would be the method that you would have to somehow override.

As a solution from here: https://issuetracker.google.com/issues/122656759, they say use (ViewPager2).fakeDragBy() which is super ugly.

Not the best, just have to wait form them to give us an API to set duration or copy their ViewPager2 code and directly modify their LinearLayoutImpl class.

其他推荐答案

When you want your ViewPager2 to scroll with your speed, and in your direction, and by your number of pages, on some button click, call this function with your parameters. Direction could be leftToRight = true if you want it to be that, or false if you want from right to left, duration is in miliseconds, numberOfPages should be 1, except when you want to go all the way back, when it should be your number of pages for that viewPager:

fun fakeDrag(viewPager: ViewPager2, leftToRight: Boolean, duration: Long, numberOfPages: Int) { val pxToDrag: Int = viewPager.width val animator = ValueAnimator.ofInt(0, pxToDrag) var previousValue = 0 animator.addUpdateListener { valueAnimator -> val currentValue = valueAnimator.animatedValue as Int var currentPxToDrag: Float = (currentValue - previousValue).toFloat() * numberOfPages when { leftToRight -> { currentPxToDrag *= -1 } } viewPager.fakeDragBy(currentPxToDrag) previousValue = currentValue } animator.addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator?) { viewPager.beginFakeDrag() } override fun onAnimationEnd(animation: Animator?) { viewPager.endFakeDrag() } override fun onAnimationCancel(animation: Animator?) { /* Ignored */ } override fun onAnimationRepeat(animation: Animator?) { /* Ignored */ } }) animator.interpolator = AccelerateDecelerateInterpolator() animator.duration = duration animator.start() }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有