一般產生 Layout 的作法大多數是使用 xml 來達成,但在一些特殊情況下必須在 java code 建立 Layout。
本篇紀錄如何在 java code 中產生 Layout。
首先貼上示意圖
device-2015-07-16-131853
可以看到示意圖中主要有4個區塊,黑,藍,紅,綠,其中黑跟綠的width都佔滿屏,藍和紅的width佔滿屏的0.5。
而Height部份,黑佔0.2,其他區塊佔0.4。
以下為source code,
第18行的藉由 Display 來計算螢幕的 width 和 height 。
第38行為了在各元件中手動設定id,提供了generateID()方法,內容參考View.generateID()。
第52行createLayout()方法提供給Activity設定Layout。
第67,84,103,121行的initxxx方法,則是各個區塊的初始化內容。

import java.util.concurrent.atomic.AtomicInteger;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class ViewCreater
{
    private static final String TAG = "ViewCreater";
    private static int mId = 0;
    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
    private Context mContext;
    private Display mDisplay;
    private RelativeLayout upLayout;
    private RelativeLayout mMiddleLeftLayout;
    private RelativeLayout mMiddleRightLayout;
    private RelativeLayout mDownLayout;
    public ViewCreater(Context context) {
        mContext = context;
        initDisplay();
    }
    private void initDisplay()
    {
        WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        mDisplay = manager.getDefaultDisplay();
    }
    public static int generateId()
    {
        if (Build.VERSION.SDK_INT < 17) {
            for (;;) {
                final int result = sNextGeneratedId.get();
                int newValue = result + 1;
                if (newValue > 0x00FFFFFF)
                    newValue = 1;
                if (sNextGeneratedId.compareAndSet(result, newValue)) {
                    return result;
                }
            }
        } else {
            return View.generateViewId();
        }
    }
    public RelativeLayout createLayout()
    {
        RelativeLayout rootlayout = new RelativeLayout(mContext);
        rootlayout.setId(generateId());
        initUpLayout();
        initMiddleLeftLayout();
        initMiddleRightLayout();
        initDownLayout();
        rootlayout.addView(mDownLayout);
        rootlayout.addView(mMiddleLeftLayout);
        rootlayout.addView(upLayout);
        rootlayout.addView(mMiddleRightLayout);
        return rootlayout;
    }
    private void initUpLayout()
    {
        upLayout = new RelativeLayout(mContext);
        upLayout.setId(generateId());
        upLayout.setTag("upLayout");
        RelativeLayout.LayoutParams layoutParamsOfUp = new RelativeLayout.LayoutParams(
                mDisplay.getWidth() / 1, mDisplay.getHeight() / 5);
        layoutParamsOfUp.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
        upLayout.setLayoutParams(layoutParamsOfUp);
        TextView textViewOfUplayout = new TextView(mContext);
        textViewOfUplayout.setId(generateId());
        textViewOfUplayout.setText("upLayout");
        textViewOfUplayout.setTextSize(20);
        upLayout.addView(textViewOfUplayout);
        upLayout.setBackgroundColor(Color.BLACK);
    }
    private void initMiddleRightLayout()
    {
        mMiddleRightLayout = new RelativeLayout(mContext);
        mMiddleRightLayout.setId(generateId());
        RelativeLayout.LayoutParams layoutParamsOfMiddleRightLayout = new RelativeLayout.LayoutParams(
                mDisplay.getWidth() / 2, mDisplay.getHeight() * 2 / 5);
        TextView textViewOfMiddleRightLayout = new TextView(mContext);
        textViewOfMiddleRightLayout.setId(generateId());
        textViewOfMiddleRightLayout.setText("middleRightLayout");
        textViewOfMiddleRightLayout.setTextSize(20);
        textViewOfMiddleRightLayout.setTextColor(Color.parseColor("#ffff00"));
        mMiddleRightLayout.addView(textViewOfMiddleRightLayout);
        layoutParamsOfMiddleRightLayout.addRule(RelativeLayout.BELOW, upLayout.getId());
        layoutParamsOfMiddleRightLayout
                .addRule(RelativeLayout.RIGHT_OF, mMiddleLeftLayout.getId());
        mMiddleRightLayout.setLayoutParams(layoutParamsOfMiddleRightLayout);
        mMiddleRightLayout.setBackgroundColor(Color.RED);
    }
    private void initMiddleLeftLayout()
    {
        mMiddleLeftLayout = new RelativeLayout(mContext);
        mMiddleLeftLayout.setId(generateId());
        RelativeLayout.LayoutParams layoutParamsOfMiddleLeftLayout = new RelativeLayout.LayoutParams(
                mDisplay.getWidth() / 2, mDisplay.getHeight() * 2 / 5);
        TextView textViewOfMiddleLeftLayout = new TextView(mContext);
        textViewOfMiddleLeftLayout.setId(generateId());
        textViewOfMiddleLeftLayout.setText("middleLeftLayout");
        textViewOfMiddleLeftLayout.setTextSize(20);
        textViewOfMiddleLeftLayout.setTextColor(Color.parseColor("#ff0000"));
        mMiddleLeftLayout.addView(textViewOfMiddleLeftLayout);
        layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.BELOW, upLayout.getId());
        layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.ALIGN_LEFT, upLayout.getId());
        mMiddleLeftLayout.setLayoutParams(layoutParamsOfMiddleLeftLayout);
        mMiddleLeftLayout.setBackgroundColor(Color.BLUE);
    }
    private void initDownLayout()
    {
        mDownLayout = new RelativeLayout(mContext);
        mDownLayout.setId(generateId());
        RelativeLayout.LayoutParams layoutParamsOfDownLayout = new RelativeLayout.LayoutParams(
                mDisplay.getWidth() / 1, mDisplay.getHeight() * 2 / 5);
        layoutParamsOfDownLayout.addRule(RelativeLayout.BELOW, mMiddleLeftLayout.getId());
        TextView textViewOfDownLayout = new TextView(mContext);
        textViewOfDownLayout.setId(generateId());
        textViewOfDownLayout.setText("DownLayout");
        textViewOfDownLayout.setTextSize(20);
        textViewOfDownLayout.setTextColor(Color.parseColor("#ffffff"));
        mDownLayout.addView(textViewOfDownLayout);
        mDownLayout.setLayoutParams(layoutParamsOfDownLayout);
        mDownLayout.setBackgroundColor(Color.GREEN);
    }
}

 
有幾個必須注意的要點。

1.即使加入所有UI widget之後,還是可以調整各個UI widget的屬性。

比如說若修改createLayout方法, 其中第14,15,16行重新修改了綠色區塊的width。

public RelativeLayout createLayout()
{
        RelativeLayout rootlayout = new RelativeLayout(mContext);
        rootlayout.setId(generateId());
        initUpLayout();
        initMiddleLeftLayout();
        initMiddleRightLayout();
        initDownLayout();
        rootlayout.addView(mDownLayout);
        rootlayout.addView(mMiddleLeftLayout);
        rootlayout.addView(upLayout);
        rootlayout.addView(mMiddleRightLayout);
       RelativeLayout.LayoutParams scaleLayoutParams = new RelativeLayout.LayoutParams(mDisplay.getWidth()/2, mDisplay.getHeight()*2/5);
       scaleLayoutParams.addRule(RelativeLayout.BELOW, mMiddleLeftLayout.getId());
       mDownLayout.setLayoutParams(scaleLayoutParams);
        return rootlayout;
}

綠色區塊的width即會變為滿版的0.5。如下圖
device-2015-07-08-160007
 

2.對Parent View來說,addView的順序和各child View的相依性並沒有一定的關係。

以本範例來說,Parent View就是rootView, 而child view就是 upLayout, mMiddleLeftLayout, mMiddleRightLayout, mDownLayout。
各元件的相依性指的是以藍色區塊來說,它必須是在黑色區塊下方,且貼齊左邊,code如下

private void initMiddleLeftLayout()
{
        ...
      layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.BELOW, upLayout.getId());
      layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.ALIGN_LEFT, upLayout.getId());
        ...
}

也就是說藍色區塊在位置的相依性上必須依賴黑色區塊,沒有黑色區塊,藍色區塊就不知道自己的位置在哪。
然而位置的相依性與被加入到rootView中的順序沒有關係。對rootView而言可以先加入藍色區塊再加入黑色區塊,如下

public RelativeLayout createLayout()
{
        ...
        rootlayout.addView(mMiddleLeftLayout);
        rootlayout.addView(upLayout);
        ...
}

 

3.調整UI Widget的重點在於LayoutParams。

以initMiddleLeftLayout方法來說,
第4~5行初始化layoutParamsofMiddleLeftLayout可設定其元件所佔的width, height。
第6~7行則是指定該元件的位置屬性。

private void initMiddleLeftLayout()
{
        ...
        RelativeLayout.LayoutParams layoutParamsOfMiddleLeftLayout = new RelativeLayout.LayoutParams(
                mDisplay.getWidth() / 2, mDisplay.getHeight() * 2 / 5);
        layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.BELOW, upLayout.getId());
        layoutParamsOfMiddleLeftLayout.addRule(RelativeLayout.ALIGN_LEFT, upLayout.getId());
        mMiddleLeftLayout.setLayoutParams(layoutParamsOfMiddleLeftLayout);
        ...
}