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>
上記では、setMyViewModelという名前のセッターが存在するため、app:myViewModelの自動バインディング属性が作成されます。
まず、このカスタムビューが既に<include>
アクティビティなどの別のレイアウトで。タグが予期しない値であるという例外が発生します。データバインディングは既にバインディングを実行しているので、設定は完了です。
onFinishInflate
を使用してバインドを実行しようとしましたか? (Kotlinの例)
override fun onFinishInflate() {
super.onFinishInflate()
this.dataBinding = MyCustomBinding.bind(this)
}
ビューでバインディングを使用する場合、プログラムで作成することはできません。少なくとも、可能な場合でも両方をサポートすることは非常に複雑です。
georgeによって提示されたソリューションに従って Androidスタジオはカスタムビューをレンダリングできなくなりました。その理由は、次のコード:
public MyCustomView(...) {
...
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = MyCustomViewBinding.inflate(inflater);
}
バインディングはインフレーションを処理すると思いますが、グラフィカルエディターはそれを気に入らなかったと思います。
私の特定のユースケースでは、ビューモデル全体ではなく、単一のフィールドをバインドしたかったのです。私は(kotlin incoming)を思いつきました:
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
ここにはすでにいくつかの良い答えがありますが、私が信じている最も簡単なものを提供したいと思いました。
他のレイアウトと同様に、周囲のレイアウトタグでカスタムコントロールを作成します。たとえば、次のツールバーを参照してください。これは各アクティビティクラスで使用されます
<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 casedのレイアウトファイルの命名規則に従っているため、簡単に検索して自動入力できます。
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = NameOfCustomControlBinding.inflate(inflater);
お役に立てば幸いです。