LazyColumn内嵌TrustPilot WebView轮播滚动冲突问题求助
解决LazyColumn与TrustPilot WebView轮播的滚动冲突问题
要解决LazyColumn拦截WebView横向滚动事件的问题,核心思路是让WebView优先处理水平方向的滑动操作:当检测到用户是在横向滚动轮播图时,阻止LazyColumn拦截触摸事件;当检测到是垂直滑动时,再交还给LazyColumn处理。
下面提供两种可行的实现方案:
方案一:通过Compose Modifier处理触摸事件
在TrustPilotWidget的外层添加pointerInput修饰符,判断滑动方向并控制父布局的事件拦截:
@SuppressLint("SetJavaScriptEnabled") @Composable fun TrustPilotWidget() { val language = Locale.getDefault().language val bootstrap = "<!-- TrustBox script --> <script type=\"text/javascript\" src=\"https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js\" strategy=\"lazyOnload\"></script> <!-- End Trustbox script -->" val trustBox = "<!-- TrustBox widget - Mini Carousel --> " + "<div class=\"trustpilot-widget\" data-locale=\"${language}\" " + "data-template-id=\"54ad5defc6454f065c28af8b\" " + "data-businessunit-id=\"46d6a890000064000500e0c3\" " + "data-style-height=\"250px\" " + "data-style-width=\"100%\" " + "data-theme=\"light\" " + "data-review-languages=\"${language}\"" + "data-stars=\"5\"> " + "<a href=\"https://www.trustpilot.com/review/revelsystems.com\" target=\"_blank\">Trustpilot</a> </div> <!-- End TrustBox widget -->" // 外层添加pointerInput处理触摸事件 Box( modifier = Modifier .fillMaxWidth() .pointerInput(Unit) { detectDragGestures( onDrag = { change, dragAmount -> val (dx, dy) = dragAmount // 判断滑动方向:横向分量大于纵向时,阻止父布局拦截 if (kotlin.math.abs(dx) > kotlin.math.abs(dy)) { change.consume() parent.requestDisallowInterceptTouchEvent(true) } else { // 纵向滑动时,允许父布局处理 parent.requestDisallowInterceptTouchEvent(false) } }, onDragEnd = { // 拖动结束后恢复父布局的拦截权限 parent.requestDisallowInterceptTouchEvent(false) } ) } ) { AndroidView( factory = { WebView(it).apply { settings.javaScriptEnabled = true setBackgroundColor(android.graphics.Color.TRANSPARENT) } }, update = { it.loadDataWithBaseURL( "https://widget.trustpilot.com", bootstrap + trustBox, "text/html", null, null ) } ) } }
方案二:通过原生WebView的OnTouchListener处理
直接在WebView的初始化代码中设置触摸监听,在原生层面判断滑动方向并控制父布局的事件拦截:
@SuppressLint("SetJavaScriptEnabled") @Composable fun TrustPilotWidget() { val language = Locale.getDefault().language val bootstrap = "<!-- TrustBox script --> <script type=\"text/javascript\" src=\"https://widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js\" strategy=\"lazyOnload\"></script> <!-- End Trustbox script -->" val trustBox = "<!-- TrustBox widget - Mini Carousel --> " + "<div class=\"trustpilot-widget\" data-locale=\"${language}\" " + "data-template-id=\"54ad5defc6454f065c28af8b\" " + "data-businessunit-id=\"46d6a890000064000500e0c3\" " + "data-style-height=\"250px\" " + "data-style-width=\"100%\" " + "data-theme=\"light\" " + "data-review-languages=\"${language}\"" + "data-stars=\"5\"> " + "<a href=\"https://www.trustpilot.com/review/revelsystems.com\" target=\"_blank\">Trustpilot</a> </div> <!-- End TrustBox widget -->" AndroidView( factory = { context -> WebView(context).apply { settings.javaScriptEnabled = true setBackgroundColor(android.graphics.Color.TRANSPARENT) var startX = 0f var startY = 0f // 设置触摸监听 setOnTouchListener { v, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { // 记录触摸起始位置 startX = event.x startY = event.y // 暂时阻止父布局拦截,等待滑动方向判断 v.parent.requestDisallowInterceptTouchEvent(true) } MotionEvent.ACTION_MOVE -> { val dx = kotlin.math.abs(event.x - startX) val dy = kotlin.math.abs(event.y - startY) // 根据滑动分量判断方向 if (dy > dx) { // 纵向滑动,允许父布局拦截(交给LazyColumn处理) v.parent.requestDisallowInterceptTouchEvent(false) } else { // 横向滑动,阻止父布局拦截(交给WebView轮播处理) v.parent.requestDisallowInterceptTouchEvent(true) } } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { // 触摸结束后恢复父布局的拦截权限 v.parent.requestDisallowInterceptTouchEvent(false) } } // 返回false,让WebView自身处理触摸事件 false } } }, update = { it.loadDataWithBaseURL( "https://widget.trustpilot.com", bootstrap + trustBox, "text/html", null, null ) } ) }
两种方案核心逻辑一致,都是通过判断滑动方向决定是否让父布局(LazyColumn)拦截触摸事件,从而避免横向滚动被中断的问题。
内容的提问来源于stack exchange,提问作者Barry Irvine
相关产品推荐
相关产品推荐

