[소소한 개발 일지] SwiftUI 기반 macOS 애플리케이션의 타이틀바 영역에 커스텀 뷰 추가하기
FE 개발자를 위한 안드로이드 후려치기 #5 투명한 액티비티(웹뷰), 풀스크린 웹뷰, 웹뷰 링크 및 뒤로가기 설정하기
2023-09-29
Explanation
한동안 꾸준히 포스팅을 하나 했으나, 어느세 한달이 지나버렸네요..
오늘은 추석 연휴를 맞이하여, 마음을 다잡고 이것저것 공부도 좀 하고 포스팅도 좀 해보려고 합니다!!
그 첫번째로, 짧은 시간이지만 제가 약간 알아보고 사용해봤던 것들을 정리도 할 겸!!
투명한 액티비티(웹뷰) 만들기, 풀스크린 웹뷰 만들기, 웹뷰 링크 및 뒤로가기 구현하기를 묶어서 적어보려 합니다.
작성된 코드는 https://github.com/falsy/blog-post-example/tree/master/android-for-frontend/webview-others 에서 확인하실 수 있습니다!
먼저 ‘TransparentActivity’라는 이름으로 액티비티를 만들어주었어요.
그리고 res/values/styles.xml 을 새로 만들어서 아래와 같이 추가해 주었습니다.
1 2 3 4 5 6 7 8 9 10 11 |
<!-- res/values/styles.xml --> <?xml version="1.0" encoding="utf-8"?> <resources> <style name="Theme.Transparent" parent="Theme.AppCompat.NoActionBar"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:backgroundDimEnabled">false</item> </style> </resources> |
windowIsTranslucent: 윈도우를 투명하게 설정
windowBackground: 윈도우 배경 색을 지정
windowContentOverlay: 일반적으로 타이틀 아래에 그림자를 그릴때 쓴다는데 뭔지 잘 모르겠네요..
(https://developer.android.com/reference/android/R.attr#windowContentOverlay)
windowNoTitle: 타이틀바 없애기
backgroundDimEnabled: 투명 앱티비티의 dimmed 영역을 사용할지??
다음으로 레이아웃 xml을 수정해 줄게요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<!-- res/lauout/activity_transparent.xml --> <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".TransparentActivity"> <WebView android:id="@+id/webView1" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="1.0" /> </androidx.constraintlayout.widget.ConstraintLayout> |
다음으로 TransparentActivity 액티비티를 수정해 줄게요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// java/com.example.frontend/TransparentActivity package com.example.frontend import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.webkit.WebView class TransparentActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_transparent) window.statusBarColor = Color.TRANSPARENT val myWebView: WebView = findViewById(R.id.webView1) myWebView.settings.javaScriptEnabled = true myWebView.setBackgroundColor(0) myWebView.loadUrl("http://10.0.2.2:8080") } } |
코드는 간단하죠? ‘window.statusBarColor = Color.TRANSPARENT’ 로 상단바 색을 투명하게 하고 ‘myWebView.setBackgroundColor(0)’ 로 웹뷰의 배경 색을 투명하게 설정해줬어요.
이제 마지막으로 매니페스트를 수정해줄게요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<!-- manifests/AndroidManifest.xml --> <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Frontend" android:usesCleartextTraffic="true" tools:targetApi="31"> <activity android:name=".TransparentActivity" android:theme="@style/Theme.Transparent" android:exported="false" /> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="" /> </activity> </application> </manifest> |
추가한 내용은 대충, TransparentActivity 라는 액티비티에 ‘android:theme=”@style/Theme.Transparent”‘라는 속성을 추가했어요. 아까 만들었던 styles.xml에 투명한 테마를 액티비티에 적용하였습니다.
끝!
캡처가 헷갈랄 수 있는데.. hello world가 투명한 새로운 액티비티의 웹뷰로 위에 떠 있는거에요.
그냥 단순하게 액티비티의 상단바를 투명하게 하는건 앞 서 작성했던 것처럼, ‘window.statusBarColor = Color.TRANSPARENT’ 로 설정할 수 있는데요.
여기서 적으려고 하는 내용은, 풀스크린으로 적용하는 방법을 적어보려합니다.
풀스크린 웹뷰를 사용하면 상단바의 영역까지도 웹뷰의 영역에 포함하기 때문에 다이얼로그를 띄울때 dimmed 처리도 웹뷰내에서 직접 할 수 있는 장점이 있답니다!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// java/com.example.frontend/TransparentActivity package com.example.frontend import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.webkit.WebView class TransparentActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_transparent) window.statusBarColor = Color.TRANSPARENT window.setDecorFitsSystemWindows(false) val myWebView: WebView = findViewById(R.id.webView1) myWebView.settings.javaScriptEnabled = true myWebView.setBackgroundColor(0) myWebView.loadUrl("http://10.0.2.2:8080") } } |
풀스크린으로 웹뷰를 사용하는 건 간단한데요. ‘window.setDecorFitsSystemWindows(false)’ 이렇게 속성을 한줄 넣어주면 된답니다!
추가로!
웹뷰가 상단바(+ 네비게이션바)의 영역을 포함한 영역을 갖게되지만, 그래도 일반적으로 상단바 영역은 잘 사용하지 않는데요. 그래서 웹뷰에서 상단바의 영역을 비워놓는 처리가 필요하답니다.
안드로이드에서는 상단바나 네비게이션바 높이값을 알 수 있는데요. 이 값과 ratio 값을 이용해서 웹뷰에서는 상단바(+ 네비게이션바)의 영역을 비워둘 수 있답니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// java/com.example.frontend/TransparentActivity package com.example.frontend import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.webkit.WebView class TransparentActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_transparent) window.statusBarColor = Color.TRANSPARENT window.setDecorFitsSystemWindows(false) val statusBarId = resources.getIdentifier("status_bar_height", "dimen", "android") val navBarId = resources.getIdentifier("navigation_bar_height", "dimen", "android") val statusBarHeight = resources.getDimensionPixelSize(statusBarId) val navigationHeight = resources.getDimensionPixelSize(navBarId) val ratio = resources.displayMetrics.scaledDensity val statusHeight = statusBarHeight/ratio val navHeight = navigationHeight/ratio val myWebView: WebView = findViewById(R.id.webView1) myWebView.settings.javaScriptEnabled = true myWebView.loadUrl("http://10.0.2.2:8080/?statusHeight=${statusHeight}&navHeight=${navHeight}") } } |
짜잔 대략적으로 이렇게 웹뷰의 쿼리스트링으로 상단바와 네비게이션바의 높이값을 전달해 줄 수 있습니다!
ratio 값은 브라우저에서도 ‘window.devicePixelRatio’ 값으로 구할 수 있으니, 전달하는 값은 선택적으로 할 수 있을 거 같아요.
안드로이드 웹뷰에서의 기본 링크는 외부 브라우저로 연결되서 출력이되는데요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// java/com.example.frontend/TransparentActivity package com.example.frontend import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.webkit.WebView class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? ): Boolean { view?.loadUrl(request?.url.toString()) return super.shouldOverrideUrlLoading(view, request) } } class TransparentActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_transparent) val myWebView: WebView = findViewById(R.id.webView1) myWebView.settings.javaScriptEnabled = true myWebView.webViewClient = MyWebViewClient() myWebView.loadUrl("http://10.0.2.2:8080") } } |
짜잔, 이렇게 웹뷰 클라이언트의 shouldOverrideUrlLoading를 오버라이드해주면 된답니다!
그러면 이제 링크를 누르면 웹뷰 내에서 페이지가 이동됩니다.
기본적으로 디바이스의 백키(혹은 네비게이션의 백키)를 누르면 기본적으로는 가장 위에 있는 스택을 종료하는데요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
// java/com.example.frontend/TransparentActivity package com.example.frontend import android.graphics.Color import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.webkit.WebView class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? ): Boolean { view?.loadUrl(request?.url.toString()) return super.shouldOverrideUrlLoading(view, request) } } class TransparentActivity : AppCompatActivity() { private lateinit var myWebView: WebView; override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_transparent) myWebView = findViewById(R.id.webView1) myWebView.settings.javaScriptEnabled = true myWebView.webViewClient = MyWebViewClient() myWebView.loadUrl("http://10.0.2.2:8080") } override fun onBackPressed() { if (myWebView.canGoBack()) { myWebView.goBack() } else { super.onBackPressed() } } } |
위와 같이 onBackPressed를 오버라이드해서, 디바이스의 백키가 스택을 종료하는 게 아닌 웹뷰의 히스토리 백으로 동작하고 더 이상 히스토리가 없을때 스택을 종료가 되도록 구성할 수 있답니다!