개발자: 박진혁
- 목표: 기존 게시글 페이지에 댓글 기능 추가하기
별 헤는 밤 v1은 유저 간의 소통 방식이 게시글을 작성하는 것 밖에 없었기 때문에 커뮤니티 기능을 추가하기 위해서 댓글 기능을 구현하는 것이 필요해졌다.
댓글 기능을 구현하면서 서버 구현은 다른 기능과 유사하여 어려움이 크게 없었지만, 레이아웃이 여태까지 구현했던 화면가 특징이 달라서 애를 많이 먹었다.
댓글 기능이 있는 레이아웃의 특징은 다음과 같다.
- 댓글이 일정 개수가 넘게 되면 따로 스크롤이 되도록 변화해야 한다.
- 화면의 전체적인 길이, 다른 레이아웃의 위치 등을 동적으로 바꿔야 한다.
1. 스크롤 기능 구현 시 문제점
댓글이 일정 개수가 넘게 되면 높이가 더 이상 늘어나지 않고 고정된 높이에서 이중으로 스크롤이 될 수 있도록 구현해야 했다.
댓글을 작성하고 화면에 반영되는 로직은 다음과 같다.
댓글을 입력 → 서버에서 댓글을 생성 → 화면 새로고침 → 새로운 댓글 목록을 가져옴
그럼 다음과 같은 생각이 들 것이다.
‘어 어차피 댓글 목록 새로 가져오면 자동으로 높이가 list에 맞춰지는데 굳이 recyclerview 높이를 따로 설정할 필요가 있나?’
당연하고 자연스러운 발상이지만 Android는 기본적으로 Scrollview안에 recyclerview를 넣어 이중 스크롤이 되는 것을 지양한다.
따라서 보통 NestedScrollview를 사용하여 초기에 recyclerview item을 모두 불러와 단일 스크롤로 형성하게 만든다. 그럼 1번 이미지처럼 모든 댓글을 한 번에 다 출력되기 때문에, 만약 댓글이 100개가 넘어가게 된다면 굉장히 오래 화면을 내려야 할 것이다.
그렇다고 recylcerview의 높이를 고정시키면 2번째 화면 같이 불필요한 공백이 생겨 효율적이지 않다.
<NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/commentRecyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" // or 512dp로 고정하면 여백이 존재하게 됨
android:orientation="vertical"
/>
</LinearLayout>
</LinearLayout>
댓글 recyclerview 의 xml (실패의 케이스)
2. 동적 레이아웃 구현을 통해 문제 해결
이중 스크롤을 구현하는데 정적인 화면으로는 구현할 수 없다는 것을 알았으니 동적으로 레이아웃을 설정하기로 결정했다.
우선 댓글 창 인터페이스에서 고려해야 하는 변화는 다음과 같다.
- 댓글 삭제/ 생성 시 댓글 창 높이 변화
- 댓글이 한 개도 존재하지 않게 되었을 때 댓글 창 레이아웃 삭제
- 댓글 창 높이 변화 이벤트
if(result.size()>1&&result.size()<5){ //댓글이 4개까지만 늘어나고 5개부터는 고정됨
int padding_in_dp = 108*result.size(); // xml에서 댓글 item 높이는 108dp
final float scale = getResources(). getDisplayMetrics(). density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
LinearLayout.LayoutParams params=(LinearLayout.LayoutParams) commentRecyclerView.getLayoutParams();
params.height=padding_in_px;
commentRecyclerView.setLayoutParams(params);
}else if(result.size()>4){
int padding_in_dp = 512;
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
LinearLayout.LayoutParams params=(LinearLayout.LayoutParams)commentRecyclerView.getLayoutParams();
params.height=padding_in_px;
commentRecyclerView.setLayoutParams(params);
}
댓글 목록을 업데이트하는 함수 안에 위와 같이 Recyclerview의 LayoutParams의 높이를 직접 수정하는 코드를 추가하여 해결했다. 이때 주의할 점은 xml은 px, dp 값 둘 다 설정이 가능하지만 코드상에서는 px값 밖에 사용할 수 없다. 따라서 xml에서 dp값을 사용했다면 이를 변환시켜주는 과정이 필요하다. 그래서 ‘getResources(). getDisplayMetrics(). density’ 코드로 1dp가 몇 px인지를 구하여 대입해 주면 된다.
- 댓글 창 레이아웃 삭제 이벤트
if (!result.isEmpty()){
commentRecyclerView.setVisibility(View.VISIBLE);
}else{
commentRecyclerView.setVisibility(View.GONE);
}
recyclerview 댓글 유무에 따라 visibility 조정
댓글 창이 아예 삭제되어야 하는 상황의 경우 이전에 ‘더 보기’ 기능을 구현한 부분을 참고해서 댓글이 존재하지 않을 경우 setVisibility(View.GONE)을 통해 댓글 레이아웃을 삭제했다.
위와 같이 코드 상에서 동적으로 화면을 구성하면 아래 화면과 같이 댓글이 5개 이상 넘어가면 높이가 고정되고 이중으로 스크롤되는 것을 확인할 수 있다.
이렇게 동적인 레이아웃 구성으로 댓글 창을 구현해 보았다.
다음에는 게시글 이미지에서 viewPager2에 터치와 스와이프 기능 분리 주제를 다루도록 해보자.
P.S ) 아래 코드는 java 파일의 댓글 레이아웃 구현과 관련된 전체 코드입니다.
Call<List<PostComment>> commentCall = //retrofit Call 함수 적기;
commentCall.enqueue(new Callback<List<PostComment>>() {
@Override
public void onResponse(Call<List<PostComment>> call, Response<List<PostComment>> response) {
if(response.isSuccessful()){
List<PostComment> result = response.body();
if (!result.isEmpty()){
commentRecyclerView.setVisibility(View.VISIBLE);
}else{
commentRecyclerView.setVisibility(View.GONE);
}
for(int i=0;i<result.size();i++){
commentAdapter.addItem(result.get(i));
}
if(result.size()>1&&result.size()<5){ //댓글이 4개까지만 늘어나고 5개부터는 고정됨
int padding_in_dp = 108*result.size();
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
LinearLayout.LayoutParams params=(LinearLayout.LayoutParams)commentRecyclerView.getLayoutParams();
params.height=padding_in_px;
commentRecyclerView.setLayoutParams(params);
}
else if(result.size()>4){
int padding_in_dp = 512;
final float scale = getResources().getDisplayMetrics().density;
int padding_in_px = (int) (padding_in_dp * scale + 0.5f);
LinearLayout.LayoutParams params=(LinearLayout.LayoutParams)commentRecyclerView.getLayoutParams();
params.height=padding_in_px;
commentRecyclerView.setLayoutParams(params);
}
postCommentCount.setText(String.valueOf(result.size()));
commentRecyclerView.setAdapter(commentAdapter);
}
else{
Log.d("postComment", "게시물 댓글 정보 업로드 실패");
}
}
@Override
public void onFailure(Call<List<PostComment>> call, Throwable t) {
Log.d("postComment", "게시물 댓글 인터넷 오류");
}
});
별 헤는 밤: 밤하늘, 별자리, 여행정보와 날씨예보까지 - Google Play 앱
오늘부터 별잘알! 오늘밤 별자리 정보, 날씨·광공해·월령까지 고려한 '관측적합도', 주변 관측지 검색으로 누구나 쉽게 밤하늘을 즐겨보세요.
play.google.com
'별밤 일지 > 개발' 카테고리의 다른 글
[Android] CustomView 를 활용한 효율적인 나만의 View 만들기 (0) | 2023.12.13 |
---|---|
[JPA] 검색 메소드 수정하기 - JPA Specification (0) | 2023.12.07 |
[Android] Viewpager2, Scrollview 터치와 스크롤 분리하기 (0) | 2023.11.29 |
[WebClient] 비동기 아키텍처를 통한 외부 api 콜 성능 개선 (0) | 2023.11.04 |
[JPA] 검색 메소드 수정하기 - N+1 문제 (2) | 2023.10.24 |