自定义视图 - 将视图移动到嵌套布局

时间:2015-08-20 19:16:52

标签: android android-layout android-custom-view

我想创建一个自定义视图,该视图显示一张带有以下内容的卡片:

  • TextView(标题)
  • TextView(说明)
  • LinearLayout(innerLayout)

所以我只是扩展了一个LinearLayout并用它夸大了我的布局文件:

public class FrageContainerView extends LinearLayout {
    private TextView objTextViewCaption;
    private TextView objTextViewDescription;

    private String caption;
    private String description;

    private LinearLayout objLayoutInner;

    public FrageContainerView(Context context) {
        this(context, null);
    }

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

        initialize(context, attrs);
    }

    public FrageContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initialize(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public FrageContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        initialize(context, attrs);
    }

    private void initialize(Context context, AttributeSet attrs) {
        TypedArray a =
                context.obtainStyledAttributes(attrs, R.styleable.options_frageContainerView, 0, 0);

        caption = a.getString(R.styleable.options_frageContainerView_caption);
        description = a.getString(R.styleable.options_frageContainerView_description);

        a.recycle();

        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER_VERTICAL);

        LayoutInflater inflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.view_fragecontainer, this, true);

        objLayoutInner = (LinearLayout) findViewById(R.id.linearlayout_inner);
        objTextViewCaption = (TextView) findViewById(R.id.textview_caption);
        objTextViewDescription = (TextView) findViewById(R.id.textview_description);

        objTextViewCaption.setText(caption);
        objTextViewDescription.setText(description);
    }

使用我的自定义View的用户应该能够在XML中添加自己的组件,如下所示:

    <FrageContainerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        custom:caption="Hallo"
        custom:description="LOLOLOL"
        android:background="#FF00FF00">
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="sdsdfsdf"/>
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="sdsdfsdf"/>
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="sdsdfsdf"/>
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="sdsdfsdf"/>

    </FrageContainerView>

当前状态是,定义的EditText在我的自定义视图中膨胀。我希望将我的示例中的EditTexts添加到InnerLayout,而不是将它们附加到自定义视图。

这样做的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

此问题的实质是如何将子视图添加到GroupView,而LayoutInflater本身就是自定义布局的子项。

这在编程方面相对简单,但更多的是XML问题。

Androids EditText在逻辑上解释XML文件中的嵌套级别,并在它创建的视图层次结构中构建相同的结构。
您的示例XML将4 FrageContainerView个视图定义为FrageContainerView的第一层子视图,但您希望将它们创建为位于LinearLayout内的LayoutInflater的第二层子视图。这将意味着改变Androids public class FrageContainerView extends LinearLayout { private TextView objTextViewCaption; private TextView objTextViewDescription; private String caption; private String description; private LinearLayout objLayoutInner; public FrageContainerView(Context context) { this(context, null); } public FrageContainerView(Context context, AttributeSet attrs) { super(context, attrs); initialize(context, attrs); } public FrageContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initialize(context, attrs); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public FrageContainerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initialize(context, attrs); } private void initialize(Context context, AttributeSet attrs) { // Create your 3 predefined first tier children // Create the Caption View objTextViewCaption = new TextView(context); // You can add your new Views to this LinearLayout this.addView(objTextViewCaption) // Create the Description View objTextViewDescription = new TextView(context); // You can also provide LayoutParams when you add any of your new Views if you want to LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); this.addView(objTextViewDescription, params); // Create your inner LinearLayout objLayoutInner = new LinearLayout(context); objLayoutInner.setOrientation(VERTICAL); // Add it this.addView(objLayoutInner); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.options_frageContainerView, 0, 0); caption = a.getString(R.styleable.options_frageContainerView_caption); description = a.getString(R.styleable.options_frageContainerView_description); a.recycle(); setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.CENTER_VERTICAL); /** * Oops! Only just spotted you're inflating your three predefined views * here. It's fine to do this instead of programmatically adding them as I * have above. Obviously they should only be added once, so I've commented out * your version for the moment. **/ // LayoutInflater inflater = // (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // inflater.inflate(R.layout.view_fragecontainer, this, true); // // objLayoutInner = (LinearLayout) findViewById(R.id.linearlayout_inner); // objTextViewCaption = (TextView) findViewById(R.id.textview_caption); // objTextViewDescription = (TextView) findViewById(R.id.textview_description); objTextViewCaption.setText(caption); objTextViewDescription.setText(description); } } /** Public method for adding new views to the inner LinearLayout **/ public void addInnerView(View view) { objLayoutInner.addView(view); } /** Public method for adding new views to the inner LinearLayout with LayoutParams **/ public void addInnerView(View view, LayoutParams params) { objLayoutInner.addView(view, params); } ,它是整个Android系统的核心组件。

要以编程方式执行此操作,您可以执行以下操作:

FrageContainerView fragContainerView = (FrageContainerView) findViewById(R.id.my_frag_container_view);

TextView newView = new TextView(context);
newView.setText("whatever");

fragContainerView.addInnerView(newView);

您可以在代码中使用此代码,如下所示:

Option Explicit

答案 1 :(得分:0)

您可以做的另一件事是

1)缓存所有当前子级并将其全部删除

ArrayList<View> nestedViews = ViewUtil.getAllChildren(this); removeAllViews();

2)膨胀已经包含内容的布局

View myLayout = LayoutInflater.from(getContext()).inflate(R.layout.my_layout_with_stuff, null);

3)将缓存的视图添加到新增加的布局中,并将其添加到根目录背面

    for (View view : nestedViews) {
        myLayout.<ViewGroup>findViewById(R.id.contentLayout).addView(view);
    }

    addView(myLayout);