在實際開發中Android中內建的控制項有時無法滿足我們的需求,這時就需要我們重寫控制項來實現我們想要的功能。比如我想使Button有按下和彈起效果還可以寫文字,就沒有哪個原生的控制項能滿足我們的需求,在這裡我選擇重載ImageButton,在ImageButton的基礎上添加文字
實現效果
重寫按鈕實現代碼
package com.example.buttontest;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Paint.Align;import android.util.AttributeSet;import android.util.Log;import android.widget.ImageButton;/** * 自訂ImageButton 可以在ImageButton上面設定文字 */public class CustomImageButton extends ImageButton {private static final String TAG = "CustomImageButton_dzt";private String mtext = "a";private int mcolor = 0;private float mtextsize = 0f;private Paint mpatin;public CustomImageButton(Context context, AttributeSet attrs) {super(context, attrs);initAttrs(attrs);}private void initAttrs(AttributeSet attrs) {TypedArray array = getContext().obtainStyledAttributes(attrs,R.styleable.CustomButtonAttrs);mtext = array.getString(R.styleable.CustomButtonAttrs_textValue);mcolor = array.getColor(R.styleable.CustomButtonAttrs_textColor, 230);mtextsize = array.getDimension(R.styleable.CustomButtonAttrs_textSize,25.0f);array.recycle(); // 回收資源mpatin = new Paint();mpatin.setTextAlign(Align.CENTER);Log.d(TAG, "mtextsize = " + mtextsize);}public void setText(String text) {this.mtext = text;}public void setColor(int color) {this.mcolor = color;}public void setTextSize(float textsize) {this.mtextsize = textsize;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mpatin.setColor(mcolor);mpatin.setTextSize(mtextsize);canvas.drawText(mtext, canvas.getWidth() / 2,(canvas.getHeight() / 2) + 6, mpatin);}}
自訂控制項需要注意幾點
1.在view類中有三個建構函式
View(Context context)
Simple constructor to use when creating a view from code.
View(Context context, AttributeSet attrs)
Constructor that is called when inflating a view from XML.
View(Context context, AttributeSet attrs, int defStyleAttr)
Perform inflation from XML and apply a class-specific base style.
自訂的控制項如果要在xml中定義就要添加帶參數的建構函式
public CustomImageButton(Context context, AttributeSet attrs)
並且要調用父類的建構函式
2.如果要在xml中自訂控制項的屬性
需要解析attrs參數
private void initAttrs(AttributeSet attrs) {TypedArray array = getContext().obtainStyledAttributes(attrs,R.styleable.CustomButtonAttrs);mtext = array.getString(R.styleable.CustomButtonAttrs_textValue);mcolor = array.getColor(R.styleable.CustomButtonAttrs_textColor, 230);mtextsize = array.getDimension(R.styleable.CustomButtonAttrs_textSize,25.0f);array.recycle(); // 回收資源mpatin = new Paint();mpatin.setTextAlign(Align.CENTER);Log.d(TAG, "mtextsize = " + mtextsize);}R.styleable.CustomButtonAttrs是自訂的屬性
attrs.xml定義
自訂控制項的使用
解釋下面這句話的意思
xmlns:custom_btn="http://schemas.android.com/apk/res/com.example.buttontest"
其中custom_btn是自訂屬性的首碼,在後面引用自訂屬性時要用到,名字可以隨便起
com.example.buttontest為建立程式的包名,不管你自訂的控制項放在哪個包下,這裡只能用原生的包名
custom_btn:textValue="@string/rock" 這句話就是使用自訂控制項的屬性
以上xml中用到的樣式定義
在樣式中定義自訂控制項的屬性時需要添加原生的包名如:com.example.buttontest:textColor
在Activity中使用
package com.example.buttontest;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;public class MainActivity extends Activity {private int moldId = -1;CustomImageButton ImageButton1;CustomImageButton ImageButton2;CustomImageButton ImageButton3;CustomImageButton ImageButton4;CustomImageButton ImageButton5;CustomImageButton ImageButton6;CustomImageButton ImageButton7;CustomImageButton ImageButton8;CustomImageButton ImageButton9;CustomImageButton ImageButton10;CustomImageButton ImageButton11;CustomImageButton ImageButton12;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ImageButton1 = (CustomImageButton) findViewById(R.id.button1);ImageButton2 = (CustomImageButton) findViewById(R.id.button2);ImageButton3 = (CustomImageButton) findViewById(R.id.button3);ImageButton4 = (CustomImageButton) findViewById(R.id.button4);ImageButton5 = (CustomImageButton) findViewById(R.id.button5);ImageButton6 = (CustomImageButton) findViewById(R.id.button6);ImageButton7 = (CustomImageButton) findViewById(R.id.button7);ImageButton8 = (CustomImageButton) findViewById(R.id.button8);ImageButton9 = (CustomImageButton) findViewById(R.id.button9);ImageButton10 = (CustomImageButton) findViewById(R.id.button10);ImageButton11 = (CustomImageButton) findViewById(R.id.button11);ImageButton12 = (CustomImageButton) findViewById(R.id.button12);ImageButton1.setOnClickListener(new buttonListener());ImageButton2.setOnClickListener(new buttonListener());ImageButton3.setOnClickListener(new buttonListener());ImageButton4.setOnClickListener(new buttonListener());ImageButton5.setOnClickListener(new buttonListener());ImageButton6.setOnClickListener(new buttonListener());ImageButton7.setOnClickListener(new buttonListener());ImageButton8.setOnClickListener(new buttonListener());ImageButton9.setOnClickListener(new buttonListener());ImageButton10.setOnClickListener(new buttonListener());ImageButton11.setOnClickListener(new buttonListener());ImageButton12.setOnClickListener(new buttonListener());moldId = R.id.button3;selectBtnState(moldId);}/** * 選中的按鈕狀態 * * @param newId */private void selectBtnState(int newId) {switch (newId) {case R.id.button1:ImageButton1.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button2:ImageButton2.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button3:ImageButton3.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button4:ImageButton4.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button5:ImageButton5.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button6:ImageButton6.setBackgroundResource(R.drawable.eq_btn_sel);break;case R.id.button7:ImageButton7.setImageResource(R.drawable.eq_btn_sel);break;case R.id.button8:ImageButton8.setImageResource(R.drawable.eq_btn_sel);break;case R.id.button9:ImageButton9.setImageResource(R.drawable.eq_btn_sel);break;case R.id.button10:ImageButton10.setImageResource(R.drawable.eq_btn_sel);break;case R.id.button11:ImageButton11.setImageResource(R.drawable.eq_btn_sel);break;case R.id.button12:ImageButton12.setImageResource(R.drawable.eq_btn_sel);break;default:break;}}/** * 把前一個按鈕的狀態恢複 * * @param */private void regainBtnState(int oldId) {switch (oldId) {case R.id.button1:ImageButton1.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button2:ImageButton2.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button3:ImageButton3.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button4:ImageButton4.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button5:ImageButton5.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button6:ImageButton6.setBackgroundResource(R.drawable.eq_btn_selector);break;case R.id.button7:ImageButton7.setImageResource(R.drawable.eq_btn_selector);break;case R.id.button8:ImageButton8.setImageResource(R.drawable.eq_btn_selector);break;case R.id.button9:ImageButton9.setImageResource(R.drawable.eq_btn_selector);break;case R.id.button10:ImageButton10.setImageResource(R.drawable.eq_btn_selector);break;case R.id.button11:ImageButton11.setImageResource(R.drawable.eq_btn_selector);break;case R.id.button12:ImageButton12.setImageResource(R.drawable.eq_btn_selector);break;default:break;}}class buttonListener implements OnClickListener {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubif (moldId != v.getId()) {switch (v.getId()) {case R.id.button1:break;case R.id.button2:break;case R.id.button3:break;case R.id.button4:break;case R.id.button5:break;case R.id.button6:break;case R.id.button7:break;case R.id.button8:break;case R.id.button9:break;case R.id.button10:break;case R.id.button11:break;}regainBtnState(moldId);selectBtnState(v.getId());moldId = v.getId();}}}}在實際使用中遇到一個奇怪的問題在電阻屏上以上代碼按鈕的點擊沒有問題,如果在電容屏(支援多點觸摸)上,第二行的按鈕有可能會出現多個按鈕同時選中的狀態,這二行按鈕不同點在於一個使用setBackgroundResource設定,另一行使用setImageResource在xml中分別對應android:background、android:src一個設定背景圖,一個設定前景圖,至於為什麼使用setImageResource會出現多個被選中,還沒有找到根本原因
還有個關於UI體驗的問題,就是在onDraw()函數中最好不要去建立對象,否則就提示下面的警告資訊:因為onDraw()調用頻繁,不斷進行建立和記憶體回收會影響UI顯示的效能
例如:
protected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint mpatin = new Paint();mpatin.setTextAlign(Align.CENTER);mpatin.setColor(mcolor);mpatin.setTextSize(mtextsize);canvas.drawText(mtext, canvas.getWidth() / 2,(canvas.getHeight() / 2) + 6, mpatin);}
Avoid object allocations during draw/layout operations (preallocate and reuse instead)
範例程式碼
http://download.csdn.net/detail/deng0zhaotai/7005597