一般產生 Layout 的作法大多數是使用 xml 來達成,但在一些特殊情況下必須在 java code 建立 Layout。
本篇紀錄如何在 java code 中產生 Layout。
首先貼上示意圖

可以看到示意圖中主要有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;
}
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);
...
}
