발견록_03

김재현·2023년 4월 26일
0

안드로이드

목록 보기
5/12

1. Dialog 위치 문제

발견록2-9에서 CustomDialog를 사용하여 위치를 잡았다. 만약 상태 표시줄을 그대로 상용한다면 문제가 없을지도 모르겠지만 상태 표시줄을 투명하게 하고 그 위치를 넘어가게 했을때 문제가 발생했다.

문제점

  • 코드상에서 dialog가 상태표시줄을 무시하도록 했기 때문에 에뮬레이터에서는 상태표시줄의 높이를 고려하여 layoutParams.y = statusBarHeight + detailView.height // y좌표처럼 y좌표를 잡아주었다.
  • 그러나 실제 기기에서 테스트 해 본 결과 기기에서는 상태 표시줄이 여전히 있는 것처럼 위치를 잡는다. layoutParams.y = 0 // y좌표을 해도 상태표시줄 아래에 나온다는 것이다.
  • 실제 기기에서의 다른 뷰들을 상태 표시줄을 무시하는 것처럼 위치가 잡혔지만 유독 Dialog만 안잡히는 문제가 있었다.

이 문제를 해결하기 위해 Dialog의 여러 위치 잡는 방법을 사용했었다. 핸드폰 기종마다 상태표시줄도 다르고 다른 크기 문제도 해결해야했기 때문에 여러 시행착오가 있었다. 그래서 Dialog는 포기하기로 하였다.

그래도 Dialog를 위해서 그려놓은 xml을 재활용하여 사용하고 싶었기에 activity_main에 <include>를 사용하여 위치를 지정하여 붙여주었다.
top을 레이아웃을 토대로 붙였기 때문에 상단 바가 이동하는 위치에 따라서 자동으로 내가 붙이고자하는 메뉴(이후 팝업메뉴)도 같이 움직일 것이다. 상단 바는 상태표시줄의 높이를 계산해서 자동으로 마진을 설정해주는 코드가 이미 있기때문이다. 팝업메뉴의 x,y좌표는 지금 위치한 x,y좌표를 넣어주면 자동으로 그 위치로 갈거기 때문에 invisible로 숨겨둔다.

그리고 이미 그려둔 pop_over.xml을 이용하여 PopupWindow를 생성한다. 그 팝업 윈도우는 버튼이 눌렸을때 생성되게 하므로 버튼이 눌렸을때 showAtLocation을 실행하여 화면에 생성되도록 한다. setONDismissListener는 팝업창 바깥을 클릭했을때 동작하는 것이다. 안에 아무것도 안써주면 그냥 dismiss()로 창이 꺼지는것 같다.
이렇게 버튼을 클릭하여 나오는 창은 pop_over.xml을 inflate한 popupView에서 Id를 찾아서 클릭 리스너를 달아야 하는것 같다. binding을 써보려고 했는데 버튼을 클릭했을때 리스너가 실행되지가 않았다.

이렇게 하면 상태표시줄과는 관계없이 layout의 상대적인 위치를 토대로 자리잡기 때문에 에뮬레이터에서든, 핸드폰에서든 관계없이 동일한 위치에 나오는 것을 확인할 수 있었다.

--추가
findViewById는 성능저하의 원인이 되므로 쓰지 않아야 한다.
viewbinding으로 쓰는 코드로 수정하였다.


2. 위에서 내려오는 스크롤 애니메이션

이전에 반견록을 보면 내가 보이고 싶은 뷰를 invisible로 숨겨두고 투명도를 올리면서 visible을 하고, 아래로 내리는것으로 애니메이션을 만들었었다.
이때의 문제점으로 처음에 실행하면 아래로 내려오는 애니메이션이 아니라 그냥 화면에 나타나는 애니메이션이 보인다는 점이였다.

이에 대한 해결책으로 처음에 뷰를 invisible이 아닌 visible로 만들어 놓은 다음에 marging값으로 음수를 줘서 화면에 넘어가서 안보이도록 만드는 방법이다. 이렇게 하면 ObjectAnimator를 사용하여 위치값과 시간만 주면 화면을 아래로 내리는게 가능해진다. 특정 위치에 스크롤이 시작되는데 스크롤 방향은 "translationY"즉 y축방향인 아래방향으로 내린다. binding.tinyProfileLayout.height.toFloat()를 주어서 레이아웃의 높이만큼 아래로 내리고, 반대방향으로 스크롤이 되었을때는 다시 음수를 주어서 화면을 위로 올려서 화면상에는 안보이도록 처리하는 것이다.


3. 리사이클러뷰, 뷰페이저2에서 viewBinding사용하기

원래 자동완성으로 만들어지는 부분에서 밑줄친 부분으로 바꾸면 되고 뷰홀더에서 binding으로 사용하여 요소를 가져올 수 있다. ItemSliderBinding같은 것은 viewbinding을 선언하면 자동으로 만들어지는 바인딩이다.


4. RecyclerView + GridLayoutManager 사용하기

이전에 photo / video란을 constraintlayout으로 내가 넣을 만큼 <ImageView>를 만들어서 집어넣었다. 이때의 문제점으로 만약 사진이 추가된다면 constraintlayout으로 어떻게 집어넣을지와, 화면이 커져서 한 줄에 3개가 넘는 사진이 들어가질때는 어떻게 처리할지의 문제가 있었다.

이를 해결하기 위해 autoGrid를 사용할 수 있는 여러 오픈소스 라이브러리를 찾아보았는데 잘 찾아지지 않아서 그냥 RecyclerView와 GridLayoutManager를 사용하기로 하였다.

RecylcerAdapter의 매개변수로는 들어갈 이미지의 R.drawable.id값이 들어있는 Array배열을 전달해주었다. R.drawable.id형식은 Int로 받아와지기 때문에 Array<Int>로 받아온다. 그 후 다른점은 없다. 테두리를 자르기 위한 clipToOutline속성을 넣어주었다.

리사이클러뷰를 연결해주면서 Manager로 GridLayoutManager를 연결해주는데 가로의 개수로 독자적으로 계산한 값을 넣는다. 리사이클러뷰가 차지하는 가로길이 대비 이미지 크기를 나눈값으로 한줄에 들어갈 최대 개수를 넣어준다.
viewTreeObserver안에 넣은 이유는 photoLayoutWidth를 구하는데 화면이 다 그려져야 구할 수 있기 때문이다.
구하고 그리는덴 한번만 실행하면 되므로 리스너 삭제는 꼭 해주어야 한다.

문제점
위 코드를 사용하여 나온 그림이다. 한 줄에 내가 원하는 것만큼 나오는건 좋은데 한줄의 마지막 사진은 오른쪽에 필요없는 마진이 생겨서 중앙정렬이 안되는 모습을 볼 수 있다. 이를 해결하는 문제가 남았다.

해결책1
Manager의 ItemDecoration으로 왼쪽 오른쪽에 마진값을 준다. GridLayoutManager는 전체길이를 spanCount수 만큼 나눈 grid를 생성하고 이미지를 집어넣는데 grid보다 이미지가 크면 이미지는 왼쪽 위에 붙어서 나와서 오른쪽에 마진값이 생겨난다.
이 마진값을 계산해서 이미지의 양옆에 균등하게 분배해준 코드이다.


5. Indicator바꾸기

무한 스크롤이 가능한 ViewPager2를 만들었고 거기에 Indicator를 만들기 위해 여러 방법을 사용해보았었다.

  1. TabLayout

    • TabLayout은 ViewPager2와 attach하는 과정에서 ViewPager2의 getItemCount의 개수를 가져오는데 무한 스크롤을 위해서는 getItemCount의 개수를 크게 만들어야 하므로 적합하지 못했다.
  2. tommybuonomo / dotsindicator

    • 오픈소스 dotsindicator로 간단하게 indicator를 만들수있을 뿐만 아니라 예쁜 모양도 많았지만, 1번과 마찬가지로 개수의 문제로 적합하지 못했다.
  3. RecylcerView

    • 장점으로는 RecylcerView의 어뎁터에 이미지의 개수를 넘겨주면 그만큼 indicator가 생기는 것이므로 ViewPager2의 Adapter의 item개수와는 관계없이 동작한다는 것이다.
    • 하지만 코드상으로 보면 뷰페이지가 변경될때마다 리사이클러뷰 인디케이터 어뎁터에 변경점을 알려주고 이미지를 계속 새로 그리는 것과 마찬가지이다.
    • RecyclerView의 장점인 이미지 재활용과는 상관없이 동작하므로 성능면에서는 안좋을 수 있다는 단점이 있다.
  4. ongakuer / CircleIndicator

    • dotsindicator를 만들수 있는 또 다른 오픈소스. 여기는 Viewpager2의 어뎁터와 직접 연결할 수도 있지만, 내가 원하는 개수만큼 만들고 지금 보고 있는 페이지의 위치를 보내주면 자동으로 indicator의 모습을 바꿔준다.
    • 하지만 3번과는 다르게 내가 원하는 drawable 이미지를 넣어줘도 이상하게 모양이 변해서 나오는 것을 볼 수 있다. 아래가 3번의 indicator, 위에가 4번의 indicator이다.

TabLayout으로만 문제를 해결할 수 있는것 같은데 잘 모르겠다.


6. 글씨 높이의 절반에 배경색 주기

다음과 같은 글씨를 만들기 위해서 사용한 방법이다.

  1. 글씨 뒤에 ImageView만들기
    이렇게 글씨 뒤에 이미지뷰를 줌으로써 마치 있는 것처럼 동작하게 했다.

  2. Spannable을 활용해서 배경색 주기

    • 배경색을 지정할 TextView에 android:bufferType="spannable"주기

    • text를 spannabletext로 바꿔주고 span속성 적용하기. 여기서는 리사이클러뷰에서 자동으로 만들어지는 텍스트에 대한 spannable을 주기 때문에 onBindViewHolder에서 정의했다는 것을 참고.49번째 줄에서 넘어오는 text정보를 SpannableString으로 바꾸고 setSpan을 하기 전에 배경에 대한 span으로 수정한 추가정보를 주어야 한다. 이를 위해서는 새로운 클래스를 만들거나 기존에 존재하는 것을 넣으면 되는데 글씨 높이의 절반이라는 커스텀을 주기 위해서 HighlightSpan이라는 클래스를 새로 만들었다.

    • 새 클래스에서 중요한 점은 LineBackgroundSpan을 상속받는다는 것이다.

    • LineBackgroundSpan 클래스는 공식문서에 있는 클래스로 텍스트 라인의 배경색을 지정하거나 텍스트 라인의 경계선 스타일을 지정하는 등의 작업을 수행할때 사용한다. 이외에도 여러방식이 있다.

    • LineBackgroundSpan을 적용했을때 나오는 drawBackground를 상속받아 rect로 그려줄 크기를 지정하면 되는데 px단위의 좌표값을 계산하기 때문에 그 점에 주의해서 적용한다. 또한 paint.color를 바꾸게 되면 모든 색에 대한 값을 지정해서 바꿔버리게 되므로 시작할 때 originalPaint처럼 시작 색을 저장해놓고 작업이 다 끝나면 paint.color를 원래 색으로 돌려놓는 작업이 필요하다.


profile
배운거 정리하기

0개의 댓글