PlantListFragment에 있는 RecyclerView를 만들자.
그 전에 RecyclerView list item인 CardView를 커스텀하자.
// views/MaskedCardView
import android.graphics.Path
import com.google.android.material.R
class MaskedCardView @JvmOverloads constructor(
context: Context,
attrs, AttributeSet? = null,
defStyle: Int, R.attr.materialCardViewStyle
) : MaterialCardView(context, attrs, defStyle) {
...
}
MaterialCardView를 부모뷰로 MaskedCardView 클래스를 생성한다.
View를 상속받은 클래스를 생성할 때에는 3개의 생성자가 필요하며, constructor
를 필요로 한다.
View(context: Context)
View(context: Context, attrs: AttributeSet)
View(context: Context, attrs: AttributeSet, defStyleRes: Int)
3개의 생성자가 모두 필요하지만, 생성자 오버로딩을 자동으로 해주는 @JvmOverloads
어노테이션을 사용하게 되면 코드가 한층 간결해진다.
@SuppressLint("RestrictedApi")
린트 검사 사용 중지 코드
(RestrictedApi 린트 검사 중지)
해당 프로젝트에 설정된 minSdkVersion 이후에 나온 API를 사용할 때 생기는 warning을 제거하고 API를 사용할 수 있게 함
override fun onDraw(canvas: Canvas) {
canvas.clipPath(path)
super.onDraw(canvas)
}
클립영역을 지정하여 canvas에 그린다.
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
...
super.onSizeChanged(w, h, oldw, oldh)
}
CardView 사이즈 조절
RecyclerView에 item으로 들어갈 layout을 생성한다.
<data>
<variable
name="clickListener"
type="android.view.View.OnClickListener" />
<variable
name="plant"
type="com.jaemin.sunflower_clone.data.Plant" />
</data>
dataBinding에 필요한 data 변수를 선언한다.
<com.jaemin.sunflower_clone.views.MaskedCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/card_side_margin"
android:layout_marginEnd="@dimen/card_side_margin"
android:layout_marginBottom="@dimen/card_bottom_margin"
android:onClick="@{clickListener}"
app:cardElevation="@dimen/card_elevation"
app:cardPreventCornerOverlap="false"
app:shapeAppearanceOverlay="@style/ShapeAppearance.Sunflower.Card">
...
</com.jaemin.sunflower_clone.views.MaskedCardView>
아까 생성한 CustomCardView를 배치해준다.
app:cardElevation
: 그림자 효과
app:cardPreventCornerOverlap
: 내용과 모서리가 겹칠 때 사용하는 속성
app:shapeAppearanceOverlay
: CardView 스타일 정의
<style name="ShapeAppearance.Sunflower.Card" parent="ShapeAppearance.MaterialComponents">
<item name="cornerFamily">rounded</item>
<item name="cornerSizeTopLeft">0dp</item>
<item name="cornerSizeTopRight">@dimen/card_corner_radius</item>
<item name="cornerSizeBottomRight">0dp</item>
<item name="cornerSizeBottomLeft">@dimen/card_corner_radius</item>
</style>
<ConstraintLayout>
<ImageView/>
<TextView/>
<ConstraintLayout/>
ConstraintLayout으로 이미지뷰와 텍스트 배치
app:imageFromUrl="@{plant.imageUrl}"
...
android:text="@{plant.name}"
dataBinding으로 데이터 속성과 뷰 연결
tools:text="Tomato"
: 데이터바인딩으로 텍스트가 연결되어 있을 때 레이아웃 상으로는 보이지 않기 때문에, 임의의 텍스트를 레이아웃상으로 보여지게 하기 위한 속성
app:imageFromUrl
속성은 데이터바인딩의 Binding Adapter로 이루어진 속성이다.
이미지 Url을 가지고 있는 데이터 객체의 해당 url 속성과 view 를 연결시키면 이미지뷰가 나타난다.
먼저 url을 이용해서 이미지를 로드할 수 있는 Glide 라이브러리를 사용하기 위한 dependency를 추가해보자.
implementation "com.github.bumptech.glide:glide:$rootProject.glideVersion"
kapt "com.github.bumptech.glide:compiler:$rootProject.glideVersion"
그 다음 BindingAdapter를 생성해준다.
@BindingAdapter("imageFromUrl")
fun bindImageFromUrl(view: ImageView, imageUrl: String?){
if (!imageUrl.isNullOrEmpty()) {
Glide.with(view.context)
.load(imageUrl)
.transition(DrawableTransitionOptions.withCrossFade())
.into(view)
}
}