발견록2-9에서 CustomDialog를 사용하여 위치를 잡았다. 만약 상태 표시줄을 그대로 상용한다면 문제가 없을지도 모르겠지만 상태 표시줄을 투명하게 하고 그 위치를 넘어가게 했을때 문제가 발생했다.
문제점
layoutParams.y = statusBarHeight + detailView.height // y좌표
처럼 y좌표를 잡아주었다. layoutParams.y = 0 // y좌표
을 해도 상태표시줄 아래에 나온다는 것이다.이 문제를 해결하기 위해 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으로 쓰는 코드로 수정하였다.
이전에 반견록을 보면 내가 보이고 싶은 뷰를 invisible로 숨겨두고 투명도를 올리면서 visible을 하고, 아래로 내리는것으로 애니메이션을 만들었었다.
이때의 문제점으로 처음에 실행하면 아래로 내려오는 애니메이션이 아니라 그냥 화면에 나타나는 애니메이션이 보인다는 점이였다.
이에 대한 해결책으로 처음에 뷰를 invisible이 아닌 visible로 만들어 놓은 다음에 marging값으로 음수를 줘서 화면에 넘어가서 안보이도록 만드는 방법이다. 이렇게 하면 ObjectAnimator를 사용하여 위치값과 시간만 주면 화면을 아래로 내리는게 가능해진다. 특정 위치에 스크롤이 시작되는데 스크롤 방향은 "translationY"
즉 y축방향인 아래방향으로 내린다. binding.tinyProfileLayout.height.toFloat()
를 주어서 레이아웃의 높이만큼 아래로 내리고, 반대방향으로 스크롤이 되었을때는 다시 음수를 주어서 화면을 위로 올려서 화면상에는 안보이도록 처리하는 것이다.
원래 자동완성으로 만들어지는 부분에서 밑줄친 부분으로 바꾸면 되고 뷰홀더에서 binding으로 사용하여 요소를 가져올 수 있다. ItemSliderBinding
같은 것은 viewbinding을 선언하면 자동으로 만들어지는 바인딩이다.
이전에 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보다 이미지가 크면 이미지는 왼쪽 위에 붙어서 나와서 오른쪽에 마진값이 생겨난다.
이 마진값을 계산해서 이미지의 양옆에 균등하게 분배해준 코드이다.
무한 스크롤이 가능한 ViewPager2를 만들었고 거기에 Indicator를 만들기 위해 여러 방법을 사용해보았었다.
TabLayout
RecylcerView
TabLayout으로만 문제를 해결할 수 있는것 같은데 잘 모르겠다.
다음과 같은 글씨를 만들기 위해서 사용한 방법이다.
글씨 뒤에 ImageView만들기
이렇게 글씨 뒤에 이미지뷰를 줌으로써 마치 있는 것처럼 동작하게 했다.
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를 원래 색으로 돌려놓는 작업이 필요하다.