【问题标题】:Custom View - Move Views into nested Layout自定义视图 - 将视图移动到嵌套布局中
【发布时间】:2015-08-20 19:16:51
【问题描述】:

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

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

使用我的自定义视图的用户应该能够最好在 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,而不是将它们附加到自定义视图。

最好的方法是什么?

【问题讨论】:

  • “我很难解释我想做什么”。是的,您的问题有很多观点,但没有答案,因为它令人困惑和不清楚。解释更多。
  • @Sound Conception 我更新了我的问题:)
  • 啊哈!您不是指正常意义上的“用户”(就像使用您的应用程序的人一样)。您实际上是指另一个使用您的课程的软件开发人员,对吧?
  • 是的,自定义组件的用户(但可能只有我 :D)

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


【解决方案1】:

这个问题的本质是如何将子视图添加到GroupView,它本身就是自定义布局的子视图。

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

Androids LayoutInflater 在逻辑上解释 XML 文件中的嵌套级别,并在它创建的视图层次结构中构建相同的结构。
您的示例 XML 将 4 个 EditText 视图定义为 FrageContainerView 的第一层子视图,但您希望将它们创建为位于 LinearLayout 内的 FrageContainerView 的第二层子视图。这意味着要更改 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);

【讨论】:

    【解决方案2】:

    你可以做的另一件事是

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

    ArrayList&lt;View&gt; 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多