목차
- 인트로, 프로젝트 셋업
- 기본 UI 구성하기
- URL 로딩 기능 구현하기
- 네비게이션 기능 구현하기
- 완성도 높이기
결과화면

1. 기본 UI 구성하기
크게 ConstraintLayout과 밑에 WebView가 뜰 수 있는 SwipeRefreshLayout으로 나누어 준다.<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Swiperefreshlayout은 사용자가 수동으로 업데이트 를 요청할 수 있도록 한다.
Swiperefreshlayout이 적용되어 있는 Activity에 수직으로 pull하면 업데이트가 트리거된다.
build.gradle (Module: app) 수정을 하여 implements를 추가 해준다.
dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
}
그리고 가장 하단부에 ContentLoadingProgressBar를 추가해준다. 이 Bar는 웹뷰가 로딩 되는 동안 ProgressBar가 보이도록 한다.
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="2dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
ContentLoadingProgressBar
https://developer.android.com/reference/androidx/core/widget/ContentLoadingProgressBar
로딩바가 떳을때 이게 떳다가 사라지는걸 사용자가 인지할수 있게 (가변적인 로딩바에 대해서) 해주는 위젯.
ProgressBar를 상속받는다.
2. WebView 세팅 하기
val webView = findViewById(R.id.webview) // 웹뷰 셋팅
webView.apply {
webViewClient = WebViewClient() // 하이퍼링크 클릭시 새창 띄우기 방지
webChromeClient = WebChromeClient() // 크롬환경에 맞는 세팅을 해줌. 특히, 알람등을 받기위해서는 꼭 선언해주어야함 (alert같은 경우)
settings.javaScriptEnabled = true // 자바스크립트 허용
settings.javaScriptCanOpenWindowsAutomatically = false
// 팝업창을 띄울 경우가 있는데, 해당 속성을 추가해야 window.open() 이 제대로 작동 , 자바스크립트 새창도 띄우기 허용여부
settings.setSupportMultipleWindows(false) // 새창 띄우기 허용 여부 (멀티뷰)
settings.loadsImagesAutomatically = true // 웹뷰가 앱에 등록되어 있는 이미지 리소스를 자동으로 로드하도록 설정하는 속성
settings.useWideViewPort = true // 화면 사이즈 맞추기 허용 여부
settings.loadWithOverviewMode = true // 메타태그 허용 여부
settings.setSupportZoom(true) // 화면 줌 허용여부
settings.builtInZoomControls = false // 화면 확대 축소 허용여부
settings.displayZoomControls = false // 줌 컨트롤 없애기.
settings.cacheMode = WebSettings.LOAD_NO_CACHE // 웹뷰의 캐시 모드를 설정하는 속성으로써 5가지 모드
/*
(1) LOAD_CACHE_ELSE_NETWORK 기간이 만료돼 캐시를 사용할 수 없을 경우 네트워크를 사용합니다.
(2) LOAD_CACHE_ONLY 네트워크를 사용하지 않고 캐시를 불러옵니다.
(3) LOAD_DEFAULT 기본적인 모드로 캐시를 사용하고 만료된 경우 네트워크를 사용해 로드합니다.
(4) LOAD_NORMAL 기본적인 모드로 캐시를 사용합니다.
(5) LOAD_NO_CACHE 캐시모드를 사용하지 않고 네트워크를 통해서만 호출합니다.
*/
settings.setAppCacheEnabled(false) // 앱 내부 캐시 사용 여부 설정 (Deprecated )
settings.domStorageEnabled = true // 로컬 스토리지 사용 여부를 설정하는 속성으로 팝업창등을 '하루동안 보지 않기' 기능 사용에 필요
settings.allowContentAccess // 웹뷰 내에서 파일 액세스 활성화 여부
settings.userAgentString = "app" // 웹에서 해당 속성을 통해 앱에서 띄운 웹뷰로 인지 할 수 있도록 합니다.
settings.defaultTextEncodingName = "UTF-8" // 인코딩 설정
settings.databaseEnabled = true //Database Storage API 사용 여부 설정
}
webView.loadUrl("https://www.naver.co.kr/") // url 주소 가져오기
}
@SuppressLint("SetJavaScriptEnabled")
private fun initViews(){
webView.apply {
webViewClient = WebViewClient()
webChromeClient = webChromeClient()
settings.javaScriptEnabled = true // 자바 스크립트도 사용하겠다는 명시도 해야
loadUrl("${DEFAULT_URL}")
}
}
// 아래식을 위처럼 apply형태로 변경 가능하다.
// webView.webViewClient = WebViewClient()
// webView.settings.javaScriptEnabled = true // 자바 스크립트도 사용하겠다는 명시도 해야
// webView.loadUrl("Https://google.com")
웹뷰 초기 세팅 initViews()를 구현 해준다.
companion object{
private const val DEFAULT_URL = "http://www.google.com"
}
Default URL을 companion object로 구현 해준다.
private fun bindViews(){
addressBar.setOnEditorActionListener { v, i, _ ->
if(i == EditorInfo.IME_ACTION_DONE){
val loadingUrl = v.text.toString()
if(URLUtil.isNetworkUrl(loadingUrl)){
webView.loadUrl(loadingUrl)
}
else {
webView.loadUrl("http://$loadingUrl")
}
}
return@setOnEditorActionListener false
}
goBackButton.setOnClickListener {
webView.goBack()
}
goFowardButton.setOnClickListener {
webView.goForward()
}
goHomeButton.setOnClickListener {
webView.loadUrl("${DEFAULT_URL}")
}
refreshLayOut.setOnRefreshListener {
webView.reload()
} // 밑으로 당기면 reflesh 새로고침이 된다.
}
상단 검색어 입력창에 주소를 입력하면 그 해당 주소로 이동 할 수 있는 bindView()를 구현해준다.
Edittext 입력완료 후 엔터(Enter) 이벤트 처리를 위해 setOnEditorActionListener 사용해준다.
IME.ACTION_DONE => Enter클릭시 를 뜻한다.
ProgressBar 설정
inner class WebViewClient : android.webkit.WebViewClient(){ // inner를 붙여줌으로써 상위 클래스에 접근 가능
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
progressBar.show()
}
override fun onPageFinished(view: WebView?, url: String?) { // Page가 전부 로딩 됐을 때 !
super.onPageFinished(view, url)
refreshLayOut.isRefreshing = false
progressBar.hide()
goBackButton.isEnabled = webView.canGoBack() // 백 이있을때만 백버튼 누를 수 있다.
goFowardButton.isEnabled = webView.canGoForward() // forward가 있을 때만 누를 수 있다.
addressBar.setText(url) // 페이지 이동시 m.naver.com 같은 url을 보여 주고 싶을 때
}
}
inner class webChromeClient : android.webkit.WebChromeClient(){
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
progressBar.progress = newProgress
}
}
안드로이드 webview 페이지 로딩 확인
(webview onProgressChanged함수)
-> 안드로이드의 페이지 로딩의 되었는지 0 - 100으로 나타내는 함수.
( 정리 최종코드)
package com.example.aop_part2_chaptor08
import android.annotation.SuppressLint
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import android.webkit.URLUtil
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
import android.widget.EditText
import android.widget.ImageButton
import androidx.core.widget.ContentLoadingProgressBar
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
class MainActivity : AppCompatActivity() {
private val progressBar : ContentLoadingProgressBar by lazy {
findViewById(R.id.progressBar)
}
private val refreshLayOut : SwipeRefreshLayout by lazy {
findViewById(R.id.refreshLayout)
}
private val goBackButton : ImageButton by lazy {
findViewById(R.id.goBackButton)
}
private val goHomeButton : ImageButton by lazy{
findViewById(R.id.goHomeButton)
}
private val goFowardButton : ImageButton by lazy{
findViewById(R.id.goFowardButton)
}
private val addressBar : EditText by lazy {
findViewById(R.id.addressBar)
}
private val webView : WebView by lazy {
findViewById(R.id.webView)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initViews()
bindViews()
}
override fun onBackPressed() {
if(webView.canGoBack()){ // 뒤로 갈 수 있다면
webView.goBack()
}
else {
super.onBackPressed() // 홈 이면 그냥 꺼버림 !!
}
}
@SuppressLint("SetJavaScriptEnabled")
private fun initViews(){
webView.apply {
webViewClient = WebViewClient()
webChromeClient = webChromeClient()
settings.javaScriptEnabled = true // 자바 스크립트도 사용하겠다는 명시도 해야
loadUrl("${DEFAULT_URL}")
}
}
// 아래식을 위처럼 apply형태로 변경 가능하다.
// webView.webViewClient = WebViewClient()
// webView.settings.javaScriptEnabled = true // 자바 스크립트도 사용하겠다는 명시도 해야
// webView.loadUrl("Https://google.com")
private fun bindViews(){
addressBar.setOnEditorActionListener { v, i, _ ->
if(i == EditorInfo.IME_ACTION_DONE){
val loadingUrl = v.text.toString()
if(URLUtil.isNetworkUrl(loadingUrl)){
webView.loadUrl(loadingUrl)
}
else {
webView.loadUrl("http://$loadingUrl")
}
}
return@setOnEditorActionListener false
}
goBackButton.setOnClickListener {
webView.goBack()
}
goFowardButton.setOnClickListener {
webView.goForward()
}
goHomeButton.setOnClickListener {
webView.loadUrl("${DEFAULT_URL}")
}
refreshLayOut.setOnRefreshListener {
webView.reload()
} // 밑으로 당기면 reflesh 새로고침이 된다.
}
inner class WebViewClient : android.webkit.WebViewClient(){ // inner를 붙여줌으로써 상위 클래스에 접근 가능
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
progressBar.show()
}
override fun onPageFinished(view: WebView?, url: String?) { // Page가 전부 로딩 됐을 때 !
super.onPageFinished(view, url)
refreshLayOut.isRefreshing = false
progressBar.hide()
goBackButton.isEnabled = webView.canGoBack() // 백 이있을때만 백버튼 누를 수 있다.
goFowardButton.isEnabled = webView.canGoForward() // forward가 있을 때만 누를 수 있다.
addressBar.setText(url) // 페이지 이동시 m.naver.com 같은 url을 보여 주고 싶을 때
}
}
inner class webChromeClient : android.webkit.WebChromeClient(){
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
progressBar.progress = newProgress
}
}
companion object{
private const val DEFAULT_URL = "http://www.google.com"
}
}
MainAcitiviy.kt
<?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=".MainActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/white"
android:elevation="4dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageButton
android:id="@+id/goHomeButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_home"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<!--리플 버튼은 background를 수정하여 변경가능 누르면 번쩍이는 기-->
<EditText
android:id="@+id/addressBar"
android:layout_width="0dp"
android:layout_height="32dp"
android:background="@drawable/shape_address_bar"
android:imeOptions="actionDone"
android:importantForAutofill="no"
android:inputType="textUri"
android:paddingHorizontal="16dp"
android:selectAllOnFocus="true"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/goHomeButton"
app:layout_constraintRight_toLeftOf="@id/goBackButton"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="LabelFor,TextFields" />
<!--인풋타입은 무슨 키보드 형식을 주는지 !!-->
<ImageButton
android:id="@+id/goBackButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_back"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintRight_toLeftOf="@id/goFowardButton"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<ImageButton
android:id="@+id/goFowardButton"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="?attr/selectableItemBackground"
android:src="@drawable/ic_forward"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="0dp"
android:layout_height="2dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main.xml
'안드로이드 > 앱개발(Android)' 카테고리의 다른 글
(코틀린 kotlin) 명언앱 (0) | 2022.02.05 |
---|---|
(Android) 파이어베이스 Notification 알림 앱 (0) | 2022.01.28 |
(코틀린 kotlin) 녹음기 앱 (0) | 2022.01.24 |
(코틀린 kotlin) 타이머 앱 (0) | 2022.01.22 |
(코틀린 kotlin) 전자액자 앱 (0) | 2022.01.21 |