이번에는 계산기를 만들어봤다. 나름 계산기다운 면모를 보여줘서 그럴싸해보인다. 대신 몇가지 기능을 빼면서 계산구현을 하는데 쓰이는 로직에 들이는 시간을 줄였다. 대신에 Room DB를 이용해보기도 했다. 전에 Room써보려다가 조금 복잡해서 뭐가 뭔지 엄청 헷갈렸었는데 이번에 구현해보면서 어떤식으로 돌아가는지 큰틀을 알게 됐다. 또 쓰레드에서 UI를 그릴때 메인 쓰레드로 굳이 메시지를 보내서 해결하지 않고 runOnUiThread를 사용해봤다. 새로운것에 대해서 꽤 많이 배웠기때문에 한편으로 정리하기보다는 몇편에 끊어서 업로드 할 생각이다.
# 결과물 미리보기
- 사칙연산 + %모듈러 구현 ( 한 계산에는 연산자 한번만 사용 가능 )
- DB을 이용하여 계산결과를 DB에 저장 후, 프로세서를 종료시켜도 계산결과가 유지
# 알게된 것
Layout
-- 👇현재 게시글👇 --
- TableLayout 🔥
- xml 이용하여 drawable 버튼 디자인 🔥
- 안드로이드 제공 기본 아이콘 사용 🔥
- 모달창과 같은 새창 띄우기 🔥
- SpannableStringBuilder사용하여 특정부분 색 바꾸기 🔥
- 문자열(String)에 함수 새로 만들기 🔥
-- 👇다음게시글👇 --
- Room DB사용하기
- Thread 만들기
- runOnUIThread 사용하기
- LayoutInflater 이용하여 xml 적용
## TableLayout
TableLayout은 행/열을 기반으로 View들을 표기해줄 수 있게하는 ViewGroup(레이아웃)이다.
계산기에서 각각의 버튼은 *5
<TableLayout>
<TableRow> //행
<Button/> // 열
<Button/>
</TableRow>
</TableLayout>
이런식에 구조를 가지게 작성할 수 있다.
## xml 이용하여 drawable 버튼 디자인
저번에 AppCompatButton을 사용했었다. 해당 버튼은 Button과 다르게 정말 기본적인 옵션만 탑재 돼 있기 때문에 내가 원하는 모양으로 커스텀하기가 편하다.
<androidx.appcompat.widget.AppCompatButton
android:background="@drawable/button_background"
android:clickable="false"
android:enabled="false"
android:textSize="24sp"/>
대신 다음과 같이 background로 내가 디자인 한 xml을 가지고 올 수 있다.
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="@color/buttonGrayPress"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@color/buttonGray"/>
<corners android:radius="100dp"/>
<stroke
android:width="1dp"
android:color="@color/buttonGrayPress"/>
</shape>
</item>
</ripple>
ripple은 버튼을 눌렀을때 터치효과 중 하나이며 물결처럼 퍼져나간다. ripple이 될경우의 색을 지정해주고 그 안에 item으로 새로운 모양을 정의해준다. corners는 얼마큼 각지게 할거냐(모서리 둥글게), stroke는 테두리, solid는 버튼 자체적 색을 지정해줄 수 있다.
## 안드로이드 기본 이미지 사용
힘들게 구글링해서 이미지를 뒤지지 않아도 안드로이드에서 기본적인 이미지들을 제공해준다.
New -> Image Asset -> Clip Art -> Clip Art 그림 누르기 원하는 아이콘을 선택후 drawable에 저장시켜주고난 후
<ImageButton
android:src="@drawable/ic_baseline_access_time_24"/>
src를 지정해줘서 사용하면 된다.
## 모달창과 같은 새창 띄우기
어떻게 이런 화면을 구현할 수 있을지 옛날에 프로젝트 해보면서 고민이 많았다. 리액트처럼 true이면 띄어주고 false면 없애주고 그런 방식으로 구현하는게 맞는걸까 했는데, 그와 비슷한 방식으로 구현했다.
즉 "기록"버튼을 누르면 ScrollLayout의 inVisiable을 true로 해주고 false로 해주는 변형을 통해 조작했고, 그 과정에서 안 내용을 지워주고 보여주고를 반복하게 했다.
fun historyButtonClicked(view: View) {
// TODO 다시한번 리셋해주기
historyLinearLayout.removeAllViews()
historyLayout.isVisible = true
// TODO 디비에서 모든 기록 가져오기
// TODO 가져온거 그려주기
}
fun closeButtonClicked(view: View) {
historyLinearLayout.removeAllViews()
historyLayout.isVisible = false
//TODO 디비에서 기록 제거
}
## SpannableStringBuilder사용하여 특정부분 색 바꾸기
오퍼레이터(연산자)는 View에 표현될때 초록색으로 보여주게하여 피연산자와 구분했는데 이 과정에서 SpannableStringBuilder을 사용했다.
val ssb = SpannableStringBuilder(expressionTextView.text) //문자열 넘겨줌
ssb.setSpan(
ForegroundColorSpan(ContextCompat.getColor(this, R.color.green)), // 바꿀 색 지정
expressionTextView.text.length - 1, // 범위(포함) <=
expressionTextView.text.length, // 범위(미포함) <
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
expressionTextView.text = ssb
## 문자열(String)에 함수 새로 만들기
문자열이 아니더라도 Int와 같은 기본형들에 대해서 적용 할 수 있다.
fun String.isNumber(): Boolean {
return try {
this.toBigInteger()
true
} catch (e: NumberFormatException) {
false
}
}
"HELLO! WORLD".isNumber() // false
"10".isNumber() // true
다음과 같이 원하는 기능 원하는 함수명 원하는 반환형으로 입맛에 맞게 바꾸어 편리하게 사용 할 수 있다.
# 느낀점👩💻
먼저 when이 상상 이상으로 편리하고 많이 쓰인다는것을 몸소 느끼고 있다. xml을 만들때 옛날에는 툴을 이용해서 만들었는데 코드로 만드니까 생각보다 빠르고 더 편리했다. 이것 저것 예제를 따라해보면서 익숙해져야지 상황에 맞는 레이아웃을 구성할 수 있을 것 같다.
아직 안린이이기 때문에, 리사이클러 뷰 뭐 커스텀** 엄청 많을텐데 빨리 배우고 싶다는 생각밖에 안든다. 블로그로 정리안하고 강의만 죽어라 듣고싶은데 그러면 내꺼가 될거 같지 않아서 정리중에 있다.