簡體   English   中英

android數據與自定義視圖綁定

[英]android data binding with a custom view

Android 數據綁定指南討論了活動或片段中的綁定值,但是有沒有辦法與自定義視圖執行數據綁定?

我想做類似的事情:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.mypath.MyCustomView
        android:id="@+id/my_view"
        android:layout_width="match_parent"
        android:layout_height="40dp"/>

</LinearLayout>

使用my_custom_view.xml

<layout>

<data>
    <variable
        name="myViewModel"
        type="com.mypath.MyViewModelObject" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{myViewModel.myText}" />

</LinearLayout>

</layout>

雖然似乎可以通過在自定義視圖上設置自定義屬性來做到這一點,但如果要綁定很多值,這很快就會變得很麻煩。

有什么好方法可以完成我想做的事情嗎?

在您的自定義視圖中,按照您通常的方式擴充布局,並為您要設置的屬性提供一個設置器:

private MyCustomViewBinding mBinding;
public MyCustomView(...) {
    ...
    LayoutInflater inflater = (LayoutInflater)
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mBinding = MyCustomViewBinding.inflate(inflater);
}

public void setMyViewModel(MyViewModelObject obj) {
    mBinding.setMyViewModel(obj);
}

然后在布局中使用它:

<layout xmlns...>
    <data>
        <variable
            name="myViewModel"
            type="com.mypath.MyViewModelObject" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.mypath.MyCustomView
            android:id="@+id/my_view"
            app:myViewModel="@{myViewModel}"
            android:layout_width="match_parent"
            android:layout_height="40dp"/>

    </LinearLayout>
</layout>

在上面,為 app:myViewModel 創建了一個自動綁定屬性,因為有一個名為 setMyViewModel 的 setter。

數據綁定即使在合並時也能正常工作,只有父級必須是“this”並附加到父級為真。

binding = DataBindingUtil.inflate(inflater, R.layout.view_toolbar, this, true)

首先,如果此自定義視圖已經在另一個布局(例如活動等)中<include> ,請不要這樣做。您只會得到有關標簽為意外值的異常。 數據綁定已經在其上運行了綁定,所以你已經設置好了。

您是否嘗試使用onFinishInflate來運行綁定? (科特林示例)

override fun onFinishInflate() {
    super.onFinishInflate()
    this.dataBinding = MyCustomBinding.bind(this)
}

請記住,如果您在視圖中使用綁定,它將無法以編程方式創建,至少即使您可以支持兩者也會非常復雜。

按照 george 提出的解決方案,android studio 中的圖形編輯器不再能夠呈現自定義視圖。 原因是,在以下代碼中實際上並沒有放大任何視圖:

public MyCustomView(...) {
    ...
    LayoutInflater inflater = (LayoutInflater)
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mBinding = MyCustomViewBinding.inflate(inflater);
}

我想綁定會處理通貨膨脹,但是圖形編輯器不喜歡它。

在我的特定用例中,我想綁定單個字段而不是整個視圖模型。 我想出了(kotlin傳入):

class LikeButton @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {

    val layout: ConstraintLayout = LayoutInflater.from(context).inflate(R.layout.like_button, this, true) as ConstraintLayout

    var numberOfLikes: Int = 0
      set(value) {
          field = value
          layout.number_of_likes_tv.text = numberOfLikes.toString()
      }
}

點贊按鈕由圖像和文本視圖組成。 文本視圖包含喜歡的數量,我想通過數據綁定來設置。

通過將 numberOfLikes 的設置器用作以下 xml 中的屬性,數據綁定會自動建立關聯:

<views.LikeButton
  android:id="@+id/like_btn"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:numberOfLikes="@{story.numberOfLikes}" />

進一步閱讀: https ://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47

今天,我想在我的自定義視圖類上使用數據綁定。 但我不知道如何為我的班級創建數據綁定。 所以我在 StackOverflow 上搜索答案。 首先我嘗試答案:

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = BottomBarItemCustomViewBinding.inflate(inflater);

但是,我發現這不適用於我的代碼

所以我改變了另一種方法:

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);

它對我有用。

完整代碼為:bottom_bar_item_custom_view.xml

<data>

    <variable
        name="contentText"
        type="String" />

    <variable
        name="iconResource"
        type="int" />

</data>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center">

    <ImageView
        android:id="@+id/bottomBarItemIconIv"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginTop="2dp"
        android:src="@{iconResource}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/bottomBarItemContentTv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="@{contentText}"
        android:textColor="@color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/bottomBarItemIconIv" />


</androidx.constraintlayout.widget.ConstraintLayout>

BottomBarItemCustomView.java

public class BottomBarItemCustomView extends ConstraintLayout {

public BottomBarItemCustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context, attrs);
}

private void init(Context context, AttributeSet attrs) {
    //use dataBinding on custom view.
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);

    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BottomBarItemCustomView);
    int iconResourceId = typedArray.getResourceId(R.styleable.BottomBarItemCustomView_bottomBarIconResource, R.drawable.my_account_icon);
    binding.setIconResource(iconResourceId);

    String contentString = typedArray.getString(R.styleable.BottomBarItemCustomView_bottomBarContentText);
    if (contentString != null) {
        binding.setContentText(contentString);
    }

    typedArray.recycle();
}

希望對你有用!

這里已經有一些很好的答案,但我想提供我認為最簡單的答案。

使用圍繞它的布局標簽創建您的自定義控件,就像任何其他布局一樣。 例如,請參見以下工具欄。 這被用於每個活動類

<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="YACustomPrefs" type="com.appstudio35.yourappstudio.models.YACustomPreference" />
</data>

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/YATheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:popupTheme="@style/YATheme.PopupOverlay"/>

    </android.support.design.widget.AppBarLayout>

</android.support.design.widget.CoordinatorLayout>

現在這個自定義布局是每個活動的孩子。 您只需在 onCreate 綁定設置中這樣對待它。

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    binding.yaCustomPrefs = YACustomPreference.getInstance(this)
    binding.toolbarMain?.yaCustomPrefs = YACustomPreference.getInstance(this)
    binding.navHeader?.yaCustomPrefs = YACustomPreference.getInstance(this)

    binding.activity = this
    binding.iBindingRecyclerView = this
    binding.navHeader?.activity = this

    //local pointer for notify txt badge
    txtNotificationCountBadge = txtNotificationCount

    //setup notify if returned from background so we can refresh the drawer items
    AppLifeCycleTracker.getInstance().addAppToForegroundListener(this)

    setupFilterableCategories()
    setupNavigationDrawer()
}

請注意,我在設置父項的同時設置了子項的內容,這都是通過點符號訪問完成的。 只要文件被布局標簽包圍並命名,就很簡單了。

現在,如果自定義類有它自己的關聯代碼膨脹,那么它可以很容易地在它的 onCreate 或構造函數中進行自己的綁定,但你明白了。 如果您有自己的類,只需在構造函數中拋出以下內容以匹配它的命名綁定類。 它遵循布局文件 pascal 大小寫的命名約定,因此很容易查找和自動填充。

    LayoutInflater inflater = (LayoutInflater)
    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = NameOfCustomControlBinding.inflate(inflater);

希望有所幫助。

當我嘗試將子視圖添加到主機片段(嵌套片段 UI/UX)中的LinearLayout時,我遇到了同樣的問題

這是我的解決方案

var binding: LayoutAddGatewayBinding? = null
binding = DataBindingUtil.inflate(layoutInflater, R.layout.layout_add_gateway,
            mBinding?.root as ViewGroup?, false)
binding?.lifecycleOwner=this
val nameLiveData = MutableLiveData<String>()
nameLiveData.value="INTIAL VALUE"
binding?.text=nameLiveData

這里mBinding是子片段ViewDataBinding對象,我使用nameLiveData進行雙向數據綁定

在Kotlin中我們可以直接使用ViewBinding:

class BenefitView(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {

    init {
        val binding = BenefitViewBinding.inflate(LayoutInflater.from(context), this, true)
        val attributes = context.obtainStyledAttributes(attrs, R.styleable.BenefitView)
        binding.image.setImageDrawable(attributes.getDrawable(R.styleable.BenefitView_image))
        binding.caption.text = attributes.getString(R.styleable.BenefitView_text)
        attributes.recycle()

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM