Android 数据绑定 layout_width 和 layout_height

Posted

技术标签:

【中文标题】Android 数据绑定 layout_width 和 layout_height【英文标题】:Android Data Binding layout_width and layout_height 【发布时间】:2016-05-19 14:52:00 【问题描述】:

我需要能够动态设置 EditText 的高度属性。我在整个应用程序中对其他属性使用数据绑定,因此我希望能够使用数据绑定来控制元素的高度。这是我的 xml 的精简版:

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

<data>
    <variable name="loginVM" type="com.testing.stuff.ViewModels.LoginViewModel" />
</data>

<EditText android:inputType="number"
            android:id="@+id/txtVerificationCode"
            android:layout_
            android:layout_
            android:paddingRight="16dp"
            android:paddingLeft="16dp"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:layout_marginLeft="10dp"
            android:alpha="@loginVM.verificationOpacity"
            android:layout_marginStart="10dp"
            android:textAlignment="center"
            android:visibility="visible"
            android:hint="Enter verificationCode"
            android:text="@loginVM.verificationCode" />
</layout> 

这是我的视图模型的精简版:

public class LoginViewModel extends BaseObservable 
public final ObservableField<String> verificationCode; 
public final ObservableField<Boolean> compact;

@Bindable
public String getVerificationCode() 
    if (this.verificationCode == null) 
        return "";
     else 
        return this.verificationCode.get();
    


public void setVerificationCode(String verificationCode) 
    this.verificationCode.set(verificationCode);
    invalidateProperties();


@Bindable
public Boolean getCompact()return this.compact.get();

public void setCompact(Boolean value)

    this.compact.set(value);
    this.invalidateProperties();


@BindingAdapter("android:layout_height")
public static void setLayoutHeight(EditText view, float height)

    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    layoutParams.height = (int)height;
    view.setLayoutParams(layoutParams);


public LoginViewModel(Context ctx) 
    verificationCode = new ObservableField();
    compact = new ObservableField();

尺寸在 dimens.xml 文件中。我正在修改视图模型中的属性。但是,当我启动应用程序时,我在启动后立即收到以下错误(绑定适配器未在调试时触发)。我在屏幕上还有其他几个元素,但这个特定的元素是我在发生特定操作时需要更改高度的元素:

FATAL EXCEPTION: main

Process: com.testing.stuff, PID: 32752

java.lang.RuntimeException: Unable to start activity  
ComponentInfocom.testing.stuff/com.testing.stuff.Login: 
java.lang.RuntimeException: Binary XML file line #69: You must supply 
a layout_height attribute.

Caused by: java.lang.RuntimeException: Binary XML file line #69: You 
must supply a layout_height attribute.

关于这个问题有一些关于 SO 的帖子,但没有明确的答案或方法不起作用。当然,这是一种常见的实现。提前感谢您的帮助。

【问题讨论】:

“这肯定是一种常见的实现”——考虑到数据绑定仍然是一个候选版本,我不会认为与数据绑定相关的任何东西都是“常见的” ”。如果您不能以这种方式设置高度和宽度,我不会感到惊讶,因为该数据会在布局膨胀后立即得到验证,到那时您还没有注入模型,更不用说设置这些属性了。可能有一些解决方法,使用您应用绑定表达式的合成属性(例如,app:width)来调整视图的LayoutParams 你可能是完全正确的。我猜是因为我熟悉其他平台(Windows)上的数据绑定,我只是希望它在 Android 上也很常见。 【参考方案1】:

在 Java 中

@BindingAdapter("layout_height")
public static void setLayoutHeight(View view, float height) 
    LayoutParams layoutParams = view.getLayoutParams();
    layoutParams.height = height;
    view.setLayoutParams(layoutParams);

在你的 XML 中

app:layout_

像这样导入应用程序

xmlns:app="http://schemas.android.com/apk/res-auto"

【讨论】:

我必须为它添加一个默认值才能工作 android:layout_ @Shubham 我不知道什么时候会使用默认值。 smallScreen 只有 2 种情况(真或假) @PhanVanLinh 对我来说它给出了错误 java.lang.RuntimeException: Binary XML file line #21: You must provide a layout_width attribute if I didn't add a default value 别忘了转换成 int layoutParams.height = height.toInt() @Shubham 您需要提供一个默认值。 app:layout_height="@ viewModel.isBig ? @dimen/dp_20 : @dimen/dp_5 , default=wrap_content"【参考方案2】:

当使用数据绑定时,我们会从 XML 中删除值。您可以添加一个在剥离时使用的默认值以避免该问题。

请参阅:http://developer.android.com/tools/data-binding/guide.html(页面底部)。

android:layout_

【讨论】:

它对我不起作用:Error:(13, 34) Cannot find the setter for attribute 'android:layout_width' with parameter type float on android.widget.LinearLayout. @GuilhermeTorresCastro 请在下面查看我的答案 我们要设置什么计算高度而不是从 xml?【参考方案3】:

根据Android问题跟踪器的讨论,如果不创建自定义绑定适配器,就无法使用数据绑定设置布局高度或宽度:

https://code.google.com/p/android/issues/detail?id=180666

设置视图高度所需的绑定适配器如下所示:

@BindingAdapter("android:layout_height")
public static void setLayoutHeight(View view, int height) 
    LayoutParams layoutParams = view.getLayoutParams();
    layoutParams.height = height;
    view.setLayoutParams(layoutParams);

【讨论】:

谢谢,它为我节省了数小时的搜索时间! 对我不起作用,我得到“你必须提供 layout_height 属性”【参考方案4】:

我用 Kotlin 而不是 Java 解决了这个问题。

制作一个名为

的文件
MyBindings.kt

然后输入:

@BindingAdapter("bind:customHeight")
fun setLayoutHeight(view: View, height: Float) 
    view.layoutParams = view.layoutParams.apply  this.height = height.toInt() 

然后你可以在你的布局中使用它:

<EditText 
android:id="@+id/internalTopDisplay"
android:layout_
bind:customHeight="@loginVM.compact ? @dimen/verificationHeightCompact : @dimen/verificationHeightFull"
android:layout_/>

【讨论】:

【参考方案5】:

对我来说,这是诀窍:

    @BindingAdapter("android:layout_height")
    public static void setLayoutHeight(View view, final Number height) 
        final ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        layoutParams.height =  height.intValue();
        view.setLayoutParams(layoutParams);
    

还有xml:

android:layout_

【讨论】:

【参考方案6】:

您可以为 android:layout_height 添加一个接受浮点数的绑定适配器。

对于身高

@BindingAdapter("android:layout_height")
    public static void setLayoutHeight(View view, float height) 
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        layoutParams.height = (int) height;
        view.setLayoutParams(layoutParams);
    

对于宽度:

@BindingAdapter("android:layout_width")
public static void setLayoutWidth(View view, float height) 
    ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
    layoutParams.width = (int) height;
    view.setLayoutParams(layoutParams);

用法

android:layout_

android:layout_

附言: 不要忘记设置默认值

【讨论】:

【参考方案7】:

这是一种简洁的、可扩展的机制,用于使用布尔值在两个 layout_heightlayout_width 状态之间切换。您需要将 LayoutWidthHeightBindingAdapterVariants 类导入布局,以在布局中指定其值之一:

@BindingAdapter(value = ["android:layout_height", "app:layout_widthHeightVariant"])
fun expandContractHeight(view: View, flag: Boolean, variant: LayoutWidthHeightBindingAdapterVariants) 
    val params = view.layoutParams
    params.height = if (flag) variant.valueWhenTrue else variant.valueWhenFalse
    view.layoutParams = params
    view.invalidate()


@BindingAdapter(value = ["android:layout_width", "app:layout_widthHeightVariant"])
fun expandContractWidth(view: View, flag: Boolean, variant: LayoutWidthHeightBindingAdapterVariants) 
    val params = view.layoutParams
    params.height = if (flag) variant.valueWhenTrue else variant.valueWhenFalse
    view.layoutParams = params
    view.invalidate()


enum class LayoutWidthHeightBindingAdapterVariants(val valueWhenFalse: Int, val valueWhenTrue: Int) 
    // format: <falseValue>_TO_<trueValue>
    WRAP_TO_MATCH(WRAP_CONTENT, MATCH_PARENT),
    MATCH_TO_WRAP(MATCH_PARENT, WRAP_CONTENT),
    WRAP_TO_ZERODP(WRAP_CONTENT, 0),
    ZERODP_TO_WRAP(0, WRAP_CONTENT)

【讨论】:

以上是关于Android 数据绑定 layout_width 和 layout_height的主要内容,如果未能解决你的问题,请参考以下文章

数据绑定设置颜色

绑定服务

绑定MvvmCross TextColor不适用于Android

怎样改变android:radiobutton的大小

Android双向绑定转换器@InverseMethod不起作用

Android中如何在布局文件中为组件绑定点击事件?