Make ViewStub support binding variables like include.
Bug 19969378
This commit is contained in:
@@ -20,6 +20,7 @@ import android.databinding.tool.expr.Expr;
|
||||
import android.databinding.tool.reflection.ModelAnalyzer;
|
||||
import android.databinding.tool.reflection.ModelClass;
|
||||
import android.databinding.tool.store.SetterStore;
|
||||
import android.databinding.tool.store.SetterStore.SetterCall;
|
||||
|
||||
public class Binding {
|
||||
|
||||
@@ -37,8 +38,16 @@ public class Binding {
|
||||
private SetterStore.SetterCall getSetterCall() {
|
||||
if (mSetterCall == null) {
|
||||
ModelClass viewType = mTarget.getResolvedType();
|
||||
mSetterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName,
|
||||
viewType, mExpr.getResolvedType(), mExpr.getModel().getImports());
|
||||
if (viewType != null && viewType.extendsViewStub()) {
|
||||
if (isViewStubAttribute()) {
|
||||
mSetterCall = new ViewStubDirectCall(mName, viewType, mExpr);
|
||||
} else {
|
||||
mSetterCall = new ViewStubSetterCall(mName);
|
||||
}
|
||||
} else {
|
||||
mSetterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName,
|
||||
viewType, mExpr.getResolvedType(), mExpr.getModel().getImports());
|
||||
}
|
||||
}
|
||||
return mSetterCall;
|
||||
}
|
||||
@@ -77,4 +86,55 @@ public class Binding {
|
||||
public Expr getExpr() {
|
||||
return mExpr;
|
||||
}
|
||||
|
||||
private boolean isViewStubAttribute() {
|
||||
if ("android:inflatedId".equals(mName)) {
|
||||
return true;
|
||||
} else if ("android:layout".equals(mName)) {
|
||||
return true;
|
||||
} else if ("android:visibility".equals(mName)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewStubSetterCall extends SetterCall {
|
||||
private final String mName;
|
||||
|
||||
public ViewStubSetterCall(String name) {
|
||||
mName = name.substring(name.lastIndexOf(':') + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJavaInternal(String viewExpression, String converted) {
|
||||
return "if (" + viewExpression + ".isInflated()) " + viewExpression +
|
||||
".getBinding().setVariable(BR." + mName + ", " + converted + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinApi() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ViewStubDirectCall extends SetterCall {
|
||||
private final SetterCall mWrappedCall;
|
||||
|
||||
public ViewStubDirectCall(String name, ModelClass viewType, Expr expr) {
|
||||
mWrappedCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(name,
|
||||
viewType, expr.getResolvedType(), expr.getModel().getImports());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toJavaInternal(String viewExpression, String converted) {
|
||||
return "if (!" + viewExpression + ".isInflated()) " +
|
||||
mWrappedCall.toJava(viewExpression + ".getViewStub()", converted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinApi() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ public abstract class ModelAnalyzer {
|
||||
public static final String VIEW_DATA_BINDING =
|
||||
"android.databinding.ViewDataBinding";
|
||||
|
||||
public static final String VIEW_STUB_CLASS_NAME = "android.view.ViewStub";
|
||||
|
||||
private ModelClass[] mListTypes;
|
||||
private ModelClass mMapType;
|
||||
private ModelClass mStringType;
|
||||
@@ -77,6 +79,7 @@ public abstract class ModelAnalyzer {
|
||||
private ModelClass mObservableMapType;
|
||||
private ModelClass[] mObservableFieldTypes;
|
||||
private ModelClass mViewBindingType;
|
||||
private ModelClass mViewStubType;
|
||||
|
||||
private static ModelAnalyzer sAnalyzer;
|
||||
|
||||
@@ -282,6 +285,13 @@ public abstract class ModelAnalyzer {
|
||||
return mObservableFieldTypes;
|
||||
}
|
||||
|
||||
ModelClass getViewStubType() {
|
||||
if (mViewStubType == null) {
|
||||
mViewStubType = findClass(VIEW_STUB_CLASS_NAME, null);
|
||||
}
|
||||
return mViewStubType;
|
||||
}
|
||||
|
||||
private ModelClass loadClassErasure(String className) {
|
||||
return findClass(className, null).erasure();
|
||||
}
|
||||
|
||||
@@ -128,6 +128,13 @@ public abstract class ModelClass {
|
||||
return ModelAnalyzer.getInstance().getObjectType().equals(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether or not this ModelClass type extends ViewStub.
|
||||
*/
|
||||
public boolean extendsViewStub() {
|
||||
return ModelAnalyzer.getInstance().getViewStubType().isAssignableFrom(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether or not this is an Observable type such as ObservableMap, ObservableList,
|
||||
* or Observable.
|
||||
|
||||
@@ -17,6 +17,8 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import android.databinding.tool.reflection.ModelAnalyzer;
|
||||
import android.databinding.tool.reflection.ModelClass;
|
||||
import android.databinding.tool.util.L;
|
||||
import android.databinding.tool.util.ParserHelper;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class ExprModelExt {
|
||||
}
|
||||
}
|
||||
|
||||
val ExprModel.ext by Delegates.lazy { (target : ExprModel) ->
|
||||
val ExprModel.ext by Delegates.lazy { target : ExprModel ->
|
||||
ExprModelExt()
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fun ExprModel.getUniqueFieldName(base : String) : String = ext.getUniqueFieldNam
|
||||
|
||||
fun ExprModel.localizeFlag(set : FlagSet, base : String) : FlagSet = ext.localizeFlag(set, base)
|
||||
|
||||
val BindingTarget.readableUniqueName by Delegates.lazy {(target: BindingTarget) ->
|
||||
val BindingTarget.readableUniqueName by Delegates.lazy { target: BindingTarget ->
|
||||
val variableName : String
|
||||
if (target.getId() == null) {
|
||||
variableName = "boundView" + target.getTag()
|
||||
@@ -84,7 +84,17 @@ val BindingTarget.readableUniqueName by Delegates.lazy {(target: BindingTarget)
|
||||
target.getModel().ext.getUniqueFieldName(variableName)
|
||||
}
|
||||
|
||||
val BindingTarget.fieldName by Delegates.lazy { (target : BindingTarget) ->
|
||||
fun BindingTarget.superConversion(variable : String) : String {
|
||||
if (isBinder()) {
|
||||
return "${getViewClass()}.bind(${variable})"
|
||||
} else if (getResolvedType() != null && getResolvedType().extendsViewStub()) {
|
||||
return "new android.databinding.ViewStubProxy((android.view.ViewStub) ${variable})"
|
||||
} else {
|
||||
return "(${interfaceType}) ${variable}"
|
||||
}
|
||||
}
|
||||
|
||||
val BindingTarget.fieldName by Delegates.lazy { target : BindingTarget ->
|
||||
if (target.getFieldName() == null) {
|
||||
if (target.getId() == null) {
|
||||
target.setFieldName("m${target.readableUniqueName.capitalize()}")
|
||||
@@ -96,61 +106,70 @@ val BindingTarget.fieldName by Delegates.lazy { (target : BindingTarget) ->
|
||||
target.getFieldName();
|
||||
}
|
||||
|
||||
val BindingTarget.getterName by Delegates.lazy { (target : BindingTarget) ->
|
||||
val BindingTarget.getterName by Delegates.lazy { target : BindingTarget ->
|
||||
"get${target.readableUniqueName.capitalize()}"
|
||||
}
|
||||
|
||||
val BindingTarget.androidId by Delegates.lazy { (target : BindingTarget) ->
|
||||
val BindingTarget.androidId by Delegates.lazy { target : BindingTarget ->
|
||||
"R.id.${target.getId().androidId()}"
|
||||
}
|
||||
|
||||
val Expr.readableUniqueName by Delegates.lazy { (expr : Expr) ->
|
||||
val BindingTarget.interfaceType by Delegates.lazy { target : BindingTarget ->
|
||||
if (target.getResolvedType() != null && target.getResolvedType().extendsViewStub()) {
|
||||
"android.databinding.ViewStubProxy"
|
||||
} else {
|
||||
target.getInterfaceType()
|
||||
}
|
||||
}
|
||||
|
||||
val Expr.readableUniqueName by Delegates.lazy { expr : Expr ->
|
||||
Log.d { "readableUniqueName for ${expr.getUniqueKey()}" }
|
||||
val stripped = "${expr.getUniqueKey().stripNonJava()}"
|
||||
expr.getModel().ext.getUniqueFieldName(stripped)
|
||||
}
|
||||
|
||||
val Expr.fieldName by Delegates.lazy { (expr : Expr) ->
|
||||
"m${expr.readableUniqueName.capitalize()}"
|
||||
val Expr.readableName by Delegates.lazy { expr : Expr ->
|
||||
Log.d { "readableUniqueName for ${expr.getUniqueKey()}" }
|
||||
"${expr.getUniqueKey().stripNonJava()}"
|
||||
}
|
||||
|
||||
val Expr.hasFlag by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.fieldName by Delegates.lazy { expr : Expr ->
|
||||
"m${expr.readableName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.hasFlag by Delegates.lazy { expr : Expr ->
|
||||
expr.getId() < expr.getModel().getInvalidateableFieldLimit()
|
||||
}
|
||||
|
||||
val Expr.localName by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.localName by Delegates.lazy { expr : Expr ->
|
||||
if(expr.isVariable()) expr.fieldName else "${expr.readableUniqueName}"
|
||||
}
|
||||
|
||||
val Expr.setterName by Delegates.lazy { (expr : Expr) ->
|
||||
"set${expr.readableUniqueName.capitalize()}"
|
||||
val Expr.setterName by Delegates.lazy { expr : Expr ->
|
||||
"set${expr.readableName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.onChangeName by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.onChangeName by Delegates.lazy { expr : Expr ->
|
||||
"onChange${expr.readableUniqueName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.getterName by Delegates.lazy { (expr : Expr) ->
|
||||
"get${expr.readableUniqueName.capitalize()}"
|
||||
val Expr.getterName by Delegates.lazy { expr : Expr ->
|
||||
"get${expr.readableName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.staticFieldName by Delegates.lazy { (expr : Expr) ->
|
||||
"s${expr.readableUniqueName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.dirtyFlagName by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.dirtyFlagName by Delegates.lazy { expr : Expr ->
|
||||
"sFlag${expr.readableUniqueName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.shouldReadFlagName by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.shouldReadFlagName by Delegates.lazy { expr : Expr ->
|
||||
"sFlagRead${expr.readableUniqueName.capitalize()}"
|
||||
}
|
||||
|
||||
val Expr.invalidateFlagName by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.invalidateFlagName by Delegates.lazy { expr : Expr ->
|
||||
"sFlag${expr.readableUniqueName.capitalize()}Invalid"
|
||||
}
|
||||
|
||||
val Expr.conditionalFlagPrefix by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.conditionalFlagPrefix by Delegates.lazy { expr : Expr ->
|
||||
"sFlag${expr.readableUniqueName.capitalize()}Is"
|
||||
}
|
||||
|
||||
@@ -238,22 +257,22 @@ fun Expr.isVariable() = this is IdentifierExpr && this.isDynamic()
|
||||
fun Expr.conditionalFlagName(output : Boolean, suffix : String) = "${dirtyFlagName}_${output}$suffix"
|
||||
|
||||
|
||||
val Expr.dirtyFlagSet by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.dirtyFlagSet by Delegates.lazy { expr : Expr ->
|
||||
val fs = FlagSet(expr.getInvalidFlags(), expr.getModel().getFlagBucketCount())
|
||||
expr.getModel().localizeFlag(fs, expr.dirtyFlagName)
|
||||
}
|
||||
|
||||
val Expr.invalidateFlagSet by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.invalidateFlagSet by Delegates.lazy { expr : Expr ->
|
||||
val fs = FlagSet(expr.getId())
|
||||
expr.getModel().localizeFlag(fs, expr.invalidateFlagName)
|
||||
}
|
||||
|
||||
val Expr.shouldReadFlagSet by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.shouldReadFlagSet by Delegates.lazy { expr : Expr ->
|
||||
val fs = FlagSet(expr.getShouldReadFlags(), expr.getModel().getFlagBucketCount())
|
||||
expr.getModel().localizeFlag(fs, expr.shouldReadFlagName)
|
||||
}
|
||||
|
||||
val Expr.conditionalFlags by Delegates.lazy { (expr : Expr) ->
|
||||
val Expr.conditionalFlags by Delegates.lazy { expr : Expr ->
|
||||
val model = expr.getModel()
|
||||
arrayListOf(model.localizeFlag(FlagSet(expr.getRequirementFlagIndex(false)),
|
||||
"${expr.conditionalFlagPrefix}False"),
|
||||
@@ -408,18 +427,23 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
|
||||
val index = indices.get(it)
|
||||
if (!it.isUsed()) {
|
||||
tab(", null")
|
||||
} else if (index == null) {
|
||||
tab(", (${it.getInterfaceType()}) root")
|
||||
} else if (it.isBinder()) {
|
||||
tab(", ${it.getViewClass()}.bind(views[${index}])")
|
||||
} else {
|
||||
tab(", (${it.getInterfaceType()}) views[${index}]")
|
||||
} else{
|
||||
val variableName : String
|
||||
if (index == null) {
|
||||
variableName = "root";
|
||||
} else {
|
||||
variableName = "views[${index}]"
|
||||
}
|
||||
tab(", ${it.superConversion(variableName)}")
|
||||
}
|
||||
}
|
||||
tab(");")
|
||||
}
|
||||
val taggedViews = layoutBinder.getBindingTargets().filter{it.isUsed() && !it.isBinder()}
|
||||
taggedViews.forEach {
|
||||
if (it.getResolvedType() != null && it.getResolvedType().extendsViewStub()) {
|
||||
tab("this.${it.fieldName}.setContainingBinding(this);")
|
||||
}
|
||||
if (it.getTag() == null) {
|
||||
if (it.getId() == null) {
|
||||
tab("this.${it.fieldName} = (${it.getViewClass()}) root;")
|
||||
@@ -584,7 +608,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
|
||||
|
||||
fun declareViews() = kcode("// views") {
|
||||
layoutBinder.getBindingTargets().filter {it.isUsed() && (it.getId() == null)}.forEach {
|
||||
nl("private final ${it.getInterfaceType()} ${it.fieldName};")
|
||||
nl("private final ${it.interfaceType} ${it.fieldName};")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +620,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
|
||||
|
||||
fun declareDirtyFlags() = kcode("// dirty flag") {
|
||||
model.ext.localizedFlags.forEach { flag ->
|
||||
flag.notEmpty { (suffix, value) ->
|
||||
flag.notEmpty { suffix, value ->
|
||||
nl("private")
|
||||
app(" ", if(flag.isDynamic()) null else "static final");
|
||||
app(" ", " ${flag.type} ${flag.getLocalName()}$suffix = $value;")
|
||||
@@ -682,6 +706,14 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
|
||||
includedBinders.filter{it.isUsed()}.forEach { binder ->
|
||||
tab("${binder.fieldName}.executePendingBindings();")
|
||||
}
|
||||
layoutBinder.getBindingTargets().filter{
|
||||
it.isUsed() && it.getResolvedType() != null && it.getResolvedType().extendsViewStub()
|
||||
}.forEach {
|
||||
tab("if (${it.fieldName}.getBinding() != null) {") {
|
||||
tab("${it.fieldName}.getBinding().executePendingBindings();")
|
||||
}
|
||||
tab("}")
|
||||
}
|
||||
}
|
||||
nl("}")
|
||||
}
|
||||
@@ -760,12 +792,12 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
|
||||
nl("import android.databinding.ViewDataBinding;")
|
||||
nl("public abstract class ${baseClassName} extends ViewDataBinding {")
|
||||
layoutBinder.getBindingTargets().filter{it.getId() != null}.forEach {
|
||||
tab("public final ${it.getInterfaceType()} ${it.fieldName};")
|
||||
tab("public final ${it.interfaceType} ${it.fieldName};")
|
||||
}
|
||||
nl("")
|
||||
tab("protected ${baseClassName}(android.view.View root_, int localFieldCount") {
|
||||
layoutBinder.getBindingTargets().filter{it.getId() != null}.forEach {
|
||||
tab(", ${it.getInterfaceType()} ${it.readableUniqueName}")
|
||||
tab(", ${it.interfaceType} ${it.readableUniqueName}")
|
||||
}
|
||||
}
|
||||
tab(") {") {
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ViewStubBindingAdapterTest
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mView = mBinder.view;
|
||||
mView = mBinder.view.getViewStub();
|
||||
}
|
||||
|
||||
public void testLayout() throws Throwable {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.databinding.testapp;
|
||||
|
||||
import android.databinding.testapp.generated.ViewStubBinding;
|
||||
import android.databinding.testapp.generated.ViewStubContentsBinding;
|
||||
import android.databinding.ViewStubProxy;
|
||||
import android.support.v4.util.ArrayMap;
|
||||
import android.test.UiThreadTest;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ViewStubTest extends BaseDataBinderTest<ViewStubBinding> {
|
||||
|
||||
public ViewStubTest() {
|
||||
super(ViewStubBinding.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mBinder.setViewStubVisibility(View.GONE);
|
||||
mBinder.setFirstName("Hello");
|
||||
mBinder.setLastName("World");
|
||||
try {
|
||||
runTestOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBinder.executePendingBindings();
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new Exception(t);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThreadTest
|
||||
public void testInflation() throws Throwable {
|
||||
ViewStubProxy viewStubProxy = mBinder.viewStub;
|
||||
assertFalse(viewStubProxy.isInflated());
|
||||
assertNull(viewStubProxy.getBinding());
|
||||
assertNotNull(viewStubProxy.getViewStub());
|
||||
assertNull(mBinder.getRoot().findViewById(R.id.firstNameContents));
|
||||
assertNull(mBinder.getRoot().findViewById(R.id.lastNameContents));
|
||||
mBinder.setViewStubVisibility(View.VISIBLE);
|
||||
mBinder.executePendingBindings();
|
||||
assertTrue(viewStubProxy.isInflated());
|
||||
assertNotNull(viewStubProxy.getBinding());
|
||||
assertNull(viewStubProxy.getViewStub());
|
||||
ViewStubContentsBinding contentsBinding = (ViewStubContentsBinding)
|
||||
viewStubProxy.getBinding();
|
||||
assertNotNull(contentsBinding.firstNameContents);
|
||||
assertNotNull(contentsBinding.lastNameContents);
|
||||
assertEquals("Hello", contentsBinding.firstNameContents.getText().toString());
|
||||
assertEquals("World", contentsBinding.lastNameContents.getText().toString());
|
||||
}
|
||||
|
||||
@UiThreadTest
|
||||
public void testChangeValues() throws Throwable {
|
||||
ViewStubProxy viewStubProxy = mBinder.viewStub;
|
||||
mBinder.setViewStubVisibility(View.VISIBLE);
|
||||
mBinder.executePendingBindings();
|
||||
ViewStubContentsBinding contentsBinding = (ViewStubContentsBinding)
|
||||
viewStubProxy.getBinding();
|
||||
assertEquals("Hello", contentsBinding.firstNameContents.getText().toString());
|
||||
mBinder.setFirstName("Goodbye");
|
||||
mBinder.executePendingBindings();
|
||||
assertEquals("Goodbye", contentsBinding.firstNameContents.getText().toString());
|
||||
}
|
||||
}
|
||||
@@ -26,4 +26,5 @@
|
||||
bind:innerObject="@{outerObject}"
|
||||
bind:innerValue="@{`modified ` + outerObject.intValue}"
|
||||
/>
|
||||
<include layout="@layout/plain_layout" android:id="@+id/plainLayout"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2015 The Android Open Source Project
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:bind="http://schemas.android.com/apk/res-auto">
|
||||
<variable name="viewStubVisibility" type="int"/>
|
||||
<variable name="firstName" type="String"/>
|
||||
<variable name="lastName" type="String"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{firstName}"
|
||||
android:id="@+id/firstName"
|
||||
/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{lastName}"
|
||||
android:id="@+id/lastName"
|
||||
/>
|
||||
|
||||
<ViewStub android:layout_width="match_parent" android:layout_height="match_parent"
|
||||
android:id="@+id/viewStub"
|
||||
android:visibility="@{viewStubVisibility}"
|
||||
android:layout="@layout/view_stub_contents"
|
||||
bind:firstName="@{firstName}"
|
||||
bind:lastName="@{lastName}"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<variable name="firstName" type="String"/>
|
||||
<variable name="lastName" type="String"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{firstName}"
|
||||
android:id="@+id/firstNameContents"/>
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:text="@{lastName}"
|
||||
android:id="@+id/lastNameContents"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.databinding;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewStub;
|
||||
import android.view.ViewStub.OnInflateListener;
|
||||
|
||||
/**
|
||||
* This class represents a ViewStub before and after inflation. Before inflation,
|
||||
* the ViewStub is accessible. After inflation, the ViewDataBinding is accessible
|
||||
* if the inflated View has bindings. If not, the root View will be accessible.
|
||||
*/
|
||||
public class ViewStubProxy {
|
||||
private ViewStub mViewStub;
|
||||
private ViewDataBinding mViewDataBinding;
|
||||
private View mRoot;
|
||||
private OnInflateListener mOnInflateListener;
|
||||
private ViewDataBinding mContainingBinding;
|
||||
|
||||
private OnInflateListener mProxyListener = new OnInflateListener() {
|
||||
@Override
|
||||
public void onInflate(ViewStub stub, View inflated) {
|
||||
mRoot = inflated;
|
||||
mViewDataBinding = DataBindingUtil.bindTo(inflated, stub.getLayoutResource());
|
||||
mViewStub = null;
|
||||
|
||||
if (mOnInflateListener != null) {
|
||||
mOnInflateListener.onInflate(stub, inflated);
|
||||
mOnInflateListener = null;
|
||||
}
|
||||
mContainingBinding.invalidateAll();
|
||||
mContainingBinding.executePendingBindings();
|
||||
}
|
||||
};
|
||||
|
||||
public ViewStubProxy(ViewStub viewStub) {
|
||||
mViewStub = viewStub;
|
||||
mViewStub.setOnInflateListener(mProxyListener);
|
||||
}
|
||||
|
||||
public void setContainingBinding(ViewDataBinding containingBinding) {
|
||||
mContainingBinding = containingBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the ViewStub has replaced itself with the inflated layout
|
||||
* or <code>false</code> if not.
|
||||
*/
|
||||
public boolean isInflated() {
|
||||
return mRoot != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The root View of the layout replacing the ViewStub once it has been inflated.
|
||||
* <code>null</code> is returned prior to inflation.
|
||||
*/
|
||||
public View getRoot() {
|
||||
return mRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The data binding associated with the inflated layout once it has been inflated.
|
||||
* <code>null</code> prior to inflation or if there is no binding associated with the layout.
|
||||
*/
|
||||
public ViewDataBinding getBinding() {
|
||||
return mViewDataBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ViewStub in the layout or <code>null</code> if the ViewStub has been inflated.
|
||||
*/
|
||||
public ViewStub getViewStub() {
|
||||
return mViewStub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link OnInflateListener} to be called when the ViewStub inflates. The proxy must
|
||||
* have an OnInflateListener, so <code>listener</code> will be called immediately after
|
||||
* the proxy's listener is called.
|
||||
*
|
||||
* @param listener The OnInflateListener to notify of successful inflation
|
||||
*/
|
||||
public void setOnInflateListener(OnInflateListener listener) {
|
||||
if (mViewStub != null) {
|
||||
mOnInflateListener = listener;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user