simpleWEB에 들어간 클래스/위젯
class, component on the simpleWEB
- WebView
- ProgessBar
- Intent
- EditText
- OptionMenu
- ContextMenu
- Thread
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/> <!-- 인터넷 권한 부여 --> <application android:usesCleartextTraffic="true"> <!-- 텍스트URL을 무조건 허용함 -->
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:inputType="textPersonName" android:text="http://www.google.com" android:ems="10" android:selectAllOnFocus="true" android:id="@+id/urledittext" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:imeOptions="actionUnspecified|actionSearch" tools:visibility="visible" android:textColorLink="#00BCD4" android:textColorHighlight="#00BCD4" android:textCursorDrawable="@color/colorPrimary"/> <ProgressBar style="?android:attr/progressBarStyleHorizontal" android:indeterminate="true" android:indeterminateTint="#00D8FF" android:progress="25" android:layout_width="0dp" android:layout_height="14dp" android:id="@+id/progressbar" app:layout_constraintTop_toBottomOf="@+id/urledittext" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> <WebView android:layout_width="0dp" android:layout_height="0dp" android:id="@+id/webview" app:layout_constraintTop_toBottomOf="@+id/progressbar" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
main.xml (option menu)
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:title="주 사이트" android:id="@+id/site"> <menu > <item android:title="SHA Computing" android:id="@+id/action_sha"/> <item android:title="Google" android:id="@+id/action_google"/> <item android:title="NAVER" android:id="@+id/action_naver"/> </menu> </item> <item android:title="개발자 정보 " android:id="@+id/developer"> <menu > <item android:title="전화하기" android:id="@+id/action_call"/> <item android:title="문자 보내기 " android:id="@+id/action_send_text"/> <item android:title="이메일 보내기 " android:id="@+id/action_email"/> </menu> </item> <item android:title="Home" android:id="@+id/action_home" android:icon="@drawable/ic_home_black_24dp" app:showAsAction="ifRoom"/> <item android:title="앱 종료" android:id="@+id/action_exit"/> </menu>
context.xml (Context menu)
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:title="페이지 공유" android:id="@+id/action_share"/> <item android:title="기본 브라우저에서 열기 " android:id="@+id/action_browser"/> </menu>
MainActivity.kt
package com.example.simpleweb import android.content.Intent import android.graphics.Bitmap import android.net.Uri import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.os.SystemClock import android.util.Log import android.view.ContextMenu import android.view.Menu import android.view.MenuItem import android.view.View import android.view.inputmethod.EditorInfo import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.ActionBar import kotlinx.android.synthetic.main.activity_main.* import org.jetbrains.anko.* import java.lang.Thread.sleep class MainActivity : AppCompatActivity() { private var lastTimeBackPressed:Long =-1500 private var isRunning=true // 옵션 메뉴 메소드 재정의 override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.main,menu) // 메뉴 리소스를 지정한다. <매개변수 main객체도 인자로 보낸다> return true // true를 반환하면 액티비티에 옵션 메뉴가 있다고 인식함 } // 옵션 메뉴 아이템 메소드 재정의 <아이템 클릭될 때 호출> override fun onOptionsItemSelected(item: MenuItem): Boolean { when(item?.itemId) { // item객체의 itemid필드는 사용자가 아이템을 선택할 때마다 값이 바뀜 R.id.action_google, R.id.action_home -> { urledittext.setText("http://www.google.com") webview.loadUrl("http://www.google.com") return true } R.id.action_naver -> { urledittext.setText("http://www.naver.com") webview.loadUrl("http://www.naver.com") return true } R.id.action_sha -> { urledittext.setText("http://shacoding.com") webview.loadUrl("http://shacoding.com") return true } R.id.action_call -> { val intent = Intent(Intent.ACTION_DIAL) // 다이얼창으로 이동하는 인텐트 기능 // Uri.parse메소드를 사용해서 전화번호 데이터를 가져옴 intent.data = Uri.parse("tel:1234-5678") // 다이얼창으로 이동할 수 있는 액티비티(앱)을 찾음 // 있으면 다이얼창으로 이동 if (intent.resolveActivity(packageManager) != null) startActivity(intent) return true } R.id.action_send_text -> { sendSMS("1234-5678", "HI") return true } R.id.action_email -> { email("cse@shacoding.com", "hi", "hi") return true } R.id.action_exit -> { finish() return true } } return super.onOptionsItemSelected(item) // 이외의 경우는 원래 메소드를 호출하는것이 일반적임 } // 컨텍스트 메뉴 메소드 재정의 override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { super.onCreateContextMenu(menu, v, menuInfo) // 컨텍스트 메뉴 만들기 위한 준비 menuInflater.inflate(R.menu.context,menu) // 메뉴 리소스를 지정한다. <매개변수 main객체도 인자로 보낸다> } // 컨텍스트 메뉴 아이템 메소드 재정의 <아이템 클릭될 때 호출> override fun onContextItemSelected(item: MenuItem): Boolean { when(item?.itemId){ R.id.action_share->{ share(webview.url) return true } R.id.action_browser->{ browse(webview.url) return true } } return super.onOptionsItemSelected(item) // 이외의 경우는 원래 메소드를 호출하는것이 일반적임 } // 뒤로 가기 눌렀을 때 호출되는 메소드 재정의 override fun onBackPressed() { if(webview.canGoBack()) // 웹뷰가 뒤로 갈 페이지가 있다면 webview.goBack() // 뒤로 간다 else{ if(System.currentTimeMillis()-lastTimeBackPressed<=1500) // '이전 버튼' 두 번 클릭 시 앱 종료 finish() lastTimeBackPressed=System.currentTimeMillis() toast("이전 버튼을 한 번 더 누르면 종료됩니다!") } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 웹뷰 기본 세팅 webview.apply { settings.javaScriptEnabled = true // 자바스크립트 기능을 동작하게 하기 // (페이지를 뜨게하는) WebViewClient를 부모로 하는 무명 클래스 정의 및 인스턴스화 webViewClient = object : WebViewClient() { // URL접속할 때 호출되는 메소드 override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { progressbar.setVisibility(View.VISIBLE) return super.shouldOverrideUrlLoading(view, request) } // 페이지 접속 마치면 호출되는 메소드 override fun onPageFinished(view: WebView?, url: String?) { urledittext.setText(webview.url) progressbar.setVisibility(View.GONE) } } // 쓰레드 설정 (에딧 텍스트 보였다 안 보였다 하기) val thread=ThreadClass() thread.start() webview.loadUrl("http://www.google.com") // 웹뷰에 지정 페이지를 연결 // 객체는 에딧 텍스트에 글자가 입력될 때마다 호출 urledittext.setOnEditorActionListener { _, actionId, _ -> // 인자로 (반응한 뷰,키보드 버튼ID,이벤트)를 넘겨줌 // 아직 <에딧 텍스트에 반응한 뷰 >없고 이벤트 처리된 것도 없음 // 오직 키보드 버튼(ID:actionId) 만 제대로 인자로 넘겨주면 됨!! (나머지는 _) if (actionId == EditorInfo.IME_ACTION_SEARCH) { // 키보드 버튼이 search버튼과 같다면 webview.loadUrl((urledittext.text).toString()) // url연결 urledittext.setText(webview.url) true // true반환 } else { false } // 아니면 계속 false반환 } // 웹뷰에 컨텍스트 메뉴 등록 registerForContextMenu(webview) } } inner class ThreadClass:Thread(){ override fun run(){ var lasty=0 while(isRunning){ SystemClock.sleep(100) runOnUiThread{ if(webview.getScrollY()==0) urledittext.visibility=View.VISIBLE else if(webview.getScrollY()>1000){ // 현재y랑 이전y랑 다를 때 동작 <스크롤 이벤트> if(webview.getScrollY()!=lasty){ if(lasty-webview.getScrollY()>=100) // 스크롤을 올릴 때 동작 [ 현재 스크롤 Y < 이전 스크롤 Y ] // 현재와 이전 사이에 100만큼 간격을 준 이유는 미세한 반응에도 동작하면 UX가 안 좋기 때문 urledittext.visibility=View.VISIBLE else if(webview.getScrollY()-lasty>=100)// 스크롤을 내릴 때 동작 urledittext.visibility=View.GONE lasty=webview.getScrollY() } } } } } } // 프로그램이 종료될 때 실행되는 메소드 재정의 // isRunning에 false를 주어서 스레드를 종료한다 override fun onDestroy() { super.onDestroy() isRunning=false } }