Android 步步為營 第5營 代碼控制UI,View


在前面的幾講中,我們都是使用xml layout 來去控制UI組件,其實我們也可以完全拋開XML,用純代碼來控制我們的界面UI。

回顧我們學過的,遇到過的UI組件,有容器類的Layout:LinearLayout,RelativeLayout等, 也有視圖類UI:TextView, EditText, Button, ImageView等。對應到代碼中,我們會發現,他們都是View子類,具體關系如下:

KYWAZ3Y$VI3K3TG[5`2B6$Y

Tips:在Eclipse中,可以用Ctrl+T鍵來查看某個類的類層次關系:

0D_F60N5P9WVPU(V5CKI8{4

 

ViewGroup 與View 的關系,是一個典型的“組合”設計模式。

我們來用代碼,實現一個簡單的UI布局:

L{HDSP]0NSR]QI`@V%UPVMF

只有一個EditText和一個Button, 看看代碼是怎么寫的:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        LinearLayout container = new LinearLayout(this);
        container.setOrientation(LinearLayout.HORIZONTAL);
        
        this.setContentView(container);
        
        EditText content = new EditText(this);
        content.setHint("寫點什么吧...");
        Button submit = new Button(this);
        submit.setText("發送");
        
        container.addView(content);
        container.addView(submit);
        
    }
}

我們來分析一下代碼,

不管LinearLayout, EditText 還是Button, 他們的構造函數都是this. 其實查看源碼后我們發現,所有的View及其子類的構造都至少包含三個構造方法:

public View(Context context)

public View(Context context, AttributeSet attrs)

public View(Context context, AttributeSet attrs, int defStyle)

 

后兩個是為XML layout 定義的,用代碼創建View時,一般都是用第一個構造函數,這里用this, 是因為Activity其實就是Context的子類。

this.setContentView()這個方法,以前我們都是傳一個R.layout進去,其實它有多個重載,也可以直接傳入根視圖View。

這里的線性布局container 就是根視圖(容器視圖),要往容器視圖里面添加View,使用addView方式,addView 方法有幾個重載版本:

public void addView(View child)

public void addView(View child, int index)

public void addView(View child, int index, LayoutParams params)

public void addView(View child, int width, int height)

public void addView(View child, LayoutParams params)

LayoutParams 我們之后會講到。

總結一下,用代碼添加UI組件的步驟是:

  • New 組件對應的類;
  • 把它添加到父容器中。

運行結果就如上圖的一樣。你也許會想到,不是說width, height是必須的嗎?怎么沒有設置也可以啊?是因為,addView默認使用wrap_content.

但是光是這樣不夠,我們還想添加邊距,權重等。

為View指定LayoutParams

添加寬,高,邊距,權重這些屬性,對應的類是LayoutParams,它一般都是作為一個內部類出現在某個ViewGroup的子類中。對於線性布局,我們使用LinearLayout.LayoutParams,

weight, leftMargin, rightMargin…..這些屬性都在它的公有變量里面。

LinearLayout.LayoutParams contentLayoutParams = new LinearLayout.LayoutParams(0,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        contentLayoutParams.weight = 1;
        contentLayoutParams.leftMargin = 10;
        
        container.addView(content, contentLayoutParams);
        
        LinearLayout.LayoutParams buttonLayoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        buttonLayoutParams.leftMargin = 10;
        container.addView(submit, buttonLayoutParams);

在addView之前,我們設置好LayoutParams 的值,調用addView(View child, LayoutParams params)這個重載方法。

UI}32`6UT_E7%RT%DTPSE4F

 

相對布局的RelativeLayout.LayoutParams

我們來看看, 在代碼中,調用那些方法來定位布局

因為在相對布局中, 定位的方法有很多種類,所以API提供了一個統一的方法:

addRule(int verb, int anchor)

addRule(int verb)

verb是動詞的意思,就是用來表達above, below, toRightOf, toLeftOf, alignParentLeft…..等等。

這些動詞的int 值在RelativeLayout下有常量定義。例如:

RelativeLayout.ABOVE

RelativeLayout.BELOW

RelativeLayout.ALIGN_LEFT

RelativeLayout.LEFT_OF

RelativeLayout.RIGHT_OF

anchor的值,可以是RelativeLayout.TRUE,0表示false, 或者其它View 的Id, 根據具體的verb, 填入相應的值:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.setContentView(this.addRelativeLayout());
    }

    private RelativeLayout addRelativeLayout() {
        RelativeLayout container = new RelativeLayout(this);
        Button btn1 = new Button(this);
        btn1.setId(11);
        btn1.setText("上");        
        Button btn2 = new Button(this);
        btn2.setId(12);
        btn2.setText("下");        
        Button btn3 = new Button(this);
        btn3.setId(13);
        btn3.setText("左");        
        Button btn4 = new Button(this);
        btn4.setId(14);
        btn4.setText("右");    
        Button btn5 = new Button(this);
        btn5.setId(15);
        btn5.setText("中");
        RelativeLayout.LayoutParams lp1 = new RelativeLayout.LayoutParams(100,
                RelativeLayout.LayoutParams.WRAP_CONTENT);
        
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(lp1);
        RelativeLayout.LayoutParams lp3 = new RelativeLayout.LayoutParams(lp1);
        RelativeLayout.LayoutParams lp4 = new RelativeLayout.LayoutParams(lp1);
        RelativeLayout.LayoutParams lp5 = new RelativeLayout.LayoutParams(lp1);
        lp5.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
        
        lp1.addRule(RelativeLayout.ABOVE, btn5.getId());
        lp1.addRule(RelativeLayout.ALIGN_LEFT, btn5.getId());
        lp2.addRule(RelativeLayout.BELOW, btn5.getId());
        lp2.addRule(RelativeLayout.ALIGN_LEFT, btn5.getId());
        lp3.addRule(RelativeLayout.LEFT_OF, btn5.getId());
        lp3.addRule(RelativeLayout.ALIGN_BASELINE, btn5.getId());
        lp4.addRule(RelativeLayout.RIGHT_OF, btn5.getId());
        lp4.addRule(RelativeLayout.ALIGN_TOP, btn5.getId());

        container.addView(btn5, lp5);
        container.addView(btn1, lp1);
        container.addView(btn2, lp2);
        container.addView(btn3, lp3);
        container.addView(btn4, lp4);
        
        return container;
    }

注意:LayoutParams的構造函數也可以是另外一個已經存在的LayoutParams對象,他的width, height值被克隆到當前對象中去。

H$5Z~Y`M$QI]095GSLL9HBH

 

FrameLayout, TableLayout的LayoutParams, 讀者可自行研究一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM