如何在编程生成的ConstraintLayout后代中使用ConstraintSet?

时间:2018-02-26 20:42:38

标签: android android-layout android-layoutparams

我有一个继承自ConstraintLayout的观点。在这个布局中,我使用ConstraintSet放置子项。

只要在构造函数外使用给定的AttributeSet表单,它就可以工作:

public AnswerView(Context context, AttributeSet attrs) {
    super(context, attrs);

如果我在没有attrs可用时尝试分配布局,则无效。

public AnswerView(Context context) {
    super(context);
    setLayoutParams(new LayoutParams(
                             ViewGroup.LayoutParams.MATCH_PARENT,
                             ViewGroup.LayoutParams.MATCH_PARENT));

在第一种情况下,子项得到一个漂亮的分布,就像ConstraintSet定义的那样,在第二种情况下,所有的行都在左边界处。

在这两种情况下,布局都会拉伸全宽,我可以通过设置背景颜色来证明。

我的代码中缺少什么?

1 个答案:

答案 0 :(得分:0)

这不是问题的直接答案。直接答案仍然缺失。这个答案的类型是“采取更好的方法!”。

当问题很少或没有答案时,我通常会走上一条轨道,很少有人去。然后有理由说他们没有。

我在其他视图中以编程方式嵌套视图的方法很酷,但事实证明如果不使用布局就很难做到这一点。 以编程方式设置配置的所有好处太昂贵了,这可以在布局中轻松完成。 Android的API没有为此做好充分的准备。

所以我转回到方法,基于布局创建视图类。这意味着,我使用布局的两个参数构造函数创建视图。

在封闭视图类中,我无法再直接创建嵌套视图,因为没有构造函数。相反,我从布局中读取配置的视图。

我创建了一个小类来帮助提取布局的已配置子部分:

public class Cloner {

    LayoutInflater inflater;
    int layoutId;

    public Cloner of(Context context) {
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        return this;
    }

    public Cloner from(@LayoutRes Integer layoutId) {
        this.layoutId = layoutId;
        return this;
    }

    public View clone(@IdRes int id) {
        assert inflater != null;
        View layout = inflater.inflate(layoutId, null);
        View view = layout.findViewById(id);
        ((ViewManager) view.getParent()).removeView(view);
        return view;
    }
}

它的用法如下:

MultipleChoiceAnswerView mcav = 
   (MultipleChoiceAnswerView) new Cloner().of(getContext())
       .from(layoutId).clone(R.id.multipleChoiceAnswerView);
mcav.plugModel(challenge.getAnswer());

这已经显示了我如何在第二步中连接模型,因为我无法再通过构造函数将其输入。

在构造函数中,我首先评估给定的属性。然后我通过膨胀附带的第二个布局文件来设置视图,我没有在这里显示。因此,涉及两个布局,一个用于配置构造函数的输入,一个用于内部布局。

当对plugModel的调用发生时,膨胀的内部布局由与给定模型匹配的对象使用和扩展。我再次以编程方式创建此对象,但是从第三个(或第二个)布局文件中将它们作为模板读取。再次在上面给出的Cloner的帮助下完成。

private Button getButton(final Integer index, String choice) {
    Button button = (Button) new Cloner().of(getContext()).from(layoutId).clone(R.id.button);
    button.setId(generateViewId());
    button.setText(choice);
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            answer.choiceByIndex(index);
        }
    });
    return button;
}

在实践中,我将此对象模板(如按钮)作为子项放入第二个布局文件中。所以我可以在Android Studio Designer中整体设计它。

以编程方式我在实际用克隆对象填充布局之前删除模板。通过这种方法,我只需要为每个视图类维护一个布局文件。 (构造函数的配置发生在封闭视图的布局文件中。)