【问题标题】:Suggestion to create Android layout dynamically from database从数据库动态创建 Android 布局的建议
【发布时间】:2018-03-27 00:51:16
【问题描述】:

假设我有这样的布局:

创建布局并不复杂,如果问题已解决。但我的要求是显示数据库中的问题,如下所示:

如您所见,有 4 个 sectionId。这意味着我们有 4 个类别。我正在考虑为此使用 LinearLayout。然后对于每个类别,我们有不同数量的问题。如果问题类型是 R,请使用 RatingBar。但如果类型是 D,则使用 TextArea。我还计划对每个问题使用 LinearLayout。现在的挑战是动态创建这些布局,我认为这并不容易。最简单的方法是什么?

【问题讨论】:

  • 将 ReyclerView 与多个视图一起使用,只需实现 getItemViewType()
  • 我不会支持recyclerview的推荐,因为那会给你一个列表,而不是一个表格

标签: android android-layout


【解决方案1】:

我不得不在几次机会中这样做,所以我希望我能提供一个或更多的提示:

如果您的问题不复杂,请寻找已经解决的问题:

这个library 创建一个基于 Firebase 数据的布局 这个library 用于创建表单

大多数情况下,任何库都可以工作,因为程序化视图严格满足特定要求,因此您必须自己动手。

定制解决方案

创建程序化视图有一个倾斜的学习曲线,但随着时间的推移,您将能够解决它。

定义你的字段:

创建字段或部分包并将这些类放入其中。您想为每种类型的字段创建一个类,以便您可以轻松地重用和修改它是在该类中完成的。 此外,定义每个领域的共同点。您可以使用界面来执行此操作:

interface FormField {

   String result();
   boolean isValid();
   void setError();

}

在这种情况下,该接口将允许您处理字段的结果,知道它是否有效并设置错误。一旦被请求,验证应该是内部的,并且错误应该可以在内部验证和外部验证中设置。

您获得的结果可以通过其他类中的特定方法进行更改,但在大多数情况下,即使对于向用户显示摘要,使用通用字符串也是有用的。

还有一个好处,你可以通过你的接口创建一个字段列表,每个字段都实现它:

List<FormFields> fields = new ArrayList();
//fields.add(ANY CLASS THAT IMPLEMENTS THE INTERFACE);

创建字段

首先创建一个为您的领域扩展合适视图的类:

public class InputText extends EditText implements FormFiel {
      //You can simply add customizations in the constructor
}

public class InputText extends LinearLayout implements FormField {

    //Maybe you need an input with a label, hence a TextView and an EditText will go inside of this

}

这个关于构造函数的任务的经验法则是一个参数用于java,两个参数用于xml。因此,无论您需要在哪里放置视图,都可以使用其中之一。

处理字段外观

如果您需要一些简单的东西,也许只需在构造函数中设置所有内容。

public class InputText extends EditText implements FormField {
          //You can simply add customizations in the constructor

    public InputText(Context context) {
         super(context)
         setLayoutParams(new LayoutParams(LayoutParams.WrapContent...)
    }

}

如果您需要更复杂的东西,请使用布局充气器。

public class InputText extends LinearLayout implements FormField {
          //You can simply add customizations in the constructor

    public InputText(Context context) {
         super(context)
         LayoutInflater layoutInflater = LayoutInflater.from(getContext())
         //You have to create the layout, a neat trick is create it inside a linear layout eand then use refactor/extract
         //The last boolean in the method attach it to the view
         layoutInflater.inflate(R.layout.field_input_text, this, true;)
         //Maybe you want to find something, this could be a field variable
         TexteView tv = this.findViewbyId(R.id.inside_the_inflated_layout)
    }

}

定义模型

您需要为所有字段类型定义一个模型

public class FireField {

    private String label, hint, type;
    // Empty constructor and getters and setters

}

创建一个容器类

容器类可能是一个具有垂直方向的线性布局,无论如何你都想创建它并添加到 xml 中(记住 2 参数构造函数),因此你可以在该视图中添加一种获取所有字段的方法,一种特殊方法为了那个原因。 它可以是字段列表,也可以是您需要发送的数据列表。 这样,字段负责自己的逻辑,形式负责一般逻辑。

添加视图

你必须获取你的数据然后做一个循环,并为每种类型的数据添加一个新的视图,这时 List&lt;FormField&gt; 的视图就派上用场了,下面是伪代码

List<FireField> data = new ArrayList();
//You can also have String, View map here, where the key is the type and the value View is your field
List<FormField> fields = new ArrayList();


for (DataSnapshot children: snapshot.getChildren()) {
    FireField field = children.getValue(FireField.class);
    data.add(field);
    if (field.getType.equals("INPUT_TEXT)) {
        //Here Im addinf the field in the constructor, then the view should take care of it
        new InputText(context, field)
        //Here I'm initializing the view, the view inside that method should set labels and other
       InputText input = new InputText(this);
      input.initialize(field);
       fields.add(input);
        //You can add it here or in other place re using some of the lists above
        container.addView(input);
    }
}

最后使用任何列表和容器方法来获取数据并将其发送到 Firebase

【讨论】:

    猜你喜欢
    • 2012-01-11
    • 1970-01-01
    • 2014-06-26
    • 2021-04-10
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    相关资源
    最近更新 更多