스팀 앱 개발기 #58 - 포스트 리스트를 구성할 항목의 레이아웃 (3) 데이터 클래스 정의 및 데이터 바인딩 적용
시작하며...
이번에는 포스트 리스트를 구성할 항목의 레이아웃의 데이터 클래스를 정의하고, 그것을 레이아웃과 데이터 바인딩으로 연결할 것입니다. 먼저 데이터 클래스부터 정의해 보겠습니다.
PostItem 데이터 클래스
이 클래스에 정의한 데이터 필드들은 다음과 같습니다.
- title: 포스트 제목
- thumbnailURL: 썸네일의 URL
- content: 텍스트 내용
- tagOrCommunity: 메인 태그 또는 커뮤니티 이름
- time: 작성 시간. 년월일 대신 '1일전', '1개월전'과 같은 방식의 포맷 사용 예정
- rewards: 보상량. 달러 단위.
- upvoteCount: 업보팅 개수
- downvoteCount: 다운보팅 개수
- account: 저자 계정
- reputation: 명성도
작성한 코드는 다음과 같습니다.
data class PostItem(
val title: String,
val thumbnailURL: String,
val content: String,
val tagOrCommunity: String,
val time: String,
val rewards: Float,
val upvoteCount: Int,
val downvoteCount: Int,
val account: String,
val reputation: Int
)
데이터 바인딩 적용
포스트 항목 레이아웃을 정의한 layout_post_item.xml 파일에 데이터 바인딩을 적용할 것입니다. 최상단 태그가 ConstraintLayout이었는데요. 이제 최상단 태그는 layout으로 정의하구요. ConstraintLayout은 그 안으로 들어갑니다.
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_post_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
그리고 layout 태그 안에 data 태그를 추가하구요. 위에서 정의한 PostItem 클래스 타입의 변수를 그 안에 정의합니다.
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="postItem"
type="lee.dorian.steem_domain.model.PostItem" />
</data>
...
</layout>
이제 ConstraintLayout 안의 뷰들과 PostItem 변수를 바인딩 해줍니다. 코드는 다음과 같습니다.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_post_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:text="@{postItem.title}"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title Example: Lorem ipsum dolor sit amet, consectetur adipiscing elit..." />
<ImageView
android:id="@+id/image_thumbnail"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="5dp"
app:srcURL="@{postItem.thumbnailURL}"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_title"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/text_content"
android:layout_width="0dp"
android:layout_height="24sp"
android:layout_marginLeft="10dp"
android:ellipsize="marquee"
android:maxLines="1"
android:text="@{postItem.content}"
android:textColor="@color/black"
android:textSize="18sp"
app:layout_constraintTop_toTopOf="@id/image_thumbnail"
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
app:layout_constraintRight_toRightOf="parent"
tools:text="Content example: Lorem ipsum dolor sit amet, consectetur adipiscing elit," />
<TextView
android:id="@+id/text_main_tag"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="@{postItem.tagOrCommunity}"
android:textSize="16sp"
app:layout_constraintLeft_toLeftOf="@id/text_content"
app:layout_constraintTop_toBottomOf="@id/text_content"
app:layout_constraintBottom_toTopOf="@id/text_rewards"
tools:text="Tag or Community" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:text="@{postItem.time}"
android:textSize="16sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_content"
app:layout_constraintBottom_toTopOf="@id/text_rewards"
tools:text="1 days ago" />
<TextView
android:id="@+id/text_rewards"
android:layout_width="wrap_content"
android:layout_height="18sp"
android:maxLines="1"
android:text='@{String.format("$%f", postItem.rewards)}'
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@id/image_thumbnail"
app:layout_constraintLeft_toLeftOf="@id/text_content"
tools:text="$987.654" />
<TextView
android:id="@+id/text_upvotes"
android:layout_width="wrap_content"
android:layout_height="18sp"
android:layout_marginLeft="3dp"
android:maxLines="1"
android:text='@{String.format("🔺%d", postItem.upvoteCount)}'
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintTop_toTopOf="@id/text_rewards"
app:layout_constraintLeft_toRightOf="@id/text_rewards"
tools:text="🔺123" />
<TextView
android:id="@+id/text_downvotes"
android:layout_width="wrap_content"
android:layout_height="18sp"
android:layout_marginLeft="3dp"
android:maxLines="1"
android:text='@{String.format("🔻%d", postItem.downvoteCount)}'
android:textColor="@color/black"
android:textSize="14sp"
app:layout_constraintTop_toTopOf="@id/text_rewards"
app:layout_constraintLeft_toRightOf="@id/text_upvotes"
tools:text="🔻0" />
<TextView
android:id="@+id/text_account_reputation"
android:layout_width="wrap_content"
android:layout_height="18sp"
android:layout_marginLeft="12dp"
android:maxLines="1"
android:text='@{String.format("%s (%d)", postItem.account, postItem.reputation)}'
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="dorian-mobileapp (99)" />
</androidx.constraintlayout.widget.ConstraintLayout>
GitHub Commit
마치며...
현재 페이스로 며칠 작업하면, 태그 화면을 구현할 수 있을 것으로 예상합니다. 바램대로 되었으면 합니다.
지난 스팀 앱 개발기
- #57 - 포스트 리스트를 구성할 항목의 레이아웃 (2)
- #56 - 포스트 리스트를 구성할 항목의 레이아웃
- #55 - .gitignore 파일 작성
- #54 - RxJava 관련 메모리 누수 방지 코드 작성
- #53 - 버그 수정: 인터넷 미연결시 API 실행하면 앱 강제 종료
- #52 - 인터넷 미연결시 API 실행하면 어떻게 될까?
- #51 - 파워다운 끝났으나 SP to power down 값이 0이 아닌 버그
- #50 - get_state API 쓸까? 말까?
- #49 - get_state API 시험해 보기
- #48 - 스팀 파워 값이 스팀잇 사이트와 다른 문제 분석
- #47 - 스팀 파워 값이 스팀잇 사이트와 다른 문제
- #46 - 다음 개발 아이템들
- #45 - 지갑 화면에서 다음 파워 다운 시간 보여주기
- #44 - 지갑 화면에 파워 다운 내용 보여주기
- #43 - 지갑 화면에서 VEST 값을 SP로 변환
- #42 - VEST를 SP로 변환하는 메소드
- #41 - 작성중...
- #40 - UTC 시간을 로컬 시간으로 바꾸는 코드 만들기
- #39 - condenser_api.get_dynamic_global_properties API 실행에 필요한 데이터 클래스 추가
- #38 - 지갑 화면 구현: 예금 보여주기 추가
- #37 - 지갑 화면 구현: WalletViewModel과 WalletFragment를 바인딩
- #36 - 유닛 테스트로 구현한 WalletViewModelTest 클래스에서 공통 부분 추출하여 CommonPartOfViewModelTest 클래스 만들기
- #35 - 유닛 테스트용 WalletViewModelTest 클래스 구현 후 보이는 문제점
- #34 - WalletViewModel 클래스에 스팀 지갑 정보 읽는 코드 작성
- #33 - 추가 리팩토링: 데이터 모듈의 데이터 클래스의 필드들에 nullable 적용
- #32 - 리팩토링: 데이터 클래스 이름 변경
- #31 - 도메인 모듈에서 정의하는 데이터 클래스들이 DTO 패턴을 따르는 것이 맞는가?
- #30 - 진도를 더 나가기 전에 리팩토링 고려 중
- #29 - 뷰모델, Repository 패턴 그리고 Use Case 패턴의 관계
- #28 - Use Case 패턴 적용
- #27 - Repository 패턴 적용
- #26 - condenser_api.get_accounts API로 받은 계정 자료를 SteemitWalletDTO 타입으로 변환하기
- #25 - SteemClient, SteemService 잘 작동하는지 유닛 테스트
- #24 - API 실행을 담당할 SteemService 인터페이스 정의
- #23 - condenser_api.get_accounts API 연동에 필요한 데이터 클래스 정의
- #22 - API 연동에 필요한 라이브러리 추가
- #21 - 사용자 지갑 정보를 담을 SteemitWallet 클래스 정의
- #20 - 클린 아키텍처를 위한 모듈 구성 (2)
- #19 - 클린 아키텍처를 위한 모듈 구성 (1)
- #18 - VEST로부터 STEEM POWER를 계산하는 방법
- #17 - VEST를 STEEM POWER로 변환하기 위해 필요한 get_dynamic_global_properties API
- #16 - 지갑 내용을 읽기 위해 필요한 API
- #15 - 지갑 서브화면(WalletFragment) 레이아웃 구성해 보기
- #14 - 지갑 서브화면(WalletFragment)에서 계정 인식하기
- #13 - 프로파일 서브화면(ProfileFragment)에서 계정 인식하기
- #12 - 태그 서브화면에서 태그 인식하기
- #11 - 검색 레이아웃을 메인 화면에 적용
- #10 - 태그 및 계정 검색 레이아웃 만들기
- #9 - BaseActivity 클래스 정의 그리고 MainActivity 클래스에 적용
- #8 - BaseFragment 클래스 정의 그리고 기존 프래그먼트들에 적용
- #7 - ProfileFragment 그리고 WalletFragment에 데이터 바인딩 적용
- #6 - 태그별 검색 내용을 보여줄 TagsFragment에 데이터 바인딩 적용
- #5 - GitHub에 소스 올리기
- #4 - 하단 내비게이션의 탭 관련 클래스 이름 수정
- #3 - 하단 내비게이션 바의 아이콘, 텍스트 수정
- #2 - 프로젝트 생성
- #1 - 시작하며...
[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Upvoted! Thank you for supporting witness @jswit.