android - 自定义 View - 将 View 移动到嵌套布局中

标签 android android-layout android-custom-view

我想创建一个自定义 View ,它显示一张包含以下内容的卡片:

  • TextView(标题)
  • TextView(描述)
  • 线性布局(内部布局)

所以我只是扩展了一个 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 在我的自定义 View 中膨胀。我希望将示例中的 EditText 添加到 InnerLayout,而不是将它们附加到自定义 View 。

执行此操作的最佳方法是什么?

最佳答案

这个问题的本质是如何将 subview 添加到本身是自定义布局的 subview 的 GroupView 中。

这在编程上相对简单,但在 XML 中更像是一个问题。

Android LayoutInflater 逻辑解释 XML 文件中的嵌套级别,并在它创建的 View 层次结构中构建相同的结构。
您的示例 XML 将 4 个 EditText View 定义为 FrageContainerView 的第一层 subview ,但您希望将它们创建为位于内部的 FrageContainerView 的第二层 subview 你的 LinearLayout。这意味着要更改 Android 的 LayoutInflater,它是整个 Android 系统的核心组件。

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

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);
}

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

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

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

fragContainerView.addInnerView(newView);

关于android - 自定义 View - 将 View 移动到嵌套布局中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32126550/

相关文章:

android - 如何获得下面的效果

android - 固定位置的ImageView

android - Material Design 中的动画调整 View 大小

Android:自定义 View 组中不显示膨胀 View

android - 在 SDK 工具中启动 Android 模拟器,修订版 12

Android:视频停止播放时如何返回到之前的 Activity ?

android - 以编程方式更改 Android 的 "Make password visible"设置

android - HoneyComb 和 DefaultHttpClient

可绘制对象上的 Android 数据绑定(bind)

android - Android心电图