總效果:
這裏動態生成十個相同的列表,這是最終效果,但凡事都是從易而難的,下面我們就從XML生成一項內容開始講解。
一、利用XML生成一項列表
這裏先利用XML生成一項列表開始,先看一項列表的效果圖及對應代碼:
對應的XML代碼爲:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#19000000"
android:gravity="center_horizontal"
android:paddingBottom="20dip"
android:paddingTop="20dip"
android:text="嘗試動態生成列表"
android:textColor="#ff0000"
android:textSize="24sp" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" >
<LinearLayout
android:id="@+id/list_Lin"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- 動態生成部分開始 -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dip"
android:layout_marginRight="10dip"
android:layout_toLeftOf="@+id/image"
android:background="#ff00ff00"
android:orientation="horizontal"
android:padding="5dip" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的第一次經歷"
android:textColor="#ff000000"
android:textSize="20dip" />
</LinearLayout>
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:clickable="true"
android:padding="5dip"
android:src="@drawable/plus" />
</RelativeLayout>
<!-- 動態生成部分結束 -->
</LinearLayout>
</ScrollView>
</LinearLayout>
動態生成註釋裏的部分就是我們將要用代碼生成的部分,這裏寫出來是爲了在寫代碼時參考,現在把註釋裏的部分刪掉,開始在代碼中生成。
二、使用XML和JAVA代碼生成界面
先貼出完整的代碼,然後再逐步講解。
完整代碼:
package com.example.trydynamiclayout;
/**
* write by harvic
* 2014-4-25
* http://blog.csdn.net/harvic880925
*/
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
private static int id = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout lin = (LinearLayout) findViewById(R.id.list_Lin);
LinearLayout.LayoutParams LP_FW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
RelativeLayout newSingleRL=new RelativeLayout(this);
for(int i=0;i<10;)
{
newSingleRL=generateSingleLayout(id,"第"+(++i)+"個動態列表");
lin.addView(newSingleRL,LP_FW);//全部用父結點的佈局參數
}
// final LinearLayout root = (LinearLayout) findViewById(R.id.layout_root); //獲取總根結點
// setContentView(root); //這裏必須是總根結點
}
/**
* 新建一個列表item
* @param imageID 新建imageView的ID值
* @param str TextView要顯示的文字
* @return 新建的單項佈局變量
*/
private RelativeLayout generateSingleLayout(int imageID,String str)
{
RelativeLayout layout_root_relative=new RelativeLayout(this);
LinearLayout layout_sub_Lin=new LinearLayout(this);
layout_sub_Lin.setBackgroundColor(Color.argb(0xff, 0x00, 0xff, 0x00));
layout_sub_Lin.setOrientation(LinearLayout.VERTICAL);
layout_sub_Lin.setPadding(5, 5, 5, 5);
TextView tv = new TextView(this);
LinearLayout.LayoutParams LP_WW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv.setText(str);
tv.setTextColor(Color.argb(0xff, 0x00, 0x00, 0x00));
tv.setTextSize(20);
tv.setLayoutParams(LP_WW);
layout_sub_Lin.addView(tv);
RelativeLayout.LayoutParams RL_MW = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);//尤其注意這個位置,用的是父容器的佈局參數
RL_MW.setMargins(5, 5, 10, 5);
RL_MW.addRule(RelativeLayout.LEFT_OF,imageID);
layout_root_relative.addView(layout_sub_Lin,RL_MW);
ImageView imageView = new ImageView(this);
RelativeLayout.LayoutParams RL_WW = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
imageView.setPadding(5, 5, 5, 5);
RL_WW.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
imageView.setLayoutParams(RL_WW);
imageView.setClickable(true);
imageView.setId(imageID);
imageView.setImageResource(R.drawable.plus);
layout_root_relative.addView(imageView);
return layout_root_relative;
}
}
講解:
一、先看generateSingleLayout(int imageID,String str)
1、看這段代碼:
RelativeLayout layout_root_relative=new RelativeLayout(this);
LinearLayout layout_sub_Lin=new LinearLayout(this);
layout_sub_Lin.setBackgroundColor(Color.argb(0xff, 0x00, 0xff, 0x00));
layout_sub_Lin.setOrientation(LinearLayout.VERTICAL);
layout_sub_Lin.setPadding(5, 5, 5, 5);
TextView tv = new TextView(this);
LinearLayout.LayoutParams LP_WW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv.setText(str);
tv.setTextColor(Color.argb(0xff, 0x00, 0x00, 0x00));
tv.setTextSize(20);
tv.setLayoutParams(LP_WW);
layout_sub_Lin.addView(tv);
RelativeLayout.LayoutParams RL_MW = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);//尤其注意這個位置,用的是父容器的佈局參數
RL_MW.setMargins(5, 5, 10, 5);
RL_MW.addRule(RelativeLayout.LEFT_OF,imageID);
layout_root_relative.addView(layout_sub_Lin,RL_MW);
根據上面的XML可以,我們要首先生成一個RelativeLayout,這就是layout_root_relative。
注意一: (控件的佈局參數選擇方式)
然後生成其第一個字佈局LinearLayout layout_sub_Lin;然後再生成layout_sub_Lin裏唯一的一個控件,注意這裏設置LayoutParams的方式,使用的是LinearLayout 參數!!!!對於如何選擇當前控件的佈局layout_width、layout_height的參數的方法,主要是看其父佈局!!!!如果其父佈局是LinearLayout 設置其LayoutParams參數時就要使用LinearLayout.LayoutParams,正如這裏的TextView tv。而如果其父容器的相對佈局呢,一樣,換它父佈局的來,使用RelativeLayout.LayoutParams RL_MW,如這裏的LinearLayout layout_sub_Lin,所以即便layout_sub_Lin自己是佈局控件也要按其父容器的佈局方法寫!!!!
注意二: layout_toLeftOf的代碼書寫方法
在XML中,對於此LinearLayout的相對佈局,用到了android:layout_toLeftOf="@+id/image",而在代碼中是動態生成的控件,如何利用此規則呢。
首先給動態生成的ImageView設置一個ID值,此ID值在些Acitivity中必須是唯一的,不可衝突的,如果衝突,關於用到此ID值的任何代碼都將是無效的!這也就是後面代碼中會看到的imageView.setId(imageID);
然後利用addRule()添加規則。
2、剩餘代碼就沒什麼好講的了,就是生成一個imageView設置ID值及其它參數,然後添加到RelativeLayout中,並將layout_root_relative返回。
二、onCreate()函數
這段代碼如下:
final LinearLayout lin = (LinearLayout) findViewById(R.id.list_Lin);
LinearLayout.LayoutParams LP_FW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
RelativeLayout newSingleRL=new RelativeLayout(this);
for(int i=0;i<10;)
{
newSingleRL=generateSingleLayout(id,"第"+(++i)+"個動態列表");
lin.addView(newSingleRL,LP_FW);//全部用父結點的佈局參數
}
final LinearLayout root = (LinearLayout) findViewById(R.id.layout_root); //獲取總根結點
setContentView(root); //這裏必須是總根結點
1、先看For循環及其上部的代碼:
final LinearLayout lin = (LinearLayout) findViewById(R.id.list_Lin);
找到當前新生成的ITEM項的插入位置。
LinearLayout.LayoutParams LP_FW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
newSingleRL=generateSingleLayout(id,"第"+(++i)+"個動態列表");
lin.addView(newSingleRL,LP_FW);//全部用父結點的佈局參數
這裏是兩塊代碼,先看第二塊,先是新生成一項,注意這一項返回的結點是RelativeLayout layout_root_relative,然後將其插入到列表位置中去,注意要插入的佈局是LinearLayout lin,也就是layout_root_relative的父結點是LinearLayout,所以這也就是在addView時爲什麼它對應的佈局參數使用LinearLayout.LayoutParams的原因了!
2、setContentView(root);顯示視圖
這段代碼如下:
final LinearLayout root = (LinearLayout) findViewById(R.id.layout_root); //獲取總根結點
setContentView(root); //這裏必須是總根結點
這裏最注意的一點,setContentView()所設置的視圖結點是整個XML的根結點!!!!設置爲其它結點會發生異常!!!很容易理解。
更正:
在原來的onCreate代碼中,在代碼的最後,加上了
final LinearLayout root = (LinearLayout) findViewById(R.id.layout_root); //獲取總根結點
setContentView(root); //這裏必須是總根結點
其實這樣做是完全沒有必要的,直接將這兩句刪除,效果是完全一樣的。
原因在於,在其上面的代碼中,我們通過
final LinearLayout lin = (LinearLayout) findViewById(R.id.list_Lin);
找到了要插入佈局的結點位置,直接在其下面插入佈局代碼,界面會自動更新,根本不需要重新setContentView()
在博客中,我將這兩句無關代碼註釋了起來,而源碼中沒有更改過來,請大家注意一下,由於當時剛接觸這部分,對大家造成的誤導,深表歉意……
三、完全使用JAVA代碼生成UI界面
這部分其實在上面的改動不大,只是完全使用代碼構建整個界面,由於這種方法構建UI可維護性很差,所以不推薦使用。
其它代碼不變,OnCreate()函數代碼如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
final LinearLayout lin = new LinearLayout(this);
lin.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams LP_FW = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
RelativeLayout newSingleRL=new RelativeLayout(this);
for(int i=0;i<10;)
{
newSingleRL=generateSingleLayout(id,"第"+(++i)+"個動態列表");
lin.addView(newSingleRL,LP_FW);//全部用父結點的佈局參數
}
setContentView(lin); //這裏必須是總根結點
}
效果圖: