具有两个EditText视图的双向数据绑定

时间:2019-09-12 18:30:00

标签: android android-databinding two-way-binding

我无法制作两个“编辑文本”视图,这些视图在更改时会更新。要提供一些上下文,请参见下图:

Rotary Photo Settings Layout Image

还在运行的视图(显然不能嵌入它):

https://i.imgur.com/an6Kodx.mp4

在这里,我们添加目标(T1,T2,T3等),然后绘制一条弧线,用户可以设置摄像机的起点和终点(分别为灰色和红色图标。)然后,获得总移动值(以度为单位)。该值将确定电动机的旋转量(该应用基本上是一个控制器,供用户进行自动拍照)。

我想要实现的是,当用户输入照片编号时,正确的edittext将总移动度除以该计数并显示每张照片的角度,反之亦然。

但是,在展示各种示例(例如密码强度等)的所有在线内容中,我有点迷茫

我已经在gradle中包括了DataBinding。

我创建了一个自定义类(RotaryPhotoShoot),以具有三个主要参数(每次拍摄的角度,照片数量和总移动量)的模型。

我已将cosntraint布局移至布局根目录。

我已经创建了以下代码块中所示的数据。

RotaryPhotoShoow.java(我的模型)

package com.example.macrorecapp.models;

import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class RotaryPhotoShoot extends BaseObservable {

    private static final String TAG = "Rotary Photo Shoot";
    private float anglePerPhotos;
    private int numberOfPhotos;
    private int totalMoveDegrees;



    public RotaryPhotoShoot(float anglePerPhotos,int numberOfPhotos, int totalMoveDegrees) {
        this.anglePerPhotos = anglePerPhotos;
        this.numberOfPhotos = numberOfPhotos;
        this.totalMoveDegrees = totalMoveDegrees;
    }
    @Bindable
    public float getAnglePerPhotos() {
        return anglePerPhotos;
    }
    @Bindable
    public int getNumberOfPhotos() {
        return numberOfPhotos;
    }
    @Bindable
    public int getTotalMoveDegrees() {
        return totalMoveDegrees;
    }
    @Bindable
    public void setAnglePerPhotos(float anglePerPhotos) {
        this.anglePerPhotos = anglePerPhotos;
    }
    @Bindable
    public void setNumberOfPhotos(int numberOfPhotos) {
        this.numberOfPhotos = numberOfPhotos;
    }
    @Bindable
    public void setTotalMoveDegrees(int totalMoveDegrees) {
        this.totalMoveDegrees = totalMoveDegrees;
    }

}

activity_rotary_photo_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>
        <variable
            name="photoShoot"
            type="com.example.macrorecapp.models.RotaryPhotoShoot" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/appMainBackground"
        tools:context=".features.rotary.RotaryPhotoSettings">

...

        <com.example.macrorecapp.features.shared.views.RotaryView
            android:id="@+id/rotaryPhotoView"
            android:layout_width="360dp"
            android:layout_height="360dp"
            app:isClockwise="true"
            app:targetList="@array/targets"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/h_guideline1"
            app:layout_constraintBottom_toTopOf="@id/h_guideline2" />

        <EditText
            android:id="@+id/numberOfPhotosEdittext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{``+photoShoot.numberOfPhotos}"
            android:textAlignment="center"
            android:ems="4"
            android:textSize="15sp"
            android:textColor="#FFFFFFFF"
            app:layout_constraintBottom_toTopOf="@+id/numberOfPhotosSubtext"
            app:layout_constraintEnd_toStartOf="@id/v_guideline"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/numberOfPhotosBG"
            android:importantForAutofill="no"
            android:inputType="number" />

...


        <EditText
            android:id="@+id/anglePerPhotosEdittext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{``+photoShoot.anglePerPhotos+(char) 0x00B0}"
            android:textAlignment="center"
            android:ems="4"
            android:textSize="15sp"
            android:textColor="#FFFFFFFF"
            app:layout_constraintBottom_toTopOf="@+id/anglePerPhotosSubtext"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@id/v_guideline"
            app:layout_constraintTop_toTopOf="@+id/anglePerPhotosBG"
            android:importantForAutofill="no"
            android:inputType="numberDecimal" />


...

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

最后是RotaryPhotoSettings.java

package com.example.macrorecapp.features.rotary;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
//import com.example.macrorecapp.features.shared.views.RotaryView;
import com.example.macrorecapp.models.RotaryPhotoShoot;

public class RotaryPhotoSettings extends AppCompatActivity {

    private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
    //RotaryView mPhotoRotaryView;
    //private int mTotalMoveInDegrees;
    ActivityRotaryPhotoSettingsBinding mBinding;
    RotaryPhotoShoot mRotaryPhotoShoot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);

        mRotaryPhotoShoot  = new RotaryPhotoShoot(6.88f, 25, 178);
        mBinding.setPhotoShoot(mRotaryPhotoShoot);

        //mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
        //mPhotoRotaryView.addTarget(300);
        //mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();

    }

    public void goBack(View view) {
        view.startAnimation(buttonClick);
        finish();
    }

    public void openThreeSixtyPhotoRotary(View view) {
    }
}

目前,我没有任何错误,而且我可以确定以编程方式将其设置为活动状态时可以以一种方式更改视图。我觉得应该做的是,首先在xmls中使用@ = {}语法。然后,我可能需要自定义适配器或活页夹。我还看到人们使用ObservableInt等,这让我有点迷惑。我需要将我的getTotalMove函数设置为static,以便从RotaryView.java中获取它,但是从那时起,我无法继续前进。

我希望有一些指针可以做些什么。我认为我可以在实现自定义绑定器/适配器的地方轻松处理四舍五入的数字。我知道例如角度可能是十进制,而照片数量需要是整数。一旦完成编辑,我将对照片计数进行四舍五入并将角度本身更改为最接近的可能值。我还需要确定起点和终点是否将包括在间隔中。例如,对于100度,每次拍摄20度,就像这样:

0:S__S__S__S__S__S:100因此有6张照片等。

在实现任何侦听器等之前,我想我可以先在这里问一下,因为使用数据绑定库显然是要摆脱一堆侦听器,等等。我希望看到一些示例,其中两个EditText视图相互更改。

一旦我弄清楚了如何设置未经编辑的EditText,我将处理上面提到的其他注意事项,但是首先我需要完成两种方式的绑定部分。我想这种“双向”显然是在视图和视图模型之间,而不是直接在视图之间。所以我不知道是否可以在xml中使用@ = {``+ photoShoot.totalMove / photoShoot.anglePerPhoto}等技巧。

无论如何,我的道歉时间比预期的要长得多。 乍一看,这看起来很简单,但我越看越复杂。也许我只是在迷惑自己。

1 个答案:

答案 0 :(得分:0)

我想为自己的问题添加部分答案。我尝试调整自己的用例中来自以下链接的信息:

https://www.bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/

我设法通过以下更改来更改角度框(右侧一个):

  • 我在上面看到的自定义视图中删除了一些不必要的变量,并添加了一个公共的“ Total Move” getter。我在模型类RotaryPhotoShoot中使用它。

  • 我还在我的xml中添加了@ = {},因为您可以在下面看到更新的代码。结合notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos);可以更新角度框。

在添加另一面文字之前,我将添加代码的相关部分以供其他人参考。

RotaryPhotoSettings.java (利用绑定的活动类。)

package com.example.macrorecapp.features.rotary;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
import com.example.macrorecapp.models.RotaryPhotoShoot;

public class RotaryPhotoSettings extends AppCompatActivity {

    private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
    //RotaryView mPhotoRotaryView;
    //private int mTotalMoveInDegrees;
    ActivityRotaryPhotoSettingsBinding mBinding;
    RotaryPhotoShoot mRotaryPhotoShoot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);
        mRotaryPhotoShoot  = new RotaryPhotoShoot(6.88f, 25);
        mBinding.setPhotoShoot(mRotaryPhotoShoot);

        //mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
        //mPhotoRotaryView.addTarget(300);
        //mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();

    }

    public void goBack(View view) {
        view.startAnimation(buttonClick);
        finish();
    }

    public void openThreeSixtyPhotoRotary(View view) {
    }
}

我的模型类, RotaryPhotoShoot.java

package com.example.macrorecapp.models;

import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import com.example.macrorecapp.features.shared.views.RotaryView;

public class RotaryPhotoShoot extends BaseObservable {

    private static final String TAG = "Rotary Photo Shoot";
    private float anglePerPhotos;
    private int numberOfPhotos;


    public RotaryPhotoShoot(float anglePerPhotos, int numberOfPhotos) {
        this.anglePerPhotos = anglePerPhotos;
        this.numberOfPhotos = numberOfPhotos;
    }

    @Bindable
    public float getAnglePerPhotos() {
        return RotaryView.getTotalMoveInDegrees()/(float) numberOfPhotos;
    }

    @Bindable
    public int getNumberOfPhotos() {
        return numberOfPhotos;
    }

    @Bindable
    public void setAnglePerPhotos(float anglePerPhotos) {
        this.anglePerPhotos = RotaryView.getTotalMoveInDegrees()/numberOfPhotos;
    }

    @Bindable
    public void setNumberOfPhotos(int numberOfPhotos) {
        this.numberOfPhotos = numberOfPhotos;
        notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos);
        notifyPropertyChanged(com.example.macrorecapp.BR.anglePerPhotos);
    }

}

其中包含视图的活动布局文件, activity_rotary_photo_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>
        <variable
            name="photoShoot"
            type="com.example.macrorecapp.models.RotaryPhotoShoot" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/appMainBackground"
        tools:context=".features.rotary.RotaryPhotoSettings"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <com.example.macrorecapp.features.shared.views.RotaryView
            android:id="@+id/rotaryPhotoView"
            android:layout_width="360dp"
            android:layout_height="360dp"
            app:isClockwise="true"
            app:targetList="@array/targets"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/h_guideline1"
            app:layout_constraintBottom_toTopOf="@id/h_guideline2" />


        <EditText
            android:id="@+id/numberOfPhotosEdittext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@={``+photoShoot.numberOfPhotos}"
            android:textAlignment="center"
            android:ems="4"
            android:textSize="15sp"
            android:textColor="#FFFFFFFF"
            app:layout_constraintBottom_toTopOf="@+id/numberOfPhotosSubtext"
            app:layout_constraintEnd_toStartOf="@id/v_guideline"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/numberOfPhotosBG"
            android:importantForAutofill="no"
            android:inputType="number" />

        <EditText
            android:id="@+id/anglePerPhotosEdittext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{``+String.format(`%.2f`, photoShoot.anglePerPhotos)+(char) 0x00B0}"
            android:textAlignment="center"
            android:ems="4"
            android:textSize="15sp"
            android:textColor="#FFFFFFFF"
            app:layout_constraintBottom_toTopOf="@+id/anglePerPhotosSubtext"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@id/v_guideline"
            app:layout_constraintTop_toTopOf="@+id/anglePerPhotosBG"
            android:importantForAutofill="no"
            android:inputType="numberDecimal" />


    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

我可以使用一些标记的当前问题:

  • 我需要交叉更改,当前我不知道如何分辨是否通过键入来更改EditText。当更改来自其他框时,我将正确格式化/舍入该值并更新EditText视图。

  • 我可以使用一个布尔值,该值将根据更改是来自手动编辑还是以人工方式更改值而进行切换。这将帮助我防止无限循环。但是,正如我在上面说的,我不确定要实现该目标需要听什么。

  • 我想拥有的另一种行为是,当移动摄像机的起拍图标并更改TotalMove(以度为单位)时,我希望固定numberOfPhotos并仅更新anglePerPhotos。为此,我可能需要在RotaryView.java中添加绑定。如果这太过分了,我可以在RotaryPhotoShoot上添加一个触发器/侦听器。目前。更改相机位置后更改numberOfPhotos时,可以正确计算角度。

  • 我有一个小错误(?),我无法删除numberOfPhotos字段的最后一位。请参见下面的以下webm视频:

https://gfycat.com/distortedyoungdairycow

我意识到的一件事是,仅模型类中的getter和setter即可实现我需要做的事情。确实,这消除了麻烦来监听器和自定义适配器。由于我交替使用两个EditText,因此最终可能仍会使用它们。

请注意,您可以使用任何内置的Java函数(请参阅我在anglePerPhotos字段中使用的字符串格式)。如有必要,我知道如何在<data></data>块中导入类。

在完成此更新回答之前,我将再添加一个链接,以帮助那些可能会丢失如何首次在其项目中设置数据绑定的人

https://www.youtube.com/watch?v=v4XO_y3RErI