android 自定義組合控制元件 頂部導航欄
在軟體開發過程中,經常見到,就是APP 的標題欄樣式幾乎都是一樣的,只是文字不同而已,兩邊圖示不同。為了減少重複程式碼,提高效率, 方便大家使用,我們把標題欄通過組合的方式定義成一個控制元件。
例下圖:
點選:
如不設定左邊,右邊圖片:
下面說一下具體實現步驟:
步驟一:
導航欄包括:
* 返回按鈕
* 標題
* 右側按鈕(功能不確定)
首先是佈局檔案,如下:
</pre><p></p><pre name="code" class="java"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/holo_blue_light" tools:context=".MainActivity" > <TextView android:id="@+id/text_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textSize="25sp" android:gravity="center" android:textColor="@android:color/white" android:padding="2dp" /> <ImageView android:id="@+id/back_image" android:layout_width="40dp" android:layout_height="40dp" android:scaleType="centerInside" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_marginLeft="12dp" /> <ImageView android:id="@+id/right_image" android:layout_width="40dp" android:layout_height="40dp" android:scaleType="centerInside" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="12dp" /> </RelativeLayout>
步驟二:在values下新建 attrs檔案 定義控制元件要用到的屬性,如下面的程式碼所示。這裡我們定義了標題欄文字(textText),字型大小(textSize),字型顏色(textColor),左邊按鈕 (leftBtn ),右邊按鈕 (rightBtn ) 。(當然你還要以給它新增其它屬性如背景)
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Topbar"> <attr name="titleText" format="string|reference" /> <attr name="titleSize" format="dimension|reference" /> <attr name="titleColor" format="color|reference" /> <attr name="leftBtn" format="reference"/> <attr name="rightBtn" format=" reference"/> </declare-styleable> </resources>
步驟三:定義類Topbar繼承自RelativeLayout,重寫建構函式並構造方法中獲得我們自定義的屬性,具體程式碼如下。程式碼中定義了一個TextView顯示標題文字,一個Imageview 顯示左側按鈕,一個Imageview 顯示右側按鈕 ,其他欄位對應attrs中宣告的屬性。
private ImageView backView; private ImageView rightView; private TextView titleView; private String titleTextStr; private int titleTextSize ; private int titleTextColor ; private Drawable leftImage ; private Drawable rightImage ; public TopBarView(Context context){ this(context, null); } public TopBarView(Context context, AttributeSet attrs) { this(context, attrs,R.style.AppTheme); } public TopBarView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); getConfig(context, attrs); initView(context); } /** * 從xml中獲取配置資訊 */ private void getConfig(Context context, AttributeSet attrs) { //TypedArray是一個數組容器用於存放屬性值 TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Topbar); int count = ta.getIndexCount(); for(int i = 0;i<count;i++) { int attr = ta.getIndex(i); switch (attr) { case R.styleable.Topbar_titleText: titleTextStr = ta.getString(R.styleable.Topbar_titleText); break; case R.styleable.Topbar_titleColor: // 預設顏色設定為黑色 titleTextColor = ta.getColor(attr, Color.BLACK); break; case R.styleable.Topbar_titleSize: // 預設設定為16sp,TypeValue也可以把sp轉化為px titleTextSize = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; case R.styleable.Topbar_leftBtn: leftImage = ta.getDrawable(R.styleable.Topbar_leftBtn); break; case R.styleable.Topbar_rightBtn: rightImage = ta.getDrawable(R.styleable.Topbar_rightBtn); break; } } //用完務必回收容器 ta.recycle(); } private void initView(Context context) { View layout = LayoutInflater.from(context).inflate(R.layout.custom_groupwidget, this,true); backView = (ImageView) layout.findViewById(R.id.back_image); titleView = (TextView) layout.findViewById(R.id.text_title); rightView = (ImageView) layout.findViewById(R.id.right_image); backView.setOnClickListener(this); rightView.setOnClickListener(this); if(null != leftImage) backView.setImageDrawable(leftImage); if(null != rightImage) rightView.setImageDrawable(rightImage); if(null != titleTextStr) { titleView.setText(titleTextStr); titleView.setTextSize(titleTextSize); titleView.setTextColor(titleTextColor); } }
步驟四:定義了一個OnClickListenner來監聽ImageView的點選
private onTitleBarClickListener onMyClickListener;
/**
* 設定按鈕點選監聽介面
* @param callback
*/
public void setClickListener(onTitleBarClickListener listener) {
this.onMyClickListener = listener;
}
/**
* 導航欄點選監聽介面
*/
public static interface onTitleBarClickListener{
/**
* 點選返回按鈕回撥
*/
void onBackClick();
void onRightClick();
}
@Override
public void onClick(View v) {
int id = v.getId();
switch(id)
{
case R.id.back_image:
if(null != onMyClickListener)
onMyClickListener.onBackClick();
break;
case R.id.right_image:
if(null != onMyClickListener)
onMyClickListener.onRightClick();
break;
}
}
步驟五: 再看一下主佈局怎樣使用自定義控制元件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.customgroupwidget"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.example.customgroupwidget.TopBarView
android:id="@+id/topbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:titleText="我的訊息"
custom:titleSize="15sp"
custom:titleColor="@android:color/white"
custom:leftBtn="@drawable/back_page"
custom:rightBtn="@drawable/edit_normal" />
</RelativeLayout>
步驟六:最後看一下Activity中的呼叫:
public class MainActivity extends Activity implements onTitleBarClickListener {
private TopBarView topbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
topbar = (TopBarView)findViewById(R.id.topbar);
topbar.setClickListener(this);
}
@Override
public void onBackClick() {
Toast.makeText(MainActivity.this, "你點選了左側按鈕", Toast.LENGTH_LONG).show();
}
@Override
public void onRightClick() {
Toast.makeText(MainActivity.this, "你點選了右側按鈕", Toast.LENGTH_SHORT).show();
}
}
最後普及一下,attrs.xml中的屬性的format(型別)說明
1. reference:參考某一資源ID。
(1)屬性定義:
<declare-styleable name = "名稱">
<attr name = "background" format = "reference" />
</declare-styleable>
(2)屬性使用:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/圖片ID"
/>
2. color:顏色值。
(1)屬性定義:
<declare-styleable name = "名稱">
<attr name = "textColor" format = "color" />
</declare-styleable>
(2)屬性使用:
<TextView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:textColor = "#00FF00"
/>
3. boolean:布林值。
(1)屬性定義:
<declare-styleable name = "名稱">
<attr name = "focusable" format = "boolean" />
</declare-styleable>
(2)屬性使用:
<Button
android:layout_width = "42dip"
android:layout_height = "42dip"
android:focusable = "true"
/>
4. dimension:尺寸值。
(1)屬性定義:
<declare-styleable name = "名稱">
<attr name = "layout_width" format = "dimension" />
</declare-styleable>
(2)屬性使用:
<Button
android:layout_width = "42dip"
android:layout_height = "42dip"
/>
5. float:浮點值。
(1)屬性定義:
<declare-styleable name = "AlphaAnimation">
<attr name = "fromAlpha" format = "float" />
<attr name = "toAlpha" format = "float" />
</declare-styleable>
(2)屬性使用:
<alpha
android:fromAlpha = "1.0"
android:toAlpha = "0.7"
/>
6. integer:整型值。
(1)屬性定義:
<declare-styleable name = "AnimatedRotateDrawable">
<attr name = "visible" />
<attr name = "frameDuration" format="integer" />
<attr name = "framesCount" format="integer" />
<attr name = "pivotX" />
<attr name = "pivotY" />
<attr name = "drawable" />
</declare-styleable>
(2)屬性使用:
<animated-rotate
xmlns:android = "http://schemas.android.com/apk/res/android"
android:drawable = "@drawable/圖片ID"
android:pivotX = "50%"
android:pivotY = "50%"
android:framesCount = "12"
android:frameDuration = "100"
/>
7. string:字串。
(1)屬性定義:
<declare-styleable name = "MapView">
<attr name = "apiKey" format = "string" />
</declare-styleable>
(2)屬性使用:
<com.google.android.maps.MapView
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"
/>
8. fraction:百分數。
(1)屬性定義:
<declare-styleable name="RotateDrawable">
<attr name = "visible" />
<attr name = "fromDegrees" format = "float" />
<attr name = "toDegrees" format = "float" />
<attr name = "pivotX" format = "fraction" />
<attr name = "pivotY" format = "fraction" />
<attr name = "drawable" />
</declare-styleable>
(2)屬性使用:
<rotate
android:fromDegrees = "0"
android:toDegrees = "360"
android:pivotX = "200%"
android:pivotY = "300%"
android:duration = "5000"
android:repeatMode = "restart"
android:repeatCount = "infinite"
/>
9. enum:列舉值。
(1)屬性定義:
<declare-styleable name="名稱">
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
(2)屬性使用:
<LinearLayout
xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation = "vertical"
android:layout_width = "fill_parent"
android:layout_height = "fill_parent"
>
</LinearLayout>
10. flag:位或運算。
(1)屬性定義:
<declare-styleable name="名稱">
<attr name="windowSoftInputMode">
<flag name = "stateUnspecified" value = "0" />
<flag name = "stateUnchanged" value = "1" />
<flag name = "stateHidden" value = "2" />
<flag name = "stateAlwaysHidden" value = "3" />
<flag name = "stateVisible" value = "4" />
<flag name = "stateAlwaysVisible" value = "5" />
<flag name = "adjustUnspecified" value = "0x00" />
<flag name = "adjustResize" value = "0x10" />
<flag name = "adjustPan" value = "0x20" />
<flag name = "adjustNothing" value = "0x30" />
</attr>
</declare-styleable>
(2)屬性使用:
<activity
android:name = ".StyleAndThemeActivity"
android:label = "@string/app_name"
android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
特別要注意:
屬性定義時可以指定多種型別值。
(1)屬性定義:
<declare-styleable name = "名稱">
<attr name = "background" format = "reference|color" />
</declare-styleable>
(2)屬性使用:
<ImageView
android:layout_width = "42dip"
android:layout_height = "42dip"
android:background = "@drawable/圖片ID|#00FF00"
/>