膨胀到"这个"?

时间:2014-03-20 04:00:40

标签: android xml android-inflate

我一直在创建没有太多XML的应用程序,以编程方式创建视图。我想切换到XML。所以我为RelativeLayout编写了一个XML文件,我需要将它扩展到一个现有的类(当然是RelativeLayout的子类),它具有所有的实现逻辑。

如何在构造函数中膨胀为“this”?

顺便说一下,XML的优势究竟是什么?当我在代码中创建视图时,我会缩放字体和图像,并根据屏幕的大小,方向,宽高比等移动视图。使用XML方法,我必须为所有可能的配置创建单独的XML。

构造函数代码:

  public OrderEditControl()
  {
    super(LmcActivity.W.getApplicationContext());
    Resources res = LmcActivity.W.getResources();
    setBackgroundColor(Color.TRANSPARENT);
    headers = res.getStringArray(R.array.item_list_columns);
    widths = new int[headers.length];

    createLabels();
    createButtons();

    LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
    lp.addRule(ALIGN_PARENT_TOP);
    lp.addRule(RIGHT_OF, labels[LabelType.CUSTOMER.ordinal()].getId());
    lp.addRule(LEFT_OF, buttons[ButtonType.FIND_CUSTOMER.ordinal()].getId());

    customerView = new TextView(LmcActivity.W.getApplicationContext());
    customerView.setTextColor(Color.BLACK);
    customerView.setId(400);
    customerView.setTypeface(Typeface.DEFAULT_BOLD);
    customerView.setGravity(Gravity.CENTER_VERTICAL);
    addView(customerView, lp);

    lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    lp.addRule(ALIGN_TOP, labels[LabelType.SHIP_TYPE.ordinal()].getId());
    lp.addRule(ALIGN_BOTTOM, labels[LabelType.SHIP_TYPE.ordinal()].getId());
    lp.addRule(RIGHT_OF, labels[LabelType.SHIP_TYPE.ordinal()].getId());

    shipSpinner = new Spinner(LmcActivity.W);
    shipSpinner.setId(401);
    shipSpinner.setAdapter(shipAdapter);
    shipSpinner.setOnItemSelectedListener(this);
    addView(shipSpinner, lp);

    deliveryView = new EditText(LmcActivity.W.getApplicationContext());
    deliveryView.setGravity(Gravity.CENTER_VERTICAL);
    deliveryView.setSingleLine();
    deliveryView.setId(402);
    addView(deliveryView);

    lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
    lp.addRule(RIGHT_OF, labels[LabelType.COMMENTS.ordinal()].getId());
    lp.addRule(LEFT_OF, buttons[ButtonType.ITEMS.ordinal()].getId());
    lp.addRule(ALIGN_TOP, labels[LabelType.COMMENTS.ordinal()].getId());

    commentView = new EditText(LmcActivity.W.getApplicationContext());
    commentView.setGravity(Gravity.TOP);
    commentView.setId(403);
    addView(commentView, lp);

    lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
    lp.addRule(BELOW, commentView.getId());
    itemList = new ListView(LmcActivity.W.getApplicationContext());
    itemList.addHeaderView(createRow(null, null), null, false);
    itemList.setOnItemClickListener(this);
    itemList.setAdapter(itemAdapter);
    itemList.setCacheColorHint(0);
    itemList.setBackgroundColor(Color.TRANSPARENT);
    itemList.setId(404);
    addView(itemList, lp);

    lays[0] = new LayParm(false);
    lays[1] = new LayParm(true);
  }

  /** create the view's buttons */
  private void createButtons()
  {
    for (int i = 0; i < N_BUT; ++i)
    {
      Button but = i == ButtonType.ITEMS.ordinal() ?
          new TextGlassButton(2.4f, LmcActivity.W.getResources().getString(R.string.items), Color.WHITE) :
          new EffGlassButton(1.2f, butEffects[i]);
      but.setId(BUT_ID + i);
      but.setOnClickListener(this);
      buttons[i] = but;

      if (i == ButtonType.DATE.ordinal())
        addView(but);
      else
      {
        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        if (i < 2)
          lp.addRule(ALIGN_PARENT_TOP);
        else
          lp.addRule(BELOW, BUT_ID + i - 2);

        if (i % 2 == 0)
          lp.addRule(ALIGN_PARENT_RIGHT);
        else
          lp.addRule(LEFT_OF, BUT_ID + i - 1);

        addView(but, lp);
      }
    }
  }

  /** create text labels */
  private void createLabels()
  {
    Paint paint = AFDraw.W.textPaint;
    paint.setTextSize(Universe.TEXT_SIZE);
    paint.setTypeface(LmcActivity.W.defaultTypeface);

    String[] titles = LmcActivity.W.getResources().getStringArray(R.array.order_labels);

    for (int i = 0; i < titles.length; ++i)
    {
      LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
      lp.addRule(ALIGN_PARENT_LEFT);

      if (i == 0)
        lp.addRule(ALIGN_PARENT_TOP);
      else
        lp.addRule(BELOW, LABEL_ID + i - 1);

      TextView tv = new TextView(LmcActivity.W.getApplicationContext());
      tv.setText(titles[i]);
      tv.setTextColor(Color.BLACK);
      tv.setId(LABEL_ID + i);
      tv.setTypeface(LmcActivity.W.defaultTypeface);
      tv.setGravity(Gravity.CENTER_VERTICAL);
      labels[i] = tv;
      addView(tv, lp);

      labelWidth = Math.max(labelWidth, paint.measureText(titles[i]));
    }

    labelWidth += Universe.TEXT_SIZE * 0.5f;
    dateWidth = paint.measureText("00/00/00") + Universe.TEXT_SIZE * 1.5f;
  }

2 个答案:

答案 0 :(得分:1)

首先,回答您的主要问题:

您不希望将XML RelativeLayout扩展到RelativeLayout类中。您将扩展RelativeLayout,然后在XML文件中声明RelativeLayout的实例,如下所示:

// com.foo.MyRelativeLayout.java
public class MyRelativeLayout extends RelativeLayout{
    /**
     * Implement MyRelativeLayout
     */
}

和...

// layout_example.xml
<?xml version="1.0" encoding="utf-8"?>
<com.foo.MyRelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- Put More Views in here... -->
    <TextView
       android:id="@+id/customer_textview"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="@string/customer_name_placeholder" />
    <!-- and on... -->

</com.foo.MyRelativeLayout>

但更重要的是,如果您使用XML来布局文件,那么您的MyRelativeLayout文件中不需要任何那些实例化或.addRule()方法调用,因为你已经用XML声明性地完成了它。

回答第二个问题“你为什么还要使用XML?”

原因很多。也许这些适用于你,也许他们没有,但他们是我能够相当容易想到的与我的工作相关的那些。

  • 您实际上不必为每个单独的屏幕大小或用例创建新的布局文件。在大多数情况下,单个布局文件就足以满足大多数屏幕的要求。您可能会发现您将拥有特定尺寸/分辨率/方向的dimens.xml或style.xml文件,但除非您希望针对不同的可能性进行截然不同的安排,否则布局本身不会经常重复。

  • 您可以使用可视化编辑器。如果您在团队中工作,并且您的团队成员不喜欢或只想使用Java来布局他们的屏幕,这一点非常重要。虽然我和其他人很乐意创建视图和布局子类以满足我们的需求,但我知道字面上 nobody 更喜欢使用Java作为主要布局语言。找到将与您合作的人(或其他人使用XML工具的工作)可能具有挑战性。

  • 如果您正在为其他人创建工具(比如上面提到的喜欢XML的人),您实际上可以为他们提供自定义属性,这使得定位和布局更加强大。这些属性可以在XML中进行硬编码,也可以是对任何其他Android资源的引用(drawable / string / color / integer / boolean / etc ...)。作为一个人为的例子,但是基于你的代码,你可以让你的用户指定一些按钮来创建,而不是依赖于N_BUT变量。您可以为其指定一个默认值,但为用户提供了一种在XML中更改它的方法。

以下是一个例子:

 // somelayout.xml
 <?xml version="1.0" encoding="utf-8"?>

 <com.foo.MyRelativeLayout
     xmlns:param="http://schemas.android.com/apk/res-auto"
     style="@style/MyRelativeLayoutStyle"
     param:numberOfButtons="3">

 </com.foo.MyRelativeLayout>

并在另一个文件中......

//attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyRelativeLayout">    
        <attr name="numberOfButtons" format="reference|integer" />
    </declare-styleable>
</resources>

在MyRelativeLayout中,您可以从构造函数中的AttributeSet访问这些属性(当Android使用XML创建布局时,由Android调用)。

  • 使用style =“@ style / foo”语法可以创建可以应用于各种视图的样式“类”,而无需实际创建View子类。假设您知道您总是希望有一组参数对所有Button元素都适用,但不想将Button子类化。

例如:

// styles.xml
 <style name="BaseButton">
     <item name="android:layout_width">match_parent</item>
     <item name="android:layout_height">wrap_content</item>
     <item name="android:focusable">true</item>
     <item name="android:clickable">true</item>
     <item name="android:background">@drawable/bg_common_button</item>
     <item name="android:textColor">@color/white</item>
     <item name="android:textSize">@dimens/base_button_text_size</item>
 <!--  ^^ that dimen value could vary from screen size to screen size, but the style likely won't -->
 </style>

// button_layout.xml
 <Button
   android:id="@+id/styled_button"
   style="@style/BaseButton" /> <!-- and you're done -->

// some_other_layout.xml
 <LinearLayout
   style="@style/BaseLinearLayout">

   <Button style="@style/BaseButton" android:text="Button1" />
   <Button style="@style/BaseButton" android:text="Button2" />
   <Button style="@style/BaseButton" android:text="Button3" />

 </LinearLayout>

如果您想使用代码实例化该按钮,那么您可以使用LayoutInflater来扩充该特定按钮的布局,并在任何您想要的地方使用它。实际上,您可以在XML中创建所有方式的组件,然后在运行时对它们进行充气。

LayoutInflater inflater = LayoutInflater.from(YourActivity.this); 
Button theInflatedButton = inflater.inflate(R.layout.button_layout.xml, null); 

当然,规范示例是ListViews以及您希望填充它们的项目。您将创建一个listview项布局xml,然后在适配器需要新的convertView实例时对其进行充气。

答案 1 :(得分:1)

@scriptocalypse通常是正确的,但是对一些布局进行子类化并将自定义布局扩展到此类有助于分离不同的抽象。有很多糟糕的教程,其中一切都在Activity中完成。我看到世界上新的程序员只会编写看起来很糟糕的应用程序。

使用自定义布局,您只能在Activity中执行以下操作:

medicineView.putMedicine(medicineList);

而不是所有糟糕的适配器创作并寻找视图......

首先您应该为自定义视图创建一些视图:

<RelativeLayout ...>
    <!-- You put all your views here -->
</RelativeLayout>

其次如果您对自己的观点满意,则应将根目录更改为 merge 标记:

<merge ...>
    <!-- You put all your views here -->
</merge>

这非常重要。我们开始使用RelativeLayout标签进行设计,以便IDE了解如何绘制布局以及如何进行完成。但是如果我们保持原样,我们最终将会出现两个嵌套的RelativeLayouts,它最终会是这样的:

<RelativeLayout ...>    <!-- That is your class -->
    <RelativeLayout ...> <!-- This is inflated from layout -->  
        <!-- You put all your views here -->
    </RelativeLayout>
</RelativeLayout>

如果您将布局更改为&#34;合并&#34;然后它会是这样的:

<RelativeLayout ...>    <!-- That is your class -->
    <merge...> <!-- This is inflated from layout -->  
        <!-- You put all your views here -->
    </merge>
</RelativeLayout>

并将合并到其根目录:

<RelativeLayout ...>    <!-- That is your class, merged with layout -->
    <!-- You put all your views here -->
</RelativeLayout>

最后,您必须子类化所需的View或ViewGroup:

public class CustomView extends RelativeLayout {
    public CustomView(Context context) {
        super(context);
        initialize();
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public CustomView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initialize();
    }

    private void initialize() {
        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.id.your_layout, this, true);

        // find your views, set handlers etc.
    }
}

<强>用法

就像@scriptocalypse已经说过的那样。在另一种布局中,你可以这样使用:

<SomeLayout>
    <com.foo.CustomView>
</SomeLayout>