私はデータバインディングとMVVMを備えたアプリを開発してきました。
横向きモードでアプリに別のレイアウトを使用しようとしています。私が持っています:
layout/fragment_content.xml
layout-land/fragment_content.xml
どちらのレイアウトも同じビューで外観が異なり、次のように同じビューモデルからフィードを取得します。
<layout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto">
<data class="MyBinding">
<variable
name="viewModel"
type="com.myapp.package.viewModel.VMFirst"/>
<variable
name="controlModel"
type="com.myapp.package.viewModel.VMSecond"/>
</data>
<DIFFERENT CONTENT HERE>
すべてのビューとIDは両方のレイアウトに存在します。
問題は、コンパイルされないことです。エラーは単に"cannot find symbol method getViewModel"
および他の変数のゲッター。
私がこれまでに試したこと:
Layoutおよびlayout-landフォルダーの使用(失敗、エラーは上記で説明されています)
レイアウトエイリアスの使用 レイアウトエイリアスの使用 ここで見つけました 問題199344:データバインディングがレイアウトエイリアスで機能しません 。このアプローチを試している間、xmlファイルでは何も変更しませんでした。これも失敗しました。エラーはCould not write to com.myapp.package.databinding.MyBinding
複数のレイアウトファイルでデータバインディングdata
タグを使用することはできませんか?データバインディングを使用しているときに、状態ごとに異なるレイアウトを使用するには、何を使用する必要がありますか?ありがとう!
編集:削除class="MyBinding"
エラーは変更されませんでした。
誰かがこの質問を検索した場合、2年後に同じことを試みましたが、今ではすべて正常に機能していることがわかりました。
layout
とactivity_main
の下にレイアウトファイルlayout_sw600dp
を作成しました。 layout
リソースの下のレイアウトは次のとおりです。
<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">
<variable
name="small_variable"
type="Integer"/>
<androidx.constraintlayout.widget.ConstraintLayout
Android:id="@+id/myRoot"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">
<View
Android:id="@+id/small_square"
Android:layout_width="60dp"
Android:layout_height="60dp"
Android:background="@Android:color/holo_blue_bright"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
これはlayout_sw600dp
フォルダの下のレイアウトです:
<?xml version="1.0" encoding="utf-8"?>
<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">
<variable
name="big_variable"
type="Long"/>
<androidx.constraintlayout.widget.ConstraintLayout
Android:id="@+id/myRoot"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context=".MainActivity">
<View
Android:id="@+id/big_square"
Android:layout_width="60dp"
Android:layout_height="60dp"
Android:background="@Android:color/holo_blue_bright"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
どちらにもビューがありますが、それぞれに異なるIDがあります:small_square
とbig_square
。
私は携帯電話とタブレットでプロジェクトを実行しています。これが私の発見です:
myRoot
はnull許容ビューではありません Kotlinからのバインディングを使用する場合、big_square
およびsmall_square
null許容ビュー。変数は、すべてのレイアウトに存在するかどうかに関係なくnull許容です(これは予想される動作です)。MainBinding
、または定義しない場合はデフォルトでLayoutResourceName
+ Binding
)。small_variable
&small_square
はコード側でbinding.smallVariable
とbinding.smallSquare
でした。binding.bigSquare?.operation
のようなビューを使用できます。これは、タブレットや電話、ビューがnullかどうかを事前に確認する必要がないので便利です。binding
フィールドを割り当てることができます。コードでbinding.smallVariable = 3
と言うと、割り当てが行われ、値が保存されます。注意するのは良いことだと思います。私はアプリでMVVMを頻繁に使用しており、その周りにライブラリも構築しています。
私は、すべてのXMLに単一のViewModelがあるという規則に従います。また、viewmodel変数の名前はすべてのXMLで同じです。
したがって、あなたの場合、VMFirst
とVMSecond
を含む別のViewModelクラスを作成できます。
public class ParentVM {
VMFirst first;
VMSecond second;
}
両方のXML(ポートレートとランドスケープ)は同じ名前になります。たとえば、activity_main.xml
。
<layout>
<data>
<variable
type="ParentViewModel"
name="vm"/>
</data>
その場合、MainActivityコードでチェックする必要はありません。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewDataBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setVariable(BR.vm, new ParentViewModel());
}
これは機能します。
実際、私はすべてのxmlで同じ変数名に従うので、基本クラスMvvmActivity
自体にバインディングロジックを含めることができます。したがって、私のすべての活動は次のようになります。
public class MainActivity extends MvvmActivity {
@NonNull
@Override
protected ViewModel createViewModel() {
return new MainViewModel();
}
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
}
MvvmActivityの実装: MvvmActivity.Java
一定のデータバインディング変数を維持するもう1つの利点は、XML自体でRecyclerViewまたはViewPagerアダプターをセットアップできることです。詳細については、 XMLからのRecyclerViewのセットアップ を参照してください。
デフォルトでは、Bindingクラスはレイアウトファイルの名前に基づいて生成され、Pascalケースに変換され、「Binding」という接尾辞が付けられます。上記のレイアウトファイルはmain_activity.xmlであったため、生成クラスはMainActivityBindingでした。 -- バインディングデータ
コンパイル時に生成されます。
したがって、Javaコードで別のレイアウトを選択してください。
layout/
R.layout.activity_main
R.layout.activity_main_tablet
values/
<bool name="is_mobile">true</bool>
<bool name="is_tablet">false</bool>
values-w820dp/
<bool name="is_mobile">false</bool>
<bool name="is_tablet">true</bool>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getResources().getBoolean(R.bool.is_mobile)) {
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
} else {
ActivityMainTabletBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main_tablet);
}
}