iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0
Mobile Development

Android Studio 30天學習紀錄系列 第 15

Android Studio 30天學習紀錄-Day15 DataBinding雙向綁定(自訂方法)

  • 分享至 

  • xImage
  •  

在昨天講完ObservableField的雙向綁定後,今天要來使用BindingAdapter及InverseBindingAdapter等實作雙向綁定,那麼首先一樣先加入依賴至gradle中:

android {
    ...
    dataBinding {
        enabled = true
    }
}

UI

首先一樣,先把布局更換成data binding的layout,那麼一樣先將今天設計的布局貼上來,稍後會去設計一個ProgressData的Model。
https://ithelp.ithome.com.tw/upload/images/20220926/20139259wxX80NrJtT.png

<layout 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">

    <data>
        <variable
            name="ProgressData"
            type="com.example.bindingadapter.ProgressData" />
    </data>

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

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(ProgressData.progress_1)}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.979"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.5" />

        <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="246dp"
            android:layout_height="wrap_content"
            app:progressing="@={ProgressData.progress_1}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.357"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.5" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

自訂方法(BindingAdapter、InverseBindingAdapter)

BindingAdapter可用於自訂一個方法,並且透過可從布局中直接做使用,可以把他理解成setter,而InverseBindingAdapter則是getter,這樣則為雙向綁定,而雙向綁定官方也有釋出一些調配器做使用:
https://ithelp.ithome.com.tw/upload/images/20220926/20139259CzX389ESzA.jpg
參考:Android Developers


BindingAdapter

寫法大約是這樣,我建立一個progressing的方法並且給ProgressBar做使用,然後layout在做使用會傳入一個ObservableField的參數,這邊是當數據發生變化時要做什麼,然後要注意這個方法必須是靜態的(static)。

@BindingAdapter(value = "progressing")
    public static void setProgressing(ProgressBar progressBar, ObservableField<Integer>){
        //要做的事...
    }

InverseBindingAdapter

InverseBindingAdapter綁的attribute必須和BindingAdapter設定的value相同,主要是當視圖屬性發生變化時會調用此,而屬性+AttrChanged這個BindingAdapter在你設定完InverseBindingAdapter要將layout自訂屬性改為雙向時必不可少的方法之一,主要是他不知道屬性何時更改,用這個BindingAdapter可以在裡面加入監聽器等判斷他View的更新。

@InverseBindingAdapter(attribute = "progressing")
    public static int getProgressing(ProgressBar progressBar) {
        //要做的事...
    }
    
@BindingAdapter(value = "progressingAttrChanged")
    public static void setProgressingAttrChanged(ProgressBar progressBar, InverseBindingListener attrChange) {
        // Set a listener for click, focus, touch
    }

ProgressData

那麼接著來設計需要的Model,一樣會用到昨天寫雙向的ObservableField。

public class ProgressData{
    private static int[] progressValue = {0};
    public final ObservableField<Integer> progress_1 = new ObservableField<>();
    
    //以此使ProgressBar進行遞增並run至完成
    @BindingAdapter(value = "progressing")
    public static void setProgressing(ProgressBar progressBar, ObservableField<Integer> progress_1) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (progressValue[0] <= 100) {
                    try {
                        Thread.sleep(500);
                        progressBar.setProgress(progressValue[0]);//設定progress進度
                        progress_1.set(progressBar.getProgress());//設定資料
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    progressValue[0] = progressValue[0] + 1;//遞增progress進度
                    //當進度滿時,更改progressBar背景顏色(因為是在線程更改ui,所以需要包Looper)
                    if(progressValue[0]==100){
                        Looper.prepare();
                        progressBar.setBackgroundColor(Color.argb(25,25,30,10));
                        Looper.loop();
                    }
                }
            }
        }).start();
    }
    //取得progress的自訂getter
    @InverseBindingAdapter(attribute = "progressing")
    public static int getProgressing(ProgressBar progressBar) {
        return progressBar.getProgress();
    }
    //必加屬性(可用於判斷屬性何時做更改)
    @BindingAdapter(value = "progressingAttrChanged")
    public static void setProgressingAttrChanged(ProgressBar progressBar, InverseBindingListener attrChange) {
        attrChange.onChange();
    }
}

設計完後,我便可在layout的元件上加入我自訂的屬性(app:processing):

<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="246dp"
    android:layout_height="wrap_content"
    app:progressing="@={ProgressData.progress_1}"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.357"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.5" />

MainActivity

最後還需要去給他databinding的variable資料。

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;
    ProgressData progressData;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        progressData= new ProgressData();
        binding.setProgressData(progressData);
    }
}

成果

https://ithelp.ithome.com.tw/upload/images/20220926/20139259va4yFijXsd.jpg


上一篇
Android Studio 30天學習紀錄-Day14 DataBinding雙向綁定
下一篇
Android Studio 30天學習紀錄-Day16 SQLiteDataBase
系列文
Android Studio 30天學習紀錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言