안전모를 만들면서 가장 힘들었지만, 가장 이룬게 없는? UI 부분에 대한 간단한 리뷰를 남겨야겠다. 사실 리뷰라고 할 것도 없이 대부분의 UI/UX 부분은 기존의 오픈 소스를 최대한 활용했고, 개인적으로 디자인 감각이 0에 수렴하므로 알아두면 좋은 부분들에 대해 정리하는 취지로 작성해야겠다.

기본적인 레이아웃 구성.

기본적으로 안전모는 화면 구성을 위한 클래스로 Fragment는 활용하지 않았다.(지도 보기 부분에서 추가할 예정.) 때문에 모든 화면이 Activity로 되어있으며, Activity 설계에 맞춰 레이아웃의 xml 파일도 구성되어 있다. 우선, 메인 엑티비티에서 사용된 레이아웃 xml 파일에 대해서 간단하게 알아보자.

<?xml version="1.0" encoding="utf-8"?>
<!--메인 레이아웃 구성 RelativeLayout로 구성-->
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fab="http://schemas.android.com/apk/res-auto"
    xmlns:materialdesign="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true">
    <!--상단 툴바 출력용 xml-->
    <android.support.v7.widget.Toolbar
        app:popupTheme="@style/AppTheme.PopupOverlay"
        android:id="@+id/toolbar"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:minHeight="@dimen/abc_action_bar_default_height_material"
        android:elevation="5dp">
    </android.support.v7.widget.Toolbar>

    <!--원형 프로그레스바 출력용 xml-->
    <com.gc.materialdesign.views.ProgressBarCircularIndeterminate
            android:layout_below="@id/toolbar"
            android:id="@+id/progressBarCircularIndeterminate"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:elevation="10dp"
            android:background="@color/white"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"/>
          <TextView
            android:layout_below="@id/toolbar"
            android:id="@+id/currentSpeed"
            android:text=""
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center"
            android:textSize="125sp"
            android:textColor="@android:color/black"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"/>
  <!--최고속도 출력용 텍스트 View-->
  <TextView
      android:id="@+id/titleMaxSpeed"
      android:text="@string/max_speed"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="20sp"
      android:textColor="@android:color/black"
      android:layout_below="@id/currentSpeed"
      android:layout_marginTop="16dp"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_marginLeft="20dp"
      android:layout_marginStart="20dp" />
  <!--최고속도 출력용 값 View-->
   <TextView
       android:id="@+id/maxSpeed"
       android:text=""
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:textSize="20sp"
       android:textColor="@android:color/black"
       android:layout_below="@id/currentSpeed"
       android:layout_alignParentRight="true"
       android:layout_alignParentEnd="true"
       android:layout_marginTop="16dp"
       android:layout_marginRight="20dp"
       android:layout_marginEnd="20dp" />
  <!--구분선-->
   <View
       android:id="@+id/separator1"
       android:layout_width="fill_parent"
       android:layout_height="1dp"
       android:background="@color/grey_lighter"
       android:layout_marginTop="16dp"
       android:layout_below="@+id/maxSpeed"
       android:layout_alignParentRight="true"
       android:layout_alignParentEnd="true" />

       <!--...중략...-->

       <!--플로팅 액션 버튼용 xml 파일(시작 및 일시 정지)-->
       <com.melnykov.fab.FloatingActionButton
           android:id="@+id/fab"
           android:onClick="onFabClick"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:src="@drawable/ic_action_play"
           android:layout_gravity="center_horizontal"
           fab:fab_colorNormal="@color/grey_lighter"
           fab:fab_colorPressed="@color/grey_light"
           fab:fab_colorRipple="@color/grey_dark"
           android:layout_alignParentBottom="true"
           android:layout_centerHorizontal="true"
           android:layout_marginBottom="16dp"/>

      <!--플로팅 액션 버튼용 xml 파일(새로고침)-->   
       <com.melnykov.fab.FloatingActionButton
           android:id="@+id/refresh"
           android:onClick="onRefreshClick"
           fab:fab_type="mini"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:src="@drawable/ic_action_refresh"
           android:layout_gravity="center_horizontal"
           fab:fab_colorNormal="@color/grey_lighter"
           fab:fab_colorPressed="@color/grey_light"
           fab:fab_colorRipple="@color/grey_dark"
           android:layout_centerHorizontal="true"
           android:layout_marginBottom="16dp"
           android:layout_above="@+id/fab" />

   <include layout="@layout/content_main" />
</RelativeLayout>

안전모의 메인 화면은 RelativeLayout으로 구성되어 있다. keepScreenOn 이라던지 조금 특별한 부분은 안전모 앱 특성상 구성되어 있다. 중략 부분은 나머지 내용과 공통되므로 생략했다. 위 코드는 SpeedMeter 오픈소스를 나름대로? 커스터마이징해서 사용했으며, Navigation Drawer를 사용하기 위해 content_main 파일을 include한 것을 확인할 수 있다. 기본적으로 레이아웃은 순서대로 쌓이게 되므로, content_main 파일을 제일 마지막에 포함해야 한다. 다음은 content_main의 xml 파일이다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    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:id="@+id/mainDrawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="app.cap.ajm.Activity.MainActivity"
    tools:showIn="@layout/activity_main"><!--이 속성이 있어야 메인 엑티비티에서 생성 가능.-->

    <!--네비게이션 드로워의 헤더 부분과 메뉴 부분을 나타낼 View-->
    <android.support.design.widget.NavigationView
        android:id="@+id/mainNavigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/navigation_drawer">
    </android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>

네비게이션 드로워는 갓 구글에서 기본적으로 제공하는 위젯 중 DrawerLayout로 레이아웃을 구성하고, NavigationView 형식으로 구성하면 된다. gravity에 따라서 왼쪽에서 나올 수도 있고, 오른쪽에서 나올 수도 있다. 현재는 왼쪽!

아래는 네비게이션의 뷰에 나타날 헤더 부분이다. 메인 아이콘 이미지와 앱이름, 연락 이메일을 나타날 수 있도록 구성되어 있다. 사실 진짜 별게 없다..?ㅋㅋ

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@color/white"
    android:backgroundTint="@color/white"
    android:backgroundTintMode="src_over"
    android:paddingLeft="30dp"
    android:paddingRight="30dp"
    android:paddingTop="30dp">
    <ImageView
        android:id="@+id/imageInNavigation"
        android:paddingTop="40dp"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/mainlogo2"/>
    <TextView
        android:id="@+id/nameInNavigation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/imageInNavigation"
        android:layout_marginBottom="2dp"
        android:layout_marginTop="10dp"
        android:text="@string/app_name"
        android:textSize="15dp"
        android:textColor="@android:color/black"
        android:textStyle="bold"/>
    <TextView
        android:id="@+id/emailInNavigation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/nameInNavigation"
        android:text="CONTACT US : seongjae.m@gmail.com"
        android:textColor="@android:color/black"/>
</RelativeLayout>

아래는 네비게이션의 뷰에 나타날 몸통? 부분이다. 갓 구글의 material-design-icons 덕분에 예쁜 머터리얼 이미지들을 손쉽게 가져다가 쓸 수 있다. res > menu 폴더 밑에 작성한다.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <!--네비게이션 드로워에 나타날 아이템들의 이름과 이미지-->
    <item
        android:id="@+id/nav_direction"
        android:icon="@drawable/ic_directions_bike_black_48dp"
        android:title="@string/nav_title_direction"/>
    <item
        android:id="@+id/nav_route"
        android:icon="@drawable/ic_trending_up_black_48dp"
        android:title="@string/nav_title_route" />
    <item
        android:id="@+id/nav_weather"
        android:icon="@drawable/ic_wb_sunny_black_48dp"
        android:title="@string/nav_title_weather"/>
    <item
        android:id="@+id/nav_compatable"
        android:icon="@drawable/ic_home_black_48dp"
        android:title="@string/nav_title_com"/>
    <item
        android:id="@+id/nav_sms"
        android:icon="@drawable/ic_sms_black_48dp"
        android:title="@string/nav_title_timetask"/>

    <item
        android:id="@+id/nav_alarm"
        android:icon="@drawable/ic_alarm_black_48dp"
        android:title="@string/action_settings"/>
    <item
        android:id="@+id/nav_about"
        android:icon="@drawable/ic_android_black_48dp"
        android:title="@string/nav_title_ajm"
        />
</menu>

아래는 안전모의 툴바에 나타낼 손전등 기능과 앱이름 메뉴를 위해 사용된 xml 부분이다. res > menu 폴더 밑에 작성한다.

<menu 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"
    tools:context="app.cap.ajm.MainActivity">
    <item
        android:id="@+id/action_flash"
        android:icon="@drawable/ic_lightbulb_outline_black_48dp"
        android:orderInCategory="100"
        android:title="@string/app_name"
        app:showAsAction="always|collapseActionView" />
</menu>

이런식으로 구성하면 아래와 같이 화면이 표현되게 된다. 정말… 디자인은 포기해야겠다. 넘나 못 하는 것~ 안전모 메인 화면네비게이션 드로워 화면

개인적으로 안스에서 제공해주는 Navigation Drawer 폼을 바로 사용해도 좋을 것 같다. Navigation Drawer는 생각보다 Deprecated가 적은? 것 같아서 다행이다. 아닌가…

오픈 소스의 활용.

안전모는 앞서 말했지만, 오픈 소스 천지이다…ㅋㅋ 이 자리를 빌어 세상 모든 오픈 소스 개발자들에게 감사함을 표한다? 땡큐 땡큐! 아무튼, 안전모에서 실제로 사용된 아주 좋은 기능들이 탑재된 오픈 소스들에 대한 기록을 남겨보자~

butterknife

안드로이드 개발 부분에 엄청난 영향력을 행사하시는 제이크왓튼 형님?이 만드신 라이브러리이다. 자바 코드에서 뷰를 일관성 있고 쉽게 컨트롤할 수 있게 해준다. 코틀린을 위한 라이브러리도 개발 중이시다. 역시 Geek… 실제 Github 저장소의 내용은 여기를 참고.

FloatingActionButton

위에서도 나와있는 예쁜 플로팅 버튼을 사용할 수 있게 해주는 라이브러리이다. 실제 Github 저장소의 내용은 여기를 참고.

CicleImageView

안드로이드 상에서 불러온 이미지를 원형으로 동그랗게 보이게 해주는 라이브러이다. 별거 아닌 것처럼 느껴지지만, 코드를 보면 아 별거구나라고 생각하게 된다… 실제 Github 저장소의 내용은 여기를 참고.

picasso

이미지를 안드로이드상으로 블러올 때 많이 사용되는 라이브러리로 Glide 라이브러리와 양대 산맥이다. 스타도 굉장히 많이 달려있다. 실제 Github 저장소의 내용은 여기를 참고.

material-design-icons

갓 구글에서 제공하는 머터리얼 디자인이 이미지 파일로 저장되어 있다. 거의 모든 dp 사이즈에 맞게 제공하는 것 같다. 얼른 클론 클론!! 실제 Github 저장소의 내용은 여기를 참고.

MultiType

안드로이드 리스트 뷰 안에 여러개의 타입을 동시에 넣기 쉽게 해주는 라이브러리다. 리스트 뷰에 이미지 파일과 글을 예쁘게 함께 넣어야 할 때 유용하다. 실제 Github 저장소의 내용은 여기를 참고.

about-page

마찬가지로 위의 멀티 타입을 구현한 개발자가 만든 오픈 소스로, 이름에서 느껴지듯 환경 설정이나, 도움말 등의 화면을 구성하기 쉽게 해준다. 실제 Github 저장소의 내용은 여기를 참고.

SpeedMeter

속도계 관련 부분을 개발할 때 도움이 정말 많이 되었던 오픈 소스이다. UI 부분과 코드 로직 부분 모두 알기 쉽게 아주 잘 구성되어 있다. 실제 Github 저장소의 내용은 여기를 참고.

EasyWeather

오픈 웨더 맵 API를 활용한 날씨 정보를 가져오는데 필요한 코드를 구현해놓은 저장소로, 뷰도 깔끔하고 API 공부하기 좋은 것 같다. 물론 오픈 웨더 맵 데이터 자체가 영어만 지원하기 때문에 열심히 한글화 해서 엑셀로 만들어 놓고 사용했다… ohttp와 volley 라이브러리를 함께 사용한다. 실제 Github 저장소의 내용은 여기를 참고.

AndroidSwipeLayout

안드로이드에서 조금 더 역동적인 레이아웃의 변화를 맛볼 수 있는 저장소이다. 굿…! 실제 Github 저장소의 내용은 여기를 참고.

오픈 소스의 제한 범위.

사실, 오픈 소스라고 해서 모두 공짜를 나타내는 것도 아니고, 막 가져다가 써도 된다는 것을 나타내는 것은 아니다. 위에 사용된 많은 오픈 소스는 각각 다른 라이센스를 가지고 있다. 실제로 유명 대기업에서도 오픈 소스를 가져다 쓰고 라이센스에 명시되어 있는 소스 코드 공개 원칙을 하지 않는다던지 해서 소송을 먹곤? 한다. 그렇다면, 오픈 소스 라이센스의 종류 및 활용범위에 대해서 간단하게 정리해보자.

종류 GPL LGPL BSD MPL EPL Apache
코드의 무료이용 가능 가능 가능 가능 가능 가능
코드의 자유배포 가능 가능 가능 가능 가능 가능
소스코드의 공개 공개 공개 비공개 공개 공개 ??
소스코드의 수정 가능 가능 가능 가능 가능 가능
수정 코드의 소스공개 공개 공개 비공개 공개 공개 비공개
상용S/W 와의 링크 불가 가능 가능 가능 가능 ??
  • 많이 쓰이는 세가지 라이센스
    아파치 라이센스에 대한 자세한 내용은 여기를 참고.
    MIT 라이센스에 대한 자세한 내용은 여기를 참고.
    GPL 라이센스에 대한 자세한 내용은 여기를 참고.

역시 문서 작업은 정말 힘들다. 아무튼, 다른 앱을 만들때도 그랬지만, 안전모를 만들때 가장 애를 먹었던게 디자인 부분이었다. 디자인 공부좀 해야되나 고민되는 요즘이다. 디자인은 어떻게 공부해야 될지 모르게쒀여… 갓 디자이너 님들께서 도와주시겠지 뭐~ 그냥 코딩이라도 열심히 해야겠다. 다음은 안전모의 위치 측정 부분에 대해서 알아보는 걸로~

  • 오타나 잘못된 부분을 지적해주시면 감사히 생각하고 수정토록 하겠습니다 :)