Unit 2: Layouts (2)

quokka·2021년 10월 31일
0

Android Basics in Kotlin

목록 보기
6/25
post-thumbnail

Material Design

Material Design의 가이드라인을 따르는 어플을 만든다.

Color system의 12 categories

  1. Primary
  2. Primary Variant
  3. Secondary
  4. Secondary Variant
  5. Background
  6. Surface
  7. Error
  8. On Primary
  9. On Secondary
  10. On Background
  11. On Surface
  12. On Error

COLOR TOOL

Mateial Design에서 제공하는 COLOR TOOL을 이용해서 색상 조합을 쉽게 선택할 수 있다.

  • Primary와 Secondary 컬러를 선택해 색상 조합을 여러 화면 구성으로 볼 수 있다.
  • Accessibility 탭에서 텍스트 색상 대비를 확인할 수 있다. 접근성이 높으려면 색상 대비가 높아야 한다.

colors.xml, themes.xml

  1. colors.xml에 색상의 이름과 색상 코드를 작성한다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="green">#1B5E20</color>
    <color name="green_dark">#003300</color>
    <color name="green_light">#A5D6A7</color>
</resources>
  1. themes.xml에 적용하기
<item name="colorPrimary">@color/green</item>

다크 모드

다크 모드의 색상 테마는 themes.xml (night)에서 수정할 수 있다.

어두운 테마는 기본 색상보다 낮은 채도를 사용한다.

앱 아이콘

런처 아이콘 애셋이 drawable 디렉터리에 있는 다른 앱 애셋과는 달리 mipmap 디렉터리에 있는 이유는 일부 런처가 기기의 기본 밀도 버킷에서 제공한 것보다 큰 크기로 앱 아이콘을 표시하는 경우가 있기 때문이다. 즉 아이콘을 확장해서 표시하는 런처가 있어 화질이 깨지는 것을 방지한다.

Android 밀도 한정자 목록

  • mdpi - 중밀도 화면의 리소스(~160dpi)
  • hdpi - 고밀도 화면의 리소스 (~240dpi)
  • xhdpi - 초고밀도 화면의 리소스(~320dpi)
  • xxhdpi - 초초고밀도 화면의 리소스(~480dpi)
  • xxxhdpi - 초초초고밀도 화면의 리소스(~640dpi)
  • nodpi - 화면의 픽셀 밀도와 관계없이 조정할 수 없는 리소스
  • anydpi - 어떤 밀도로도 조정 가능한 리소스

적응형 아이콘

관련 내용과 시각적인 효과를 이 링크🔗 에서 확인해보자! 시각적 효과를 보면 왜 foreground와 background를 나눠서 구성하는지 알 수 있다.

Android 8.0부터 적응형 런처 아이콘을 지원해 앱 아이콘이 더 유연해지고 시각 효과를 발휘할 수 있게 되었다.

개발자는 앱 아이콘을 foreground와 background 레이어로 구성할 수 있다.

vector drawable

비트맵 이미지는 각 픽셀의 색상 정보만 안다. 반면 벡터 그래픽은 이미지를 정의하는 모양을 그리는 방법을 알고 있다.

즉 벡터 그래픽은 화질 저하 없이 모든 화면 밀도의 어떤 캔버스 크기로도 조정할 수 있다.

Material Components

Material Components를 사용하면 다른 어플과 일관된 디자인과 방식으로 동작하기 때문에 사용자가 앱을 훨씬 더 빠르고 쉽게 사용할 수 있다. 아래 코드를 gradle에 추가해 사용할 수 있다. Component의 종류와 사용 방법은 위에있는 링크에서 확인!

dependencies {
    implementation 'com.google.android.material:material:<version>'
}

스타일 및 테마

styles.xml

일관된 스타일을 적용하려면 이렇게 values/styles.xml 에 스타일 내용을 작성해 스타일을 적용할 수 있다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Widget.TipTime.TextView" parent="Widget.MaterialComponents.TextView">
        <item name="android:minHeight">@dimen/min_text_height</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:textAppearance">?attr/textAppearanceBody1</item>
    </style>
    <style name="Widget.TipTime.CompoundButton.RadioButton"
        parent="Widget.MaterialComponents.CompoundButton.RadioButton">
        <item name="android:paddingStart">8dp</item>
        <item name="android:textAppearance">?attr/textAppearanceBody1</item>
    </style>
    <style name="Widget.TipTime.CompoundButton.Switch" parent="Widget.MaterialComponents.CompoundButton.Switch">
        <item name="android:minHeight">@dimen/min_text_height</item>
        <item name="android:gravity">center_vertical</item>
        <item name="android:textAppearance">?attr/textAppearanceBody1</item>
    </style>
</resources>

dimens.xml

반복적으로 사용하는 치수는 dimens에 작성해두고 불러와 사용한다.

<resources>
   <dimen name="min_text_height">48dp</dimen>
</resources>

테마에 스타일 추가

res/values/themes.xml 에 아래 코드를 추가한다. night 테마도 마찬가지로 추가!

<item name="textInputStyle">@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox</item>
<item name="radioButtonStyle">@style/Widget.TipTime.CompoundButton.RadioButton</item>
<item name="switchStyle">@style/Widget.TipTime.CompoundButton.Switch</item>

User Experience 향상하기

기기 회전

회전 시 화면이 잘려 사용자가 아래에 있는 버튼을 사용할 수 없다.

해결 방법: ContraintLayout 주위를 ScrollView로 감싼다.

Enter 키 누르면 키보드 숨기기

다음과 같은 코드를 Main Activity에 추가하고,

private fun handleKeyEvent(view: View, keyCode: Int): Boolean {
   if (keyCode == KeyEvent.KEYCODE_ENTER) {
       // Hide the keyboard
       val inputMethodManager =
           getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
       inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
       return true
   }
   return false
}

onCreate안에 onKeyListener를 설정한다.

binding.costOfServiceEditText.setOnKeyListener { view, keyCode, _ -> handleKeyEvent(view, keyCode)
   }

Instrumentation Tests

Tip time 앱의 UI 테스트를 해보자.
먼저 androidTest 디렉토리에 CalculatorTests.kt를 생성했다.

테스트 코드는 다음과 같다.

@RunWith(AndroidJUnit4::class)
class CalculatorTests {
    @get:Rule()
    val activity = ActivityScenarioRule(MainActivity::class.java)

    @Test
    fun calculate_20_percent_tip(){
        onView(withId(R.id.cost_of_service_edit_text))
            .perform(typeText("50.00"))
            .perform(ViewActions.closeSoftKeyboard())

        onView(withId(R.id.calculate_btn))
            .perform(click())

        onView(withId(R.id.tip_result))
            .check(matches(withText(containsString("$10.00"))))

    }
}

이 강의에서는 AndroidJUnit4 테스트 실행기를 사용한다.

MainActivity와 상호작용 하려면 먼저 액티비티를 실행한다.

	@get:Rule()
    val activity = ActivityScenarioRule(MainActivity::class.java)

그 다음 테스트 로직을 작성하는데 여기서는 Expresso라는 라이브러리를 사용한다.

        onView(withId(R.id.cost_of_service_edit_text))
            .perform(typeText("50.00"))
            .perform(ViewActions.closeSoftKeyboard())

onView()는 상호작용할 UI 구성요소를 찾는다. onView()는 ViewMatcher 객체를 매개변수로 하는데 withId()가 해당 Id의 ViewMatcher를 반환한다.
onView()는 ViewInteraction을 반환한다.
텍스트를 입력하고 나면 ViewInteraction에서 perform()을 호출한다.

그 다음 코드도 어떻게 동작하는지는 쉽게 이해할 수 있을 것이다.
EditText에 50.00을 입력하고,
Calculate 버튼을 클릭하고
Tip result에 해당하는 값이 $10.00인지 확인한다.

테스트를 실행하면 누군가 실제로 앱을 사용하는 것처럼 텍스트를 입력하고, 버튼을 클릭하고 결과를 얻는 화면이 뜬다.

안드로이드 스튜디오에서도 아래 처럼 확인된다.

0개의 댓글