I have a TrustPilot webview within a LazyColumn
but scrolling the carousel horizontally is very glitchy. Any slight vertical movement will be intercepted by the LazyColumn
and stop the horizontal scroll of the carousel.
Is there a way to allow the carousel to scroll horizontally without competing with the vertical scroll of the lazy list.
Here is a simple example that easily shows the issue:
Scaffold { padding ->
LazyColumn(contentPadding = padding) {
item {
TrustPilotWidget()
}
}
}
Where TrustPilotWidget looks like this:
@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 = {
WebView(it).apply {
settings.javaScriptEnabled = true
setBackgroundColor(android.graphics.Color.TRANSPARENT)
}
},
update = {
it.loadDataWithBaseURL(
"https://widget.trustpilot.com",
bootstrap + trustBox,
"text/html",
null,
null
)
}
)
}
You need have a gesture for checking if user scrolled horizontally and based on that result disable user gesture.
For a gesture to work you shouldn't consume it and get it even if AnroidView consumes it with
val down = awaitFirstDown(requireUnconsumed = false)
Then after first touch and move following first touch check whether moved pointer horizontally only for once with
.pointerInput(Unit) {
awaitEachGesture {
val down = awaitFirstDown(requireUnconsumed = false)
val initialPosition = down.position
var isPositionCheckDone = false
do {
val event: PointerEvent = awaitPointerEvent()
event.changes.forEach {
if (isPositionCheckDone.not()) {
val position = it.position
val diff = initialPosition.x - position.x
isWebViewTouched = diff != 0f
isPositionCheckDone = true
}
}
} while (event.changes.any { it.pressed })
isWebViewTouched = false
}
}
And assign this isWebViewTouched to LazyColumn
var isWebViewTouched by remember {
mutableStateOf(false)
}
LazyColumn(
userScrollEnabled = isWebViewTouched.not(),
contentPadding = padding
) {
// Rest of the code
}
Result
Full code
@Preview
@Composable
fun ScrollTest() {
Scaffold { padding ->
var isWebViewTouched by remember {
mutableStateOf(false)
}
LazyColumn(
userScrollEnabled = isWebViewTouched.not(),
contentPadding = padding
) {
items(5) {
Box(
modifier = Modifier.fillMaxWidth().height(50.dp).background(Color.Red)
)
}
item {
Box(
modifier = Modifier
.pointerInput(Unit) {
awaitEachGesture {
val down = awaitFirstDown(requireUnconsumed = false)
val initialPosition = down.position
var isPositionCheckDone = false
do {
val event: PointerEvent = awaitPointerEvent()
event.changes.forEach {
if (isPositionCheckDone.not()) {
val position = it.position
val diff = initialPosition.x - position.x
isWebViewTouched = diff != 0f
isPositionCheckDone = true
}
}
} while (event.changes.any { it.pressed })
isWebViewTouched = false
}
}
) {
TrustPilotWidget()
}
}
items(10) {
Box(
modifier = Modifier.fillMaxWidth().height(50.dp).background(Color.Red)
)
}
}
}
}