之前寫過一篇文章裡面有用到自定義組件的一個小Demo ,今天特地把這個Demo 拿出來講講。 在 ApiDemos 中有相應的幾個例子也有講述自定義組件,比如:Custorm 、 List4 和 List 6 。
那麼為什麼需要自定義組件?
因為在實際項目中或許 Android 給出的View 的功能不足以你實現一些特定的功能,這時候你就有必要去擴展它,或者去組裝它,使它的功能更為強大。 本篇只講述了如何將不同的組件混合起來並為其設置監聽事件。
下面是一段從CSDN 博客摘錄的一段話,感興趣的朋友可以:http://blog.csdn.net/shiqx429/archive/2009/02/06/3865581.aspx
如果你不想創建一個完全自定義的組件,而是由幾個現有組件的組合產生的新的組件,那麼混合組件技術就更加適合。簡單的來說,這樣把幾個現有的組件融合到一個邏輯組合裡面可以封裝成一個新的組件。例如,一個Combo Box組件可以看作是是一個EditText和一個帶有彈出列表的Button組件的混合體。如果你點擊按鈕為列表選擇一項,
在Android中,其實還有其他的兩個View類可以做到類似的效果: Spinner和AutoCompleteTextView,,但是Combo Box作為一個例子更容易讓人理解。
下面簡單的介紹如何創建組合組件:
一般從Layout類開始,創建一個Layout類的派生類。也許在Combo box我們會選擇水平方向的LinearLayout作為父類。記住,其他的Layout類是可以嵌套到裡面的,因此混合組件可以是任何組件的混合。注意,正如Activity一樣,你既可以使用外部XML文件來聲明你的組件,也可以嵌套在代碼中。
在新的混合組件的構造函數中,首先,調用所有的父類的構造函數,傳入對應的參數。然後可以設置你的混合組件的其他的一些方面,在哪創建EditText組件,又在哪創建PopupList組件。注意:你同時也可以在XML文件中引入一些自己的屬性和參數,這些屬性和參數也可以被你的混合組件所使用。
你也可以創建時間監聽器去監聽新組件中View類觸發的事件,例如,對List選項單擊事件的監聽,你必須在此時間發生後更新你EditText的值。
你可能創建自己的一些屬性,帶有訪問和修改方法。例如,允許設置EditText初始值並且提供訪問它的方法。
在Layout的派生類中,你沒有必要去重載onDraw()和onMeasure()方法,因為Layout會有比較好的默認處理。但是,如果你覺得有必要你也可以重載它。
你也可能重載一些on系列函數,例如通過onKeyDown()的重載,你可以通過按某個鍵去選擇列表中的對應的值。
總之,把Layout類作為基類有下面幾個優點:
正如activity一樣,你也可以通過XML文件去聲明你的新組件,或者你也可以在代碼中嵌套。
onDraw()函數和onMeasure()函數是沒有必要重載的,兩個函數已經做得很好了。
你可以很快的創建你的混合組件,並且可以像單一組件那樣使用。
本篇Demo 例子功能為:擴展LinearLayout 為其加一個ImageButton 和 TextView 使其具有混合功能的效果,並為各自組件添加get/set 方法,並為ImageButton 設置監聽使其的功能跟我們後面要使用的設置監聽的功能賦值,達到設置混合組件監聽的目的,下面給出代碼:
package com.terry.custom.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TextExt extends LinearLayout {
private TextView tv;
private ImageButton ib;
private onExtClickListener clickListener;
public TextExt(Context context, String text, int imgres) {
super(context);
// TODO Auto-generated constructor stub
this.setOrientation(VERTICAL);
tv = new TextView(context);
tv.setText(text);
addView(tv, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
ib = new ImageButton(context);
ib.setImageResource(imgres);
ib.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (clickListener != null) {
clickListener.onclickListenr(getText());
}
}
});
addView(ib, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
public void setText(String text) {
tv.setText(text);
}
public String getText() {
return tv.getText().toString();
}
public void setImage(int res) {
ib.setImageResource(res);
}
public Drawable getDrawable() {
return ib.getDrawable();
}
public void setDrawable(Drawable dd) {
ib.setImageDrawable(dd);
}
public void setOnExtClickListener(onExtClickListener click) {
this.clickListener = click;
}
}
設置監聽其實就是實現一個接口功能,不知道這樣表達是否正確,如果不正確請指教,這裡我的理解是這樣的:
public interface onExtClickListener {
public void onclickListenr(String text);
}
通過上面的代碼,我們己經封裝好了一個組合控件,下面給出調用和設置代碼:
package com.terry;
import com.terry.custom.widget.TextExt;
import com.terry.custom.widget.onExtClickListener;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
public class CustomActivity extends Activity {
boolean isChange = true;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextExt te = new TextExt(this, "自定義組件", R.drawable.icon);
te.setOnExtClickListener(new onExtClickListener() {
@Override
public void onclickListenr(String text) {
// TODO Auto-generated method stub
Toast.makeText(CustomActivity.this, text, 1000).show();
}
});
LinearLayout ly = (LinearLayout) findViewById(R.id.testWidget);
ly.addView(te);
Button btn = (Button) findViewById(R.id.Button01);
Button btn2 = (Button) findViewById(R.id.Button02);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isChange) {
te.setImage(android.R.drawable.btn_dialog);
} else {
te.setDrawable(getResources().getDrawable(R.drawable.icon));
}
isChange = !isChange;
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
te.setText("只可以改變一次喔 ");
}
});
}
}
假如你希望把自己的封裝完成的組件能夠像普通VIEW 一樣可以在XML 勾勒出來,可以參照我的一篇文章,裡面有給出實現的效果:
Android ApiDemos 系列解析【View-ImageView/ImageButton】
實現效果如下:
源碼下載:
自定義組件源碼
轉自:http://www.cnblogs.com/TerryBlog/archive/2010/08/03/1791568.html