안드로이드 기기의 해상도와 크기는 갈수록 다양해지고 있고, 폴더블 폰 등의 괴상한 사이즈의 폰도 등장하고 있다. 해상도도 가로:세로 비율도 얼추 비슷하던 때에는 상하좌우 dp 값을 통해 레이아웃을 정의하기도 했다. 하지만 ‘왼쪽으로부터 20dp’ 같은 척도는 모든 폰에서 절대적으로 같게 보일 수가 없다.

이번 포스트는 안드로이드 뷰를 구성하는 가장 기초 요소 중 하나인 TextView 두 개를 임의로 배치하고자 시도한 삽질을 정리한 글이다. (큰 건 아니고 모종삽정도.)


구현하고자 한 뷰

구현하고자 했던 건 두 개의 텍스트뷰와 구분선 역할을 하는 이미지뷰.


텍스트 길이가 유동적인 두 개의 텍스트뷰가 있다. 왼쪽 텍스트는 짧을 수도 있고 길 수도 있으며 자리가 없을 때에 … 로 처리해야 한다. 오른쪽 텍스트는 짧지만 모든 내용이 다 표시되어야 하며 왼쪽 텍스트 바로 옆에 위치시킨다.

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_orange_light"
    android:ellipsize="end"
    android:maxLines="1"
    android:textSize="16sp"
    tools:text="아주 짧을 때도 있고 때로는 아주 길 때도 있는 텍스트" />

<ImageView
    android:layout_width="1dp"
    android:layout_height="12dp"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:background="@android:color/darker_gray" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_green_light"
    android:maxLines="1"
    android:textSize="16sp"
    tools:text="네글자쯤" />


실패한 시도 1 - ConstraintLayout

당연히 ConstraintLayout를 이용해서 좌우를 연결해주면 될 것이라고 생각헀다. 그러나 width를 0dp, wrap_content 등으로 시도해보아도, 각 뷰의 좌우를 연결하고 chain Mode를 순환해봐도 구현에 실패했다. 계속 한 쪽이 되면 다른 한 쪽이 말썽을 부렸다. 거기에 ellipsize 로 … 기능까지 처리해주자니 마음처럼 되지 않았다.

  1. 가로 길이가 가변적이어야 하니 왼쪽 텍스트뷰의 width 를 wrap_content 로 주었다. 그랬더니 길이가 길어져도 텍스트 내용을 감싸는 것으로 적용이 되어 ellipsize 가 동작하지 않았고, 오른쪽 뷰가 화면 밖으로 밀려나버렸다.
  2. View width 를 ‘0dp’로 주자니 길이가 고정되어버려 오른쪽 텍스트뷰가 화면 우측에 붙어서 움직이지 않았다.

ellipsizewrap_content 의 속성이 서로 상반되어 ConstraintLayout 로는 힘들겠다는 것을 느꼈다. 그래서 다른 레이아웃으로 시도해보았다.


실패한 시도 2 - LinearLayout

LinearLayout 에서 maxWeight 를 이용해 보면 ellipsize 기능을 제대로 적용할 수 있을 것 같았다.

왼쪽 텍스트뷰에 android:layout_weight="1" 속성을 주어봤지만, 자리를 고정적으로 차지하는 바람에 이 방법도 성공하지는 못했다.


실패한 시도 3 - RelativeLayout

RelativeLayout 에서는 alignParenttoRightOf 속성을 쓰면

  1. 오른쪽 텍스트뷰에 layout_alignParentRight=”true”, android:layout_toRightOf=”@+id/tvLeft” 속성을 주었더니 width가 wrap_content 임에도 여백 없이 가로 길이를 채웠다.
  2. 그렇다고 alignParentRight를 안 주자니 오른쪽 텍스트가 화면 밖으로 나가버리는 문제가 발생했다.


성공한 시도 - TableLayout

TableLayout은 Android Stuido 설치한 이래로 처음 써보았다. 정확히는 킹스택오버갓플로우 글을 참조하였다. 포인트가 되는 속성은 android:shrinkColumns="0" 이었다. 이름 그대로 표를 만드는 레이아웃이기 때문에 내용의 너비에 따른 처리를 하는데, 아무 열도 수축(shrink)하지 않는다면 모든 열이 올바로 표시되어야 한다.

이런 점을 이용해 왼쪽 텍스트뷰는 최대한 유지하되, 아무 열도 수축하지 않게 함으로써 오른쪽 텍스트뷰의 본래 너비를 유지할 수 있었다.

<TableLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:shrinkColumns="0"
    app:layout_constraintTop_toBottomOf="@id/table2">

    <TableRow
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_orange_light"
            android:ellipsize="end"
            android:singleLine="true"
            android:textSize="16sp"
            tools:text="아주 짧을 때도 있고 때로는 아주 길 때도 있는 텍스트" />

        <ImageView
            android:layout_width="1dp"
            android:layout_height="12dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:background="@android:color/darker_gray" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_green_light"
            android:ellipsize="none"
            android:singleLine="true"
            android:textSize="16sp"
            tools:text="네글자쯤" />
    </TableRow>

</TableLayout>



결론

로직도 아닌 뷰 가지고 두어 시간 동안 고민하는 것은 나에게는 꽤나 자존심 상하는 일이었다. TableLayout은 나온 지도 오래됐고, 레이아웃 안에 직접 row를 일일이 그리는 것도 생각보다는 번거로웠다. 심지어 더 나은 퍼포먼스를 위해서는 ConstraintLayout 을 사용하라고 안드로이드 개발자 공식 문서에 적혀있다. (그래서 이걸로 해결한 것이 더 찝찝하기도 하다.)

그럼에도 구 컴포넌트에서만 작동하는 shrinkColumns 같은 속성들이 여전히 존재했다. 구에서 신으로 완벽하게 호환되기를 우선 바라야겠지만, 무조건 신기술로만 해결하려는 버릇도 다시 한 번 생각해 볼 필요가 있었다.


오늘의 영단어
shrink : 줄다, 감소하다, 축소되다, 수축


References

  • https://stackoverflow.com/questions/24106885/expand-textview-with-wrap-content-until-the-neighbor-view-reaches-the-end-of-the