[Android] constraint layout을 이용한 UI 그리기 연습

neoneoneo·2024년 3월 20일
0

android

목록 보기
2/16

배경

캠프의 튜터 선생님께서 화면을 그려보는 과제를 내주셨다!
이번 과제에서는 개발 시간을 미리 계산해 보는 것까지 해보자고 하셔서 Phase를 3개로 나누어서 개발을 진행하고자 한다.


task

위 이미지의 UI 그려보기!


Phase1

개발 일정 산정

총 예상 소요 시간 : 10h 20m

- Phase1 : 325m(5h 25m)
      - 개발 일정 산정 - 15m
      - 과제 분석 및 asset 확보 - 10m
      - 1번 화면 constraint layout 전체 구조 설계 - 30m
      - radius 스터디 - 60m (구현과 동시 진행)
      - button 스터디 - 60m (구현과 동시 진행)
      - 1번 화면 구현 - 120m (스터디와 동시 진행)
      - 버퍼 - 30m
- Phase2 : 225m(3h 45m)
      - 2번 화면 constraint layout 전체 구조 설계 - 30m
      - chain 스터디 - 60m
      - 2번 화면 구현 - 120m
      - 버퍼 - 15m
- Phase3 : 70m(1h 10m)
      - 1, 2 화면 전환 - 30m
      - 보완 - 30m
      - 버퍼 - 10m

사실 처음에는 한.. 3시간이면 할 수 있지 않을까? 했는데, 약간의 서치를 미리 하면서 3배로 늘어났다. 진짜 근거없는 자신감 이거 어떻하면 좋지.. 무튼간에 하다보면 10시간 25분도 부족할 수 있겠다.

일단은 10시간 안에 마무리가 우선적인 목표이고, 아직 익히는 단계이니 최종 데드라인은 이번 주 금요일(3/22) 정오까지로 넉넉하게 설정해두고 시작해본다.

과제 분석 및 asset 확보

  • emulator : Medium Phone 6.4” (아이폰 13, 14 6.1”)
    • 과제로 내어주신 figma 자료를 보니, 아이폰 13, 14 사이즈로 frame이 설정되어 있었다. 여러 에뮬레이터를 실행해본바, 그나마 Pixel 7a이 6.1"로 샘플과 가장 유사하지만, 상단 중앙에 카메라가 있어 UI 일부를 가리게 되는 것을 확인했다. 그래서 일단 그나마 비슷한 Medium Phone로 진행을 해본다!
  • font : outfit
  • 로고 및 기타 이미지 자료 : figma에서 SVG 확장자로 획득

1번 화면 constraint layout 전체 구조 설계


일단 대충 필요한 요소들을 넣어본다(맨 처음에 사진 찍는 것을 깜빡해서, 일단 radius 들어간 상태의 사진을 올린다;).

1번 화면 구현

  1. 상단 사각형 그리기

rectangle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <solid android:color="#EB9EE8"/>
    <stroke android:width="1dp" android:color="@color/black"/>
    <corners android:radius="50dp"/>
</shape>
  • radius 값을 넣어 둥근 사각형을 만든다.
  1. 그림자 넣기

elevation를 추가해준다.

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="match_parent"
        android:layout_height="463dp"
        android:elevation="10dp"
        android:background="@color/white"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@drawable/rectangle" />

그림자에 문제 발생..!

  • elevation을 넣었더니 radius 값이 적용된 상태가 아닌.. 사각형 그 자체의 모양으로 그림자가 적용되고 있다.
<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="460dp"
        android:background="@drawable/rectangle"
        android:elevation="10dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

  • ImageView가 아닌 frameLayout으로 넣어주고 elevation을 주었더니 해결되었다.
  1. 하단 텍스트들

크기, 스타일을 먼저 맞춰준다.

폰트를 적용해준다.

폰트에 문제 발생..!


폰트 중 weight만 추가를 해두어서 글자들이 전부 말라깽이가 되었다.. 피그마를 다시 보니 bold, medium, light가 사용되어 다시 리소스를 추가해준다.

  1. 버튼들

SVG 이미지 형태의 버튼 리소스를 추가하고 화면에 넣어준다. 근데...

버튼에 문제 발생..!

  • drawableLeft와 같은 속성으로 넣으니 뒤에 베이스 버튼의 이미지가 같이 보이고 있다. 심지어 text도 보이지 않는다.
  • background 속성에 넣었더니, 버튼의 색상이 기본 색상으로 표시된다.
  • 스택오버플로에서 도움을 받아 수정했다. FrameLayout에 이미지버튼과 텍스트뷰를 함께 넣으면 해결! 그러나 여전히 디테일이 안맞는다. 벡터이미지를 다루는 게 생각보다 어렵다. 한 30분 정도 고전했는데, 일단 넘어가고 나중에 튜터 선생님한테 문의해본다.
  • 역시 god tutor sunsangnim ImageButton을 FrameLayout으로 변경하고, 이미지 xml을 background로 넣으니 이쁘게 보인다. 아마 기존 ImageButton의 못 생긴 회색이 겹쳐 보여서 문제가 되었던 것 같다..!
  • 일단 elevation으로 그림자를 넣어주었는데, 또 radius 먹은대로 이쁘게 안되고 난리다 ^^.. 아주 크리티컬하지 않은 요인에 시간을 너무 많이 사용하여 전체를 완성하지 못하는 것도 리소스 낭비가 되므로, 일단 넘어가본다.

Phase1은 5시간 25분을 예상하였다. 일단 여기까지 작업하는 데에 4시간 정도 걸렸다. 어렵지만 재밌다^^.. 버튼은 일단 정리만 좀 해보고 마무리할 때 보강하는 것으로 한다.

이번 페이즈에서 배운점 요약

  • 사각형에 둥근 효과를 주고 싶으면 xml을 생성하고 corners android:radius에 값을 준다.
  • ImageView에 radius가 있는 이미지를 넣고 elevation을 넣으면 그림자가 ImageView 자체에 적용되어 원하는 결과를 얻기 힘들 수 있다.
    • FrameLayout에 이미지를 입히고 그림자를 적용하면 radius가 적용된 상황에서도 그림자를 이쁘게 뽑아낼 수 있다. 다만, FrameLayout안에 있는 FramLayout에 대해서는 안된다. 진짜 뭐 어쩌라는건지 모르겠다;
  • ImageButton에는 src 속성으로 이미지를 넣을 수 있다. 다만, text를 동시에 표시할 수는 없다.
    • 텍스트와 이미지를 동시에 표시하기 위해서는 FrameLayout 안에 ImageButton과 TextView를 함께 배치한다.
    • Button에서도 background 속성을 이용하여 이미지를 넣고 text도 보이게 할 수 있다. 다만, 사용할 때 뭔가 호환이 잘 안되는 부분이 있는 것 같다. 스튜디오 버전 문제인가? 아직 모르겠다.

스터디 자료 아카이빙


Phase2

2번 화면 constraint layout 전체 구조 설계


이번에도 대충 필요한 위젯과 레이아웃들을 넣어준다. 나중에 Forgot Password?랑 로고쪽은 다른 위젯이나 레이아웃을 사용해야 할 수도 있겠다 싶으니 염두해두고 시작을 해본다.

2번 화면 구현

  1. 상단 TextView 2개 처리
    Phase1에서 폰트를 넣어준 덕분에 이번에는 5분컷으로 마무리
  1. EditText 2개와 Forgot Password? 처리

EditText를 위해 et_rec.xml을 생성해준다.

et_rec.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#F3F3F3"/>
            <corners android:radius="15dp"/>
        </shape>
    </item>
</layer-list>

생성한 xml은 EditText background에 적용한다.
Forgot Password?는 일단 TextView로만 만들어둔다.

  1. Sign in 버튼 처리

버튼을 위해 et_rec.xml을 생성해준다.

btn_sign_large_rec.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#EB9EE8"/>
            <corners android:radius="15dp"/>
        </shape>
    </item>
</layer-list>

하다보니 FrameLayout의 background에 이미지 xml을 넣고, 그 하위로 TextView를 넣어주면 그림자가 깔끔하게 들어간다는 것을 알게 되었다! 1번 화면에 가서도 똑같이 바꿔주어 아름답게 수정해놨다.

  1. 그라데이션으로 흐려지는 라인

양쪽의 색상이 흰-핑, 핑-흰으로 다르므로 두 개의 xml 파일을 만들어준다.

fl_gradient_line_left.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/gradient_white_to_pink">
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle">
            <gradient
                android:angle="0"
                android:startColor="@color/white"
                android:endColor="#EB9EE8"/>
        </shape>
    </item>
</layer-list>
  • 다른 하나는 startColor, endColor의 색상을 반대로 주면 된다.
  • shape문만 있어도 되나, 하나의 xml 파일에 여러 개의 옵션을 줄 수 없는건가 싶어서 트라이해봤더니 layer-list, item의 흔적이 남아있다..ㅎ 혹시 다시 건드리면 참고하려고 남겨준다.

  1. 로고 배치하기

배경으로 들어간 circle에 대한 xml을 만들어준다.

fl_circle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:color="#ECE9EC"/>
    <stroke android:color="#F89AEE" android:width="0.4dp"/>
</shape>

그 다음 horizontal spread 체인으로 엮어준다. 간격이 좀 넓은 것 같아서, 첫 번째 로고 start와 세 번째 로고 end에 margin 값을 주어 조정한다.

체인들이 참 아름답게 엮여 있다.

Phase2는 3시간 반 정도를 예상했는데, 2시간 반으로 마무리할 수 있었다. 손에 익으니 작업 시간이 많이 줄기는 했다.

이번 페이즈에서 배운점 요약

  • 그라데이션은 별도의 xml 파일을 만들어 start, end의 Color 값과 angle 값을 지정해주면 된다.
  • spread 체인은 start-end에서부터 일정 간격으로 배치, spread inside는 start-end에 붙은 상태에서 일정 간격으로 배치, packed은 빈틈없이 붙여서 가운데에 배치한다.

Phase1, 2 결과물

스터디 자료 아카이빙


Phase3

1, 2 화면 전환

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        window.insetsController?.hide(WindowInsets.Type.statusBars())
        val btnSignIn = findViewById<FrameLayout>(R.id.fl_btn_sign_in)
        btnSignIn.setOnClickListener {
            val intent = Intent(this, IntroActivity::class.java)
            startActivity(intent)
        }
    }
}
  • 1번 화면에서는 상단의 상태바를 숨긴다.
    • window.insetsController?.hide(WindowInsets.Type.statusBars())
  • 1번 화면의 Sign in 버튼을 누르면 2번 화면으로 이동한다.
    • FrameLayout에 setOnClickListener를 이용한다

Phase3는 30분 정도 걸렸다.

이번 페이즈에서 배운 것

  • Activity별로 상태바의 상태를 조정할 수 있다..! window의 함수들을 트래킹하다보면 찾을 수 있다. window에 재밌는 함수들이 많을 것 같다.

스터디 자료 아카이빙


과제 후기

이번 과제를 처음 받았을때 너무나도 막막했지만, 구글링과 튜터 선생님의 도움을 받아 재밌게 할 수 있었다. 과제 덕분에 constraint layout에 대해 더 많은 이해를 하게된 것 같다. 곁가지로 xml 문법도 조금씩 터득하고있다. 다음에는 어떤 과제를 하게 될지 기대가 된다~

예상 작업 시간 : 10시간 20분
실제 작업 시간 : 7시간

[TIL-240320]
[TIL-240321]

0개의 댓글