Android自定義Button

實現自定義Button有兩種方式,


1. 繼承View,在裏面自己去實現onDraw(), onMeasure(), onClickListener()等方法。這種方式比較靈活,可以實現複雜的需求。


代碼樣例如下:


public class CustomButton extends View{


private final static int WIDTH_PADDING = 8;


private final static int HEIGHT_PADDING = 10;


private final String label;


private final int imageResId;


private final Bitmap image;


//private final InternalListener listenerAdapter = new InternalListener();


public CustomButton(Context context, int resImage, String label)


       {


           super(context);


          this.label = label;


          this.imageResId = resImage;


           this.image = BitmapFactory.decodeResource(context.getResources(),


                  imageResId);


 


           setFocusable(true);


           setBackgroundColor(Color.WHITE);


           //setOnClickListener(listenerAdapter);


           setClickable(true);


       }


@Override


protected void onFocusChanged (boolean gainFocus, int direction, Rect previouslyFocusedRect){


this.setBackgroundColor(Color.GREEN);


}


@Override


protected void onDraw(Canvas canvas)


    {


         Paint textPaint = new Paint();


         textPaint.setColor(Color.BLACK);


         canvas.drawBitmap(image, WIDTH_PADDING / 2, HEIGHT_PADDING / 2, null);


          canvas.drawText(label, WIDTH_PADDING / 2, (HEIGHT_PADDING / 2) +


                  image.getHeight() + 8, textPaint);


     }


@Override


       protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)


        {


         setMeasuredDimension(measureWidth(widthMeasureSpec),


                 measureHeight(heightMeasureSpec));


         }


private int measureWidth(int measureSpec)


     {


        int preferred = image.getWidth() * 2;


         return getMeasurement(measureSpec, preferred);


     }


    


     private int measureHeight(int measureSpec)


     {


          int preferred = image.getHeight() * 2;


          return getMeasurement(measureSpec, preferred);


     }


     private int getMeasurement(int measureSpec, int preferred)


     {


              int specSize = MeasureSpec.getSize(measureSpec);


              int measurement = 0;


           


              switch(MeasureSpec.getMode(measureSpec))


             {


                  case MeasureSpec.EXACTLY:


                      // This means the width of this view has been given.


                      measurement = specSize;


                      break;


                 case MeasureSpec.AT_MOST:


                     // Take the minimum of the preferred size and what


                      // we were told to be.


                     measurement = Math.min(preferred, specSize);


                     break;


                default:


                     measurement = preferred;


                    break;


             }


      


             return measurement;


         }


    /* public void setOnClickListener(ClickListener newListener)


          {


              listenerAdapter.setListener(newListener);


          }*/


     public String getLabel()


          {


              return label;


          }


        


          /**


           * Returns the resource id of the image.


           */


          public int getImageResId()


          {


              return imageResId;


          }


         /* private class InternalListener implements View.OnClickListener


               {


                   private ClickListener listener = null;


             


                  


                   public void setListener(ClickListener newListener)


                   {


                       listener = newListener;


                   }


                 


                   @Override


                   public void onClick(View v)


                   {


                       if (listener != null)


                       {


                           listener.onClick(CustomImageButton.this);


                       }


                   }


               }*/


  


}


2. 另一種還是保持原來button的基本功能,只需要改變button在不同狀態下的樣式,那麼就可以這樣來做:

Android開發應用中,默認的Button是由系統渲染和管理大小的。而我們看到的成功的移動應用,都是有着酷炫的外觀和使用體驗的。因此,我們在開發產品的時候,需要對默認按鈕進行美化。在本篇裏,筆者結合在應用開發中的經驗,探討一下自定義背景的按鈕、自定義形狀按鈕的實現方法。

首先看實現效果截圖:

自定義背景的按鈕目前有2種方式實現,矢量和位圖。

1. 矢量圖形繪製的方式

矢量圖形繪製的方式實現簡單,適合對於按鈕形狀和圖案要求不高的場合。步驟如下:

(a) 使用xml定義一個圓角矩形,外圍輪廓線實線、內填充漸變色,xml代碼如下。

  1. //bg_alibuybutton_default.xml  
  2. <?xml version="1.0" encoding="utf-8"?>  
  3. <layer-list xmlns:android="http://schemas.android.com/apk/res/android">  
  4.    <item>  
  5.       <shape android:shape="rectangle">   
  6.          <solid android:color="#FFEC7600" />  
  7.          <corners  
  8.             android:topLeftRadius="5dip"  
  9.             android:topRightRadius="5dip"  
  10.             android:bottomLeftRadius="5dip"  
  11.             android:bottomRightRadius="5dip" />  
  12.       </shape>  
  13.    </item>  
  14.    <item android:top="1px" android:bottom="1px" android:left="1px" android:right="1px">  
  15.      <shape>  
  16.         <gradient   
  17.             android:startColor="#FFEC7600" android:endColor="#FFFED69E"   
  18.             android:type="linear" android:angle="90"  
  19.             android:centerX="0.5" android:centerY="0.5" />  
  20.         <corners  
  21.             android:topLeftRadius="5dip"  
  22.             android:topRightRadius="5dip"  
  23.             android:bottomLeftRadius="5dip"  
  24.             android:bottomRightRadius="5dip" />  
  25.       </shape>  
  26.    </item>    
  27. </layer-list>  

同樣定義bg_alibuybutton_pressed.xml和bg_alibuybutton_selected.xml,內容相同,就是漸變顏色不同,用於按鈕按下後的背景變化效果。

(b) 定義按鈕按下後的效果變化描述文件drawable/bg_alibuybutton.xml,代碼如下。

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item android:state_pressed="true"  
  4.         android:drawable="@drawable/bg_alibuybutton_pressed" />  
  5.     <item android:state_focused="true"  
  6.         android:drawable="@drawable/bg_alibuybutton_selected" />  
  7.     <item android:drawable="@drawable/bg_alibuybutton_default" />  
  8. </selector>  

(c) 在你需要的界面定義文件中,如layout/main.xml中定義一個Button控件。

  1. <Button  
  2.     android:layout_width="120dip"  
  3.     android:layout_height="40dip"  
  4.     android:text="矢量背景按鈕"       android:background="@drawable/bg_alibuybutton" />  

這樣,自定義背景的按鈕就可以使用了,在實現onClick方法後就可以響應操作。

 

2. 9-patch圖片背景方式

此種方法相對複雜繁瑣,但可以製作出更多、更復雜樣式的按鈕圖樣。

什麼是9-patch格式呢?

9-patch格式,是在Android中特有的一種PNG圖片格式,以"***.9.png"結尾。此種格式的圖片定義了可以伸縮拉伸的區域和文字顯示區域,這樣,就可以在Android開發中對非矢量圖進行拉伸而仍然保持美觀。如果使用位圖而沒有經過9-patch處理的話,效果就會想第一張截圖中的“普通圖片背景按鈕”那樣被無情的拉伸,影響效果。Android中大量用了這種技術,默認的按鈕的背景就是用了類似的方法實現的。我們看一下google官方的描述:

 

該格式相對於一般PNG圖片來說,多了上下左右各一條1px的黑線。左、上黑線隔開了9個格子,當中一個格子(見上圖Strechable Area區域)聲明爲可以進行拉伸。右、下兩條黑線所定義的Paddingbox區域是在該圖片當做背景時,能夠在圖片上填寫文字的區域。每條黑線都是可以不連續的,這樣就可以定義出很多自動拉伸的規格。Android sdk中提供了設置的工具,啓動命令位於:$ANDROID_SDK/tools/draw9patch.bat,使用它對於原始PNG進行設置9-patch格式,非常方便,如下圖。

        

draw9patch工具的右側是能夠看到各方向拉伸後的效果圖,你所要做的就是在圖上最外側一圈1px寬的像素上塗黑線。

注意,在draw9patch.bat第一次運行時,sdk2.2版本上會報錯:Java.lang.NoClassDefFoundError:org/jdesktop/swingworker/SwingWorker。需要下載swing-worker-1.1.jar,放入$android_sdk/tools/lib路徑下,成功運行。

此種方法實現的步驟如下。

(a) 使用draw9patch.bat作完圖片後,得到兩張按鈕背景,分別是正常和按下狀態下的,命名爲bg_btn.9.png和bg_btn_2.9.png。

(b) 編寫圖片使用描述文件bg_9patchbutton.xml。

  1. // in bg_9patchbutton.xml  
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  4.     <item android:state_pressed="true"  
  5.         android:drawable="@drawable/bg_btn_2" />  
  6.     <item android:state_focused="true"  
  7.         android:drawable="@drawable/bg_btn_2" />  
  8.     <item android:drawable="@drawable/bg_btn" />  
  9. </selector>  

(c) 在界面定義文件 layout/main.xml中添加Button、ImageButton按鈕控件的定義。Button、ImageButton都是可以使用背景屬性的。

  1. <Button  
  2.     android:layout_width="120dip"  
  3.     android:layout_height="40dip"  
  4.     android:text="9-patch圖片背景按鈕"  
  5.     android:background="@drawable/bg_9patchbutton" />  
  6. <Button  
  7.     android:layout_width="200dip"  
  8.     android:layout_height="40dip"  
  9.     android:text="9-patch圖片背景按鈕"  
  10.     android:background="@drawable/bg_9patchbutton" />  
  11. <Button  
  12.     android:layout_width="120dip"  
  13.     android:layout_height="80dip"  
  14.     android:text="9-patch圖片背景按鈕"  
  15.     android:background="@drawable/bg_9patchbutton" />  
  16. <ImageButton  
  17.     android:layout_width="120dip"  
  18.     android:layout_height="40dip"  
  19.     android:src="@drawable/bg_9patchbutton"  
  20.     android:scaleType="fitXY"  
  21.     android:background="@android:color/transparent" />  

以上2種實現按鈕的美化,都是標準的矩形按鈕爲基礎。在一些應用中我們可以看到漂亮的自定義形狀的異形按鈕,這是怎麼實現的呢?經過一番研究和實踐,找出了一種方便的方法,就是使用ImageButton加上9-patch就可以實現漂亮的自動延伸效果。

 

3. 自定義形狀、顏色、圖樣的按鈕的實現

步驟如下。

(a) 設計一張自定義形狀風格背景的圖片,如下圖。

(b) 未點擊和按下後的狀態各做一張,形成一套圖片,如下圖。

 forward.png    forward2.png

(c) 創建和編寫按鈕不同狀態的圖片使用描述文件drawable/ib_forward.xml

  1. // ib_forward.xml  
  2. <?xml version="1.0" encoding="UTF-8"?>  
  3. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  4.     <item android:state_pressed="true"  
  5.         android:drawable="@drawable/forward2" />  
  6.     <item android:state_focused="true"  
  7.         android:drawable="@drawable/forward2" />  
  8.     <item android:drawable="@drawable/forward" />  
  9. </selector>  

(d) 在界面定義文件 layout/main.xml中添加ImageButton按鈕控件的定義。

  1. // in layout/main.xml  
  2.     <ImageButton  
  3.         android:layout_width="80dip"  
  4.         android:layout_height="40dip"  
  5.         android:src="@drawable/ib_forword"  
  6.         android:scaleType="fitXY"  
  7.         android:background="@android:color/transparent" />  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章