webViewをドラッグしたい!
アプリ開発をしている中で、ドラッグして大きさが変えられるwebViewを作ることになりました。
ドラッグして操作できるviewというのを作ったことがなかったので、色々試してみた結果を残しておきます。
パターン1:全体を上下にスライド
DraggableBrowse()がメインのViewです。
DraggableArea()がドラッグする時につかむところ、BrowserWebViewはそのままwebViewです。
以下のコードではDraggableAreaでModifier.draggable
を使って、上下にドラッグしたときにoffsetを増減させています。
このoffsetをDraggableBrowserのColumnのModifier.offset
に渡してあげることでドラッグを実現させています。
DraggableBrowser全体が上下に移動するようなイメージです。
@Composable
private fun DraggableBrowser() {
var offsetY by remember { mutableFloatStateOf(0f) }
Column(
Modifier
.windowInsetsPadding(WindowInsets.statusBars)
.fillMaxWidth()
.offset { IntOffset(x = 0, y = offsetY.roundToInt()) },
verticalArrangement = Arrangement.Bottom,
) {
DraggableArea(
modifier = Modifier
.fillMaxWidth()
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
offsetY = (offsetY + delta).coerceAtLeast(0f)
},
)
)
BrowserWebView(url = "https://www.youtube.com/")
}
}
@Composable
private fun DraggableArea(modifier: Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.height(30.dp)
.background(color = Color.Black),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(width = 40.dp, height = 4.dp)
.border(2.dp, Color.White)
.background(Color.White)
)
}
}
@SuppressLint("SetJavaScriptEnabled")
@Composable
private fun BrowserWebView(url: String, modifier: Modifier = Modifier) {
val isInspecting = LocalInspectionMode.current
var webView: WebView? by remember { mutableStateOf(null) }
Column {
AndroidView(
modifier = modifier.clipToBounds(),
factory = {
WebView(it).apply {
if (!isInspecting) {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
}
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
webChromeClient = WebChromeClient()
loadUrl(url)
}
},
update = { newWebView ->
if (isInspecting) return@AndroidView
webView = newWebView
}
)
}
}
パターン2: webViewを拡大・縮小
こちらのパターンでは、webViewの大きさを変更します。
LocalConfiguration.current.screenHeightDp
であらかじめ画面全体の高さを取得しておきます。
DraggableAreaのModifier.draggable
では上下のドラッグに合わせてwindowSizePxを増減させます。
このwindowSizePxをBrowserWebViewの高さとして設定することで、webViewそのものの高さを増減させることで、ドラッグして引っ張ったり押し込めたりしているように見せることができます。
Modifier.height()
はpx のままだと適用できないので、with(density) { windowSizePx.toDp() }
でdpに変換してから渡しています。
@Composable
private fun DraggableBrowser() {
val density = LocalDensity.current
val screenHeightPx = with(density) { LocalConfiguration.current.screenHeightDp.dp.toPx() }
var windowSizePx by remember { mutableFloatStateOf(screenHeightPx) }
Box(modifier = Modifier.fillMaxSize()) {
Column(
Modifier
.windowInsetsPadding(WindowInsets.statusBars)
.fillMaxWidth()
.align(Alignment.BottomCenter),
verticalArrangement = Arrangement.Bottom,
) {
DraggableArea(
modifier = Modifier
.fillMaxWidth()
.draggable(
orientation = Orientation.Vertical,
state = rememberDraggableState { delta ->
windowSizePx = (windowSizePx - delta).coerceAtMost(screenHeightPx)
},
)
)
BrowserWebView(
url = "https://www.youtube.com/",
modifier = Modifier.height(with(density) { windowSizePx.toDp() }),
)
}
}
}
@Composable
private fun DraggableArea(modifier: Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.height(30.dp)
.background(color = Color.Black),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.size(width = 40.dp, height = 4.dp)
.border(2.dp, Color.White)
.background(Color.White)
)
}
}
@SuppressLint("SetJavaScriptEnabled")
@Composable
private fun BrowserWebView(url: String, modifier: Modifier = Modifier) {
val isInspecting = LocalInspectionMode.current
var webView: WebView? by remember { mutableStateOf(null) }
Column {
AndroidView(
modifier = modifier.clipToBounds(),
factory = {
WebView(it).apply {
if (!isInspecting) {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
}
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
webViewClient = WebViewClient()
webChromeClient = WebChromeClient()
loadUrl(url)
}
},
update = { newWebView ->
if (isInspecting) return@AndroidView
webView = newWebView
}
)
}
}
ドラッグできた
どちらの方法でもドラッグすることができました。
好みで多分大丈夫だとは思いますが、状況によってはうまくいかないこともあると思うのでお気をつけください。
(xmlのcomposeViewにsetContentして使うとうまくいかないこともあるかも......)