Kotlinベース#13 DataBindingとBindingAdapter


デザインモデルなしで開発を行い、数週間前にデザインモデルを使うことを決意しました.
MVVMモードを使用するには、基本的にはDataBindingとLiveDataを理解する必要があります.

1. 😃 DataBindingとは?


これは、XMLにデータをバインドして不要なコードを減らすことを意味します.コード内
setTextを使用する必要はありません.

ViewBindingは変数や式を提供しないため、動的UIコンテンツを作成できません.
簡単な処理では、ViewBindingを使用する必要がある場合があります.

2. 😊 DataBindingの使い方


次のコードを見てください.
android {
.
.
.
dataBinding {
    enabled = true
    
}
アプリケーションレベルのBuild.gradeに記入し、Pluginを入れます.
apply plugin: 'kotlin-kapt'
使用するXMLに移動します.
//맨위에 layout을 선언한다.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    //넣게 되면 BindingAdapter 구분할때 편리하다.
    xmlns:bind="http://schemas.android.com/tools"
    xmlns:tools="http://schemas.android.com/tools">

  //Activity와 Data를 Bind시켜주는 말그대로의 의미
    <data>

        <variable
            name="activity"
            type="kr.co.kworks.studylivedatabindingadapter.MainActivity" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            이제 직접적으로 해당 액티비티의 변수를 바로바로 Bind할  있다.
            android:text="@{activity.liveText}"
            bind:visibleL="@{activity.liveVisible}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@id/btn_change1"
            app:layout_constraintVertical_chainStyle="packed"/>

        <Button
            android:id="@+id/btn_change1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="visible"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text_view"
            app:layout_constraintBottom_toTopOf="@id/btn_change2"/>

        <Button
            android:id="@+id/btn_change2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="gone"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/btn_change1"
            app:layout_constraintBottom_toBottomOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

3. 🥰 BindingAdapter


データバインディングを実際の操作に適用するには、BindingAdapterが好きなようにしなければなりません.
ImageView、ListView、Recycleviewなどの機能が複雑なビューはBindingAdderで処理しなければならないからです.
@BindingAdapter("dragTargetView")
fun setSwipeLayout(swipeLayout: SwipeLayout, dragTargetView: View?) {
    //null일경우, 리턴한다.
    dragTargetView ?: return
    swipeLayout.apply {
        showMode = SwipeLayout.ShowMode.LayDown
        isLeftSwipeEnabled = false
        addDrag(SwipeLayout.DragEdge.Left, dragTargetView)
    }
}
このバインディングはSWEEELayoutを設定するために作成されました.
次は対応するxmlです.
  <com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/swipeLayout_item_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:minHeight="80dp"
                                  
        변수로 아래의 ConstraintLayout을 줘버렸다.              
        bind:dragTargetView="@{constraintLayoutDeleteButtonContainer}">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/constraintLayout_delete_button_container"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="end"
            android:background="@android:color/holo_red_dark"
            android:paddingStart="36dp"
            android:paddingEnd="36dp">

            <ImageView
                android:id="@+id/imageView_delete"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_marginBottom="4dp"
                android:contentDescription="@string/item_main_delete_image_content_description"
                android:src="@drawable/ic_delete_white_48dp"
                app:layout_constraintBottom_toTopOf="@id/textView_delete"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintVertical_chainStyle="packed" />

            <TextView
                android:id="@+id/textView_delete"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/item_main_delete_text"
                android:textColor="@android:color/white"
                android:textSize="12sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="@id/imageView_delete"
                app:layout_constraintStart_toStartOf="@id/imageView_delete"
                app:layout_constraintTop_toBottomOf="@id/imageView_delete" />

        </androidx.constraintlayout.widget.ConstraintLayout>
このようにswifeレイアウトの設定は終了しました.bodynならactivityにoverlightを付けるべきですがbindingAdapterを使うときれいになっているのが見えます.

4. 😚 冗長BindingAdapter


同じ名前であれば、異なる変数を受け入れることもできます.
この場合、適切なマッピングを自分で行うことができます.
@BindingAdapter("loadImage")
public static void loadImage(ImageView view, String path) {
    GlideApp.with(view.getContext())
            .load(path)
            .into(view);
}
@BindingAdapter("loadImage")
public static void loadImage(ImageView view, Uri uri) {
    GlideApp.with(view.getContext())
            .load(uri)
            .into(view);
}
@BindingAdapter("loadImage")
public static void loadImage(ImageView view, int resId) {
    GlideApp.with(view.getContext())
            .load(resId)
            .into(view);
}
もう一つ注意すべきことは、xmlから別のviewにメソッドを書き込む場合、この方法が可能であることです.
@BindingAdapter(value = {"android:visibility", "visibleAnimType"
, "goneAnimType "}, requireAll = false)
public static void setVisibility(View view, 
int visibility, int visibleAnimType, int goneAnimType ) {
}
RequireAll=falseを使用する場合は、すべてのパラメータは必要ありません.でも.
予期せぬ事態を避けるために、例外処理を行うべきです.
Javaのデフォルトオブジェクトタイプがnullの場合、0が返されます.
BindingAdapter

2021年08月29日


簡単にdataBindingを書きましょう
BaseActivityで
    protected inline fun <reified T : ViewDataBinding> binding(resId: Int): Lazy<T> =
        lazy { DataBindingUtil.setContentView<T>(this, resId) }
BaseFragmentで
    protected inline fun < T : ViewDataBinding> binding(
        inflater: LayoutInflater,
        @LayoutRes resId: Int,
        container: ViewGroup?
    ): T = DataBindingUtil.inflate(inflater, resId, container, false)
2つのコードを追加します.

呼び出し


Activityはこのように呼び出されます.
    private val binding by binding<ActivityIntroBinding>(R.layout.activity_intro)
    
       override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        with(binding) {
            lifecycleOwner = this@IntroActivity // binding에 LifeCycle을 지정해줘야함.
            }
       }
Fragmentはこのように呼び出された.
class AddDialogFragment : BaseBottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ) = binding<FragmentAddBinding>(
        inflater, R.layout.fragment_add, container
    ).apply {
        lifecycleOwner = this@AddDialogFragment
    }.root