zhpanvip / BannerViewPager

🚀 An awesome banner view for Android,Based on ViewPager2. 这可能是全网最好用的ViewPager轮播图。简单、高效,一行代码实现循环轮播,一屏三页任意变,指示器样式任你挑。
Apache License 2.0
3.59k stars 436 forks source link

Page can only be offset by a positive amount, not by -1 #291

Closed wkbin closed 1 year ago

wkbin commented 1 year ago

这问题出现了有段时间,不确定是否是 ViewPager2.PageTransformer导致

wkbin commented 1 year ago

java.lang.IllegalStateException Page can only be offset by a positive amount, not by -1 androidx.viewpager2.widget.ScrollEventAdapter.updateScrollEventValues(ScrollEventAdapter.java:280) androidx.viewpager2.widget.ScrollEventAdapter.onScrolled(ScrollEventAdapter.java:178) androidx.recyclerview.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:5347) androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5512) android.view.Choreographer$CallbackRecord.run(Choreographer.java:1142) android.view.Choreographer.doCallbacks(Choreographer.java:946) android.view.Choreographer.doFrame(Choreographer.java:870) android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1127) android.os.Handler.handleCallback(Handler.java:938) android.os.Handler.dispatchMessage(Handler.java:99) android.os.Looper.loopOnce(Looper.java:210) android.os.Looper.loop(Looper.java:299) android.app.ActivityThread.main(ActivityThread.java:8118) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)

zhpanvip commented 1 year ago

必现的还是偶现,PageTransformer是自定义的吗

zhpanvip commented 1 year ago

检查一下是不是设置了pageMarge或者revealWidth了,如果这两个值设置成负数是会抛出这个异常的

NewHuLe commented 1 year ago

检查一下是不是设置了pageMarge或者revealWidth了,如果这两个值设置成负数是会抛出这个异常的 image 与pageMarge或者revealWidth无关,我项目中没有设置这两个属性,也发现了此错误,希望作者也排查下是否与本库有关,初步猜测跟mViewPager.setPageTransformer(mCompositePageTransformer)有关系

wkbin commented 1 year ago

问题偶现,但是出现的很频繁,setRevealWidth 是这样设置的

fun getScreenWidth(): Int = Resources.getSystem().displayMetrics.widthPixels setRevealWidth(16.dp, getScreenWidth() - (getScreenWidth() * 136 / 375) - 16.dp)

PageTransformer 是自定义的具体如下 `class ZoomPageTransformer() : ViewPager2.PageTransformer { private var RATE = 0.9f //缩放比率

override fun transformPage(page: View, position: Float) {
    val param = page.layoutParams as RecyclerView.LayoutParams
    val ox = (page.width - page.width * RATE) / 2
    when{
        position < -1f -> {
            page.scaleX = RATE //设置X轴缩放
            page.scaleY = RATE //设置Y轴缩放
        }
        position >= -1f &&  position < 0f -> {
            val s = 1 + position
            page.scaleX = s
            page.scaleY = s
            page.alpha = s
        }
        position >= 0f && position < 1f -> {
            val s = 1 - position *  (1-RATE)
            page.scaleX = s
            page.scaleY = s
        }
        position >= 1f && position < 2f -> {
            val s = (position - 1)
            page.scaleX = RATE
            page.scaleY = RATE
            page.alpha = 1f
            param.leftMargin = (-s * ox).roundToInt()
        }
        else -> {
            page.scaleX = RATE
            page.scaleY = RATE
            page.alpha = 1f
            param.leftMargin = -ox.roundToInt()
        }

    }
    page.layoutParams = param

}

}`

peter100u commented 1 year ago

我也遇到了,你们解决了吗,找到原因了吗

zhpanvip commented 1 year ago

我也遇到了,你们解决了吗,找到原因了吗

麻烦提供一个可以复现的demo,好排查原因

peter100u commented 1 year ago

没发复现呢,线上很多crash,但是都是>Android11的设备,测试一直无法出现

zhpanvip commented 1 year ago

没发复现呢,线上很多crash,但是都是>Android11的设备,测试一直无法出现

你提供一下你写的代码吧

peter100u commented 1 year ago

没发复现呢,线上很多crash,但是都是>Android11的设备,测试一直无法出现

你提供一下你写的代码吧

不知道是什么地方呢,我昨天用Aspect暂时处理下,等用户反馈后,我看看日志

@Aspect public class InsertTryErrorScrollEventAdapter {

@Pointcut("execution(* androidx.viewpager2.widget.ScrollEventAdapter.updateScrollEventValues(..))")
public void updateScrollEventValues() {

}

@Around(value = "updateScrollEventValues()")
public Object aroundUpdateScrollEventValues(ProceedingJoinPoint pjp) throws Throwable {
    Object obj = new Object();
    try {
        obj = pjp.proceed();
    } catch (IllegalStateException e) {
        reportErrorInfo();
    } catch (Exception e) {
        reportErrorInfo();
    }
    return obj;
}

}

zhpanvip commented 1 year ago

可以提供一下你是怎么使用BVP的代码,后边我来分析一下原因。

zhpanvip commented 1 year ago

导致此问题的可能原因: 1.revealWidth设置了负数,且pageMargin+revealWidth<0; 2.自定义的Transformer有问题; 3.通过mViewPager.getChildAt(0).setPadding(padding),padding为负数; 4.ViewPager自身bug(可能性不大) BVP能够优化的只有第1点

zhpanvip commented 1 year ago

RecyclerView

问题偶现,但是出现的很频繁,setRevealWidth 是这样设置的

fun getScreenWidth(): Int = Resources.getSystem().displayMetrics.widthPixels setRevealWidth(16.dp, getScreenWidth() - (getScreenWidth() * 136 / 375) - 16.dp)

PageTransformer 是自定义的具体如下 `class ZoomPageTransformer() : ViewPager2.PageTransformer { private var RATE = 0.9f //缩放比率

override fun transformPage(page: View, position: Float) {
    val param = page.layoutParams as RecyclerView.LayoutParams
    val ox = (page.width - page.width * RATE) / 2
    when{
        position < -1f -> {
            page.scaleX = RATE //设置X轴缩放
            page.scaleY = RATE //设置Y轴缩放
        }
        position >= -1f &&  position < 0f -> {
            val s = 1 + position
            page.scaleX = s
            page.scaleY = s
            page.alpha = s
        }
        position >= 0f && position < 1f -> {
            val s = 1 - position *  (1-RATE)
            page.scaleX = s
            page.scaleY = s
        }
        position >= 1f && position < 2f -> {
            val s = (position - 1)
            page.scaleX = RATE
            page.scaleY = RATE
            page.alpha = 1f
            param.leftMargin = (-s * ox).roundToInt()
        }
        else -> {
            page.scaleX = RATE
            page.scaleY = RATE
            page.alpha = 1f
            param.leftMargin = -ox.roundToInt()
        }

    }
    page.layoutParams = param

}

}`

你这个问题确实是你的PageTransformer导致的,param.leftMargin的值如果是负数就会出现这个crash。