RecyclerView로 화면구성
RecyclerView에 대해서 실습을 진행하기 전에 RecyclerView에 대해서 자세히 알아보도록 하자.
(최근에 생각이 복잡해졌기에, RecyclerView를 제대로 학습하지 않았다.)
그래서, 차근차근히 처음부터 RecyclerView에 대해서 알아보도록 하겠다.
# RecyclerView
RecyclerView란, 동일한 어떤 목록들을 나타내기 위해 사용하는 View이다.
즉, 동일한 형태로 된 View를 리스트 형태로 앱의 뷰로 표현해주도록 하는 게 RecyclerView이다.
(ListView도 존재하지만, 안드로이드 OS 메모리를 효율적으로 관리해주는 RecyclerView를 대부분 사용한다.)
# RecyclerView 특징
1. RecyclerView는 원하는 대로 View를 생성할 수 있다.
RecyclerView는 원하는만큼 목록들을 생성할 수 있기에, 사용자의 요청에 따라서
목록들을 자유자재로 생성 그리고 삭제 그리고 수정이 가능하다.
만약, RecyclerView를 사용하지 않고 앱 목록을 구현했더라면,
개발자는 사용자가 하나를 업데이트 할 때마다 주기적으로 목록들을 업데이트해줘야 되는 상황이 펼쳐진다.
예) 카카오톡 친구목록, 카카오톡 대화목록, 인스타그램 피드 목록
(RecyclerView는 안드로이드 앱에서 가장 많이 쓰이는 View로, 어렵지만 핵심인 개발전략이다.)
2. RecyclerView는 View를 재사용해서 메모리 부담을 줄인다.
ListView와 RecyclerView의 차이인 View를 재사용한다는 점이다.
View를 사용자가 생성한 View 갯수 만큼 생성되는 게 아니라, RecyclerView로 작동하면서
안드로이드 OS가 지정한 View 갯수를 할당해준다. 그리고 이 View만을 가지고 사용자의 모든 View들을 표현한다.
그렇기에, RecylcerView는 메모리 면에서 절약해서 사용할 수 있다는 점이 장점이다.
그치만, 앞에서 말한 바와 같이 View 갯수를 안드로이드 OS에서 지정해주기에
개발자가 이를 감안해서 사용자의 View를 고려해서 관리해야 된다는 점이다.
(이는, 이번 실습에 진행되는 체크박스를 클릭 후 아래로 스크롤 시 맨 하단에 체크하지 않았던 항목에 대해서 체크가 되어있다.
해당 실습을 진행해보면서 RecyclerView의 View 재사용에 대해서 자세히 알아보도록 하자.)
정리해서, RecyclerView는 View 갯수가 한정되어 있기에, 앱 구동 시 메모리 사용량을 줄인다.
그치만, 안드로이드 OS에서 한정한 View를 감안해서 개발자는 View에 대해서 신경쓰면서 구성해야 된다.
(안그러면, 체크 박스를 하는 곳에서 View를 제대로 재사용하지 못해서 발생하는
이전 View가 그대로 출력되어지는 사태가 발생한다.)
3. RecyclerView의 View 요소들은 Item 배열로 따로 관리한다
그럼, RecyclerView에서 View가 생성되는 게 한정되어져 있는데
View로 나타낼 Item들은 많을 때가 대다수다.
RecyclerView는 이를 관리하고자 View의 Item에 대한 배열을 생성해두어 관리한다.
결국, Item에 대한 배열이 존재하니, 한정된 View로 앱에서 보여지고 할 때
보여지고 있는 영역을 위치값을 Index로 적절한 Item 배열의 요소 값을 넣어서 View로 보여지게 만든다.
(이때는, onBindViewHolder 메소드인 Adapter의 LifeCycle을 이용해 구현된다.)
RecyclerView 동작
아래의 블로그를 참고해서 RecyclerView가 어떻게 동작해서 형성되는지 알아보자.
우선 RecyclerView는 Adapter 클래스를 통해서 동작되어진다.
(Adapter 클래스는 View 객체와 액티비티에서 생성된 데이터를 다루기 위해
규정된 View - 액티비티 Data 연결자 클래스이다.)
RecyclerView를 구현하기위해 Adapter 클래스는 Recycler.Adapter를 상속받아서 사용한다.
상속받음으로써, Adapter의 LifeCycle 메소드들이 할당되어지고, 이는
RecyclerView를 구현하는 액티비티가 동작되어질 때 호출된다.
# RecyclerView LifeCycle의 호출 구조
getItemCount() 메소드 호출
: View의 Item 갯수를 센다.
onCreateViewHolder() 메소드 호출
: Activity에 RecyclerView 영역에 따라 View 객체를 한정된 값으로 생성한다. (얼마만큼의 View객체가 생성되는지는 안드로이드 OS가 판단한다.)
그리고 생성된 View 객체로 모든 Item을 표현하며, 이는 사용자 동작에 따라 View 객체가 업데이트 된다.
onBindViewHolder() 메소드 호출
: View 객체가 새롭게 생성되었을 때 Item에 대한 값으로 View 객체를 초기화 시킨다.
그리고, 사용자 동작에 따라 View 객체가 업데이트 된다.
position 값을 찾을 인자로 받아서, 업데이트가 필요한 Item 배열의 인덱스로 View 객체를 업데이트 시킨다.
(이때, position 값은 스크롤된 Item 배열의 인덱스를 의미하고, 안드로이드 OS가 알아서 관리해준다.)
Kotlin 정리
Kotlin은 Java와 달리 생성메소드 대신 생성자를 사용해서 클래스의 인자 값을 받고,
초기화를 진행한다.
RecyclerView가 앱 뷰에서 구현되는 동작을 잘 설명해주는 블로그이다.
아래를 참고해서 RecyclerView를 Adapter를 사용해서 어떻게 구현을 하는지 자세히 알아보자.
RecyclerView 구현
Data Class 생성
우선, RecyclerView로 표현할 Item에 대한 Data 클래스를 생성한다.
데이터 클래스는 데이터를 다루는데 최적화된 클래스로 equals(), hashCode(), toString(), copy(), componentN() 5가지 유용한 함수들을 내부적으로 자동으로 생성해준다
즉, Data Class를 통해 View에 사용될 Item을 관리함으로써 Item들을 체계적으로 관리할 수 있다.
- 유지보수가 쉬워진 개발환경
item_data.xml 생성
item_data.xml 파일은 RecyclerView에서 목록형태로 표시할 XML 대표 객체를 생성한다.
대표 XML 파일로써, RecyclerView에서 내부 요소 값만 바꿔서 item_data.xml 형태로 View 목록을 구성을 한다.
아래와 같이 item_data.xml 파일을 구성할 수 있다.
이때, layout을 하나로만 구성해서 대표 객체 View를 구성해뒀다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--RecyclerView를 구성할 때는 하나의 대표모델을 만든다.-->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="TextView"
android:textColor="@color/black"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/tv_title"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
<Switch
android:id="@+id/btn_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
아래와 같이 item_data.xml의 layout에 대한 영역을 지정해줌으로써,
RecyclerView에 목록으로 나열 될 View 객체가 정의되어졌다.
activity_main.xml 생성
activity_main 에서 RecyclerView를 보여줄 영역을 지정한다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--RecyclerView 영역 activity_xml에서 지정함.-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_data"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
아래와 같이 전체 영역을 RecyclerView로 지정해줬다.
그럼, 이제 Activity 앱 뷰에서 모든 영역을 기준으로 View 목록이 나열 될 것이다.
DataRVAdapter 생성
아래와 같이 RecyclerView Adapter 클래스의 LifeCycle 메소드 호출을 토대로
RecyclerView에 표시 될 View를 생성한다.
package com.example.umc_week5
import android.util.SparseBooleanArray
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.umc_week5.databinding.ItemDataBinding
// RecyclerView의 Adpter를 상속받아서 구현
/*
RecyclerView Adapter 클래스는
고정된 View 객체를 자유자재로 나타내기 위해 사용하는 클래스이다.
그래서, 사용자의 입력에 따른 View 구성을 이 Adapter 클래스를 통해 실현시킨다.
현재는 RecycleView를 표현하기 위해 Adapter 클래스를 이용하는 방법이고, 나중에 PagerView2 를 표현하고자 Adapter 클래스를 구성하니 참고하자.
*/
class DataRVAdapter(private val dataList: ArrayList<Data>): RecyclerView.Adapter<DataRVAdapter.DataViewHolder>() {
// Switch Item의 상태의 Boolean 값을 담는 필드변수 생성
private val checkboxStatus = SparseBooleanArray()
// ViewHolder 객체를 받아서 ViewHolder 객체를 (Item 배열을 통해) 완성하는 내부 클래스 구현
inner class DataViewHolder(private val viewBinding: ItemDataBinding): RecyclerView.ViewHolder(viewBinding.root){
// View에 Item을 표시할 때 호출한다. | 실제로 View를 설정할 때 호출한다.
fun bind(data: Data){
viewBinding.tvTitle.text = data.title
viewBinding.tvDesc.text = data.desc
// RecyclerView | View의 Postion 값 저장
var position_data: Int = adapterPosition
}
}
/*
아래의 메소드들은 Recycler View.adapter 클래스를 상속받아서 사용할 시
필요한 메소드들이다. | Recycler View Adapter 클래스를 사용할 때 함께 작동하는 메소드들이라고 생각하면 된다.
*/
// ViewHolder 만들어질 때 호출되는 함수 || ViewHolder 객체 생성
/*
DataViewHolder 클래스를 상속받아서 viewHolder 객체를 넘겨줌.
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataViewHolder {
// ViewHolder 객체 생성
/*
ViewHolder 객체는 getItemCount() 메소드에서 받아진 Item 갯수를 토대로
ViewHolder 객체를 생성하는데,
화면에 보이는 전체 리스트 목록이 10개라면, 위아래 버퍼까지 감안해 13~15개 정도의 객체를 생성한다.
그렇기에, ViewHolder 객체는 Item 배열의 갯수만큼 생성된다.
*/
val viewBinding = ItemDataBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return DataViewHolder(viewBinding)
}
// ViewHolder 가 실제로 데이터를 표시할 때 호출되는 함수 - 앱 사용자의 해당 액티비티에서 스크롤할 때마다 액티비티가 변형되면 호출되는 메소드
// 액티비티에서 사라지는 요소를 토대로 View를 새롭게 Bind 시켜준다.
/*
onBindViewHolder 메소드는
데이터가 스크롤 되어서 맨 위에있던 뷰 홀더(레이아웃) 객체가 맨 아래로 이동한다면,
그 레이아웃(View)은 재사용 하되 데이터는 새롭게 바뀔 것이다. (bind 메소드를 통해서 바뀐다.)
아래에서 새롭게 보여질 데이터의 인덱스 값이 position이라는 이름으로 자동으로 받아서 사용가능하다.
*/
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
holder.bind(dataList[position])
}
// 앱에 나타낼 목록의 총 갯수를 Adapter 클래스에게 알려준다.
// 그래서, Adapter 클래스를 처음 생성했을 때, 실행되는 메소드로 초기화하지 않는 이상 해당 메소드는 한번실행된 채 앱이 구현된다.
override fun getItemCount(): Int {
return dataList.size
}
}
getItemCount() -> onCreateViewHolder() -> onBindViewHolder()
View의 Item 갯수를 세고, View를 생성함. 그리고, 스크롤 되면, Item의 인덱스를 토대로 View 객체를 업데이트한다.
MainActivity 생성
아래와 같이
앞서 구성해둔 activity Layout과 Recycler Adapter 클래스를 이용해서
받아지는 Item 데이터를 모두 목록 형태로 구성했다.
Adapter를 이용해 RecyclerView에 들어가는 View 객체 생성
그리고, 생성된 View 객체를 activity Layout에 표현
(이때, activity Layout의 RecyclerView에 Adapter를 통해 생성한 View 객체를 넣음.)
package com.example.umc_week5
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.umc_week5.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// 메인 액티비티 XML 객체 선언
private lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 메인 액티비티 XML 객체 생성
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
// RecyclerView에 표시될 Item을 ArrayList {Data} 객체 타입으로 배열로 선언
/*
arrayList는 배열의 크기가 자동으로 배정된다.
- 동적 배열
*/
val dataList: ArrayList<Data> = arrayListOf()
// arrayList 에 데이터 삽입
dataList.apply{
// arrayList 타입이 Data 객체이다. | 데이터 삽입 시 Data 객체 타입으로 넣어줌.
add(Data("hello", "1"))
add(Data("hello", "2"))
add(Data("hello", "3"))
add(Data("hello", "4"))
add(Data("hello", "5"))
add(Data("hello", "6"))
add(Data("hello", "7"))
add(Data("hello", "8"))
add(Data("hello", "9"))
add(Data("hello", "10"))
add(Data("hello", "11"))
add(Data("hello", "12"))
add(Data("hello", "13"))
add(Data("hello", "14"))
add(Data("hello", "15"))
add(Data("hello", "16"))
}
val dataRVAdapter = DataRVAdapter(dataList)
// Recycle View의 Adapter 구현
viewBinding.rvData.adapter = dataRVAdapter
// Recycle View의 Item 배치설정
viewBinding.rvData.layoutManager = LinearLayoutManager(this)
}
}
이제, 본격적인 실습인 RecyclerView의 View 재활용하며 생긴 체크박스 에러를 해결해보겠다.
그리고, RecyclerView를 사용해서 메모장 앱인 메모 후
기록 후 View를 새롭게 생성하는 것과
클릭 시 View를 삭제하는 걸 수행해보겠다.
실습 1. RecyclerView의 View 재활용 에러
기획
RecyclerView로 구성한 View의 체크박스에서 상단의 체크박스를 체크한다.
스크로를 해보면 체크하지 않았던 하단의 체크박스에 체크가 되어있다.
*원인
RecyclerView는 View를 재활용하기에 사용하면서 View의 요소들에 대해서 재할당을 해줘야한다.
(View 객체에 대해 text 요소는 초기화해줬지만,
체크박스 요소는 초기화하지 않았다.)
따라서, View 객체를 bind 해주는 부분에서
체크박스가 되어있는지 기억을 하고,
체크박스가 되어있을 때만, View 객체의 체크박스를 표시하도록 동작하도록 구현하면 되겠다.
(내가 첨에 기획한 아이디어 그대로 인듯 하다 ㅎ..ㅎ)
구현
클래스 파일
# Data 클래스
package com.example.umc_week5
// Recycler View Item 클래스
data class Data(
val title: String,
val desc: String
)
# RecycleView Adapter 클래스
View 객체와 데이터를 연결해 RecyclerView로 만들어주는 클래스이다.
package com.example.umc_week5
import android.util.SparseBooleanArray
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.umc_week5.databinding.ItemDataBinding
// RecyclerView의 Adpter를 상속받아서 구현
/*
RecyclerView Adapter 클래스는
고정된 View 객체를 자유자재로 나타내기 위해 사용하는 클래스이다.
그래서, 사용자의 입력에 따른 View 구성을 이 Adapter 클래스를 통해 실현시킨다.
현재는 RecycleView를 표현하기 위해 Adapter 클래스를 이용하는 방법이고, 나중에 PagerView2 를 표현하고자 Adapter 클래스를 구성하니 참고하자.
*/
class DataRVAdapter(private val dataList: ArrayList<Data>): RecyclerView.Adapter<DataRVAdapter.DataViewHolder>() {
// Switch Item의 상태의 Boolean 값을 담는 필드변수 리스트 생성
private val checkboxStatus = SparseBooleanArray()
// ViewHolder 객체를 받아서 ViewHolder 객체를 (Item 배열을 통해) 완성하는 내부 클래스 구현
inner class DataViewHolder(private val viewBinding: ItemDataBinding): RecyclerView.ViewHolder(viewBinding.root){
// View에 Item을 표시할 때 호출한다. | 실제로 View를 설정할 때 호출한다.
fun bind(data: Data){
// View의 Switch 요소의 check boolean 값을 기록해두는 리스트로 선언
/*
index : postion
value : boolean
*/
viewBinding.btnSwitch.isChecked = checkboxStatus[adapterPosition]
// 클릭 인벤트가 들어왔을 때, View의 Switch 요소 Check 여부를 확인하고,
// boolean 값으로 리스트에 저장
viewBinding.btnSwitch.setOnClickListener {
if(!viewBinding.btnSwitch.isChecked){
checkboxStatus.put(adapterPosition, false)
}
else{
checkboxStatus.put(adapterPosition, true)
}
}
// Switch가 체크되었는지 확인하고
// 체크가 안되어있다면, 체크제거 || 체크가 되어있다면, 체크
viewBinding.btnSwitch.isChecked = checkboxStatus.get(adapterPosition)
// 모든 View의 Item에 대한 초기화를 거침.
viewBinding.tvTitle.text = data.title
viewBinding.tvDesc.text = data.desc
}
}
/*
아래의 메소드들은 Recycler View.adapter 클래스를 상속받아서 사용할 시
필요한 메소드들이다. | Recycler View Adapter 클래스를 사용할 때 함께 작동하는 메소드들이라고 생각하면 된다.
*/
// ViewHolder 만들어질 때 호출되는 함수 || ViewHolder 객체 생성
/*
DataViewHolder 클래스를 상속받아서 viewHolder 객체를 넘겨줌.
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DataViewHolder {
// ViewHolder 객체 생성
/*
ViewHolder 객체는 getItemCount() 메소드에서 받아진 Item 갯수를 토대로
ViewHolder 객체를 생성하는데,
화면에 보이는 전체 리스트 목록이 10개라면, 위아래 버퍼까지 감안해 13~15개 정도의 객체를 생성한다.
그렇기에, ViewHolder 객체는 Item 배열의 갯수만큼 생성된다.
*/
val viewBinding = ItemDataBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return DataViewHolder(viewBinding)
}
// ViewHolder 가 실제로 데이터를 표시할 때 호출되는 함수 - 앱 사용자의 해당 액티비티에서 스크롤할 때마다 액티비티가 변형되면 호출되는 메소드
// 액티비티에서 사라지는 요소를 토대로 View를 새롭게 Bind 시켜준다.
/*
onBindViewHolder 메소드는
데이터가 스크롤 되어서 맨 위에있던 뷰 홀더(레이아웃) 객체가 맨 아래로 이동한다면,
그 레이아웃(View)은 재사용 하되 데이터는 새롭게 바뀔 것이다. (bind 메소드를 통해서 바뀐다.)
아래에서 새롭게 보여질 데이터의 인덱스 값이 position이라는 이름으로 자동으로 받아서 사용가능하다.
*/
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
holder.bind(dataList[position])
}
// 앱에 나타낼 목록의 총 갯수를 Adapter 클래스에게 알려준다.
// 그래서, Adapter 클래스를 처음 생성했을 때, 실행되는 메소드로 초기화하지 않는 이상 해당 메소드는 한번실행된 채 앱이 구현된다.
override fun getItemCount(): Int {
return dataList.size
}
}
# MainActivity 클래스
package com.example.umc_week5
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.umc_week5.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
// 메인 액티비티 XML 객체 선언
private lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 메인 액티비티 XML 객체 생성
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
// RecyclerView에 표시될 Item을 ArrayList {Data} 객체 타입으로 배열로 선언
/*
arrayList는 배열의 크기가 자동으로 배정된다.
- 동적 배열
*/
val dataList: ArrayList<Data> = arrayListOf()
// arrayList 에 데이터 삽입
dataList.apply{
// arrayList 타입이 Data 객체이다. | 데이터 삽입 시 Data 객체 타입으로 넣어줌.
add(Data("hello", "1"))
add(Data("hello", "2"))
add(Data("hello", "3"))
add(Data("hello", "4"))
add(Data("hello", "5"))
add(Data("hello", "6"))
add(Data("hello", "7"))
add(Data("hello", "8"))
add(Data("hello", "9"))
add(Data("hello", "10"))
add(Data("hello", "11"))
add(Data("hello", "12"))
add(Data("hello", "13"))
add(Data("hello", "14"))
add(Data("hello", "15"))
add(Data("hello", "16"))
}
val dataRVAdapter = DataRVAdapter(dataList)
// Recycle View의 Adapter 구현
viewBinding.rvData.adapter = dataRVAdapter
// Recycle View의 Item 배치설정
viewBinding.rvData.layoutManager = LinearLayoutManager(this)
}
}
XML - Layout 파일
# activity_main 파일
activity_main으로 앱 뷰가 보여지는 곳이다.
그리고, RecyclerView 영역을 할당해줌으로써, 목록 리스트를 구현한다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--RecyclerView 영역 activity_xml에서 지정함.-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_data"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
# item_data 파일
RecyclerView에 들어갈 대표 View 객체이다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--RecyclerView를 구성할 때는 하나의 대표모델을 만든다.-->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:text="TextView"
android:textColor="@color/black"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/tv_title"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
<Switch
android:id="@+id/btn_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
'📚 스터디 > 프론트엔드' 카테고리의 다른 글
[안드로이드] 7주차: Thread & 동기, 비동기 작업 (0) | 2022.11.12 |
---|---|
[안드로이드] 6주차 실습: BottomNavigation & ViewPager2 - TabLayout (0) | 2022.11.06 |
[안드로이드] 6주차: 고급 Layout과 View (0) | 2022.11.05 |
[안드로이드] 4주차: LifeCycle 실습 (0) | 2022.11.01 |
[안드로이드] 4주차: LifeCycle, 외부 작용으로의 Activity 예외처리 (2) | 2022.10.24 |