自定义控件,代码如下public class ActionBar extends LinearLayout { public static final int NONE = 0; public enum Type {
Normal,
Dashboard,
Empty
} public interface OnActionBarListener { /**
* Index used to indicate the ActionBar home item has been clicked.
*/
int HOME_ITEM = -1; void onActionBarItemClicked(int position);
} private TextView mTitleView;
private ImageButton mHomeButton;
private ImageView mHomeView; private boolean mMerging = false; private CharSequence mTitle;
private ActionBar.Type mType;
private OnActionBarListener mOnActionBarListener;
private LinkedList<ActionBarItem> mItems; private Drawable mDividerDrawable;
private Drawable mHomeDrawable;
private int mDividerWidth; private int mMaxItemsCount; public ActionBar(Context context) {
this(context, null);
} public ActionBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdActionBarStyle);
} public ActionBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs); initActionBar(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0); mTitle = a.getString(R.styleable.ActionBar_title); mDividerDrawable = a.getDrawable(R.styleable.ActionBar_dividerDrawable);
mDividerWidth = a.getDimensionPixelSize(R.styleable.ActionBar_dividerWidth, -1);
mHomeDrawable = a.getDrawable(R.styleable.ActionBar_homeDrawable);
mMaxItemsCount = a.getInt(R.styleable.ActionBar_maxItems, 3);
if (mHomeDrawable == null) {
mHomeDrawable = new ActionBarDrawable(context, R.drawable.gd_action_bar_home);
} int layoutID;
int type = a.getInteger(R.styleable.ActionBar_type, -1);
switch (type) {
case 2:
mType = Type.Empty;
layoutID = R.layout.gd_action_bar_empty;
break;
case 1:
mType = Type.Dashboard;
layoutID = R.layout.gd_action_bar_dashboard;
break;
case 0:
default:
mType = Type.Normal;
layoutID = R.layout.gd_action_bar_normal;
break;
} // HACK Cyril: Without this, the onFinishInflate is called twice !?!
// This issue is due to a bug when Android inflates a layout with a
// parent - which is compulsory with a <merge /> tag. I've reported this
// bug to Romain Guy who fixed it (patch will probably be available in
// the Gingerbread release).
mMerging = true;
LayoutInflater.from(context).inflate(layoutID, this);
mMerging = false; a.recycle();
} private void initActionBar() {
mItems = new LinkedList<ActionBarItem>();
} @Override
protected void onFinishInflate() {
super.onFinishInflate(); if (!mMerging) { switch (mType) {
case Dashboard:
// mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
// mHomeButton.setOnClickListener(mClickHandler);
mHomeView = (ImageView) findViewById(R.id.gd_action_bar_home_item);
mHomeView.setImageDrawable(mHomeDrawable);
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; case Empty:
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; case Normal:
default:
mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
mHomeButton.setOnClickListener(mClickHandler);
mHomeButton.setImageDrawable(mHomeDrawable);
mHomeButton.setContentDescription(getContext().getString(R.string.gd_go_home));
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; }
}
} /**
* Register a callback to be invoked when the user interacts with the
* {@link ActionBar}.
*
* @param listener The callback that will run.
*/
public void setOnActionBarListener(OnActionBarListener listener) {
mOnActionBarListener = listener;
} /**
* @param title The title to set to this {@link ActionBar}
*/
public void setTitle(CharSequence title) {
mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
}
} /**
* @param actionBarItemType
* @return
*/
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), NONE);
} /**
* @param actionBarItemType
* @param itemId
* @return
*/
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType, int itemId) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), itemId);
} /**
* @param item
* @return
*/
public ActionBarItem addItem(ActionBarItem item) {
return addItem(item, NONE);
} /**
* @param item
* @param itemId
* @return
*/
public ActionBarItem addItem(ActionBarItem item, int itemId) { if (mItems.size() >= mMaxItemsCount) {
/*
* An ActionBar must contain as few items as possible. So let's keep
* a limit :)
*/
return null;
} if (item != null) { item.setItemId(itemId); if (mDividerDrawable != null) {
ImageView divider = new ImageView(getContext());
int dividerWidth = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
final LinearLayout.LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.FILL_PARENT);
divider.setLayoutParams(lp);
divider.setBackgroundDrawable(mDividerDrawable);
addView(divider);
} final View itemView = item.getItemView();
itemView.findViewById(R.id.gd_action_bar_item).setOnClickListener(mClickHandler); final int size = (int) getResources().getDimension(R.dimen.gd_action_bar_height);
addView(itemView, new LayoutParams(size, LayoutParams.FILL_PARENT)); mItems.add(item);
} return item;
} /**
* @param position
* @return
*/
public ActionBarItem getItem(int position) {
if (position < 0 || position >= mItems.size()) {
return null;
}
return mItems.get(position);
} /**
* @param item
*/
public void removeItem(ActionBarItem item) {
removeItem(mItems.indexOf(item));
} /**
* @param position
*/
public void removeItem(int position) { if (position < 0 || position >= mItems.size()) {
return;
} final int viewIndex = indexOfChild(mItems.get(position).getItemView());
final int increment = (mDividerDrawable != null) ? 1 : 0;
removeViews(viewIndex - increment, 1 + increment);
mItems.remove(position);
} /**
* @param type
*/
public void setType(Type type) {
if (type != mType) { removeAllViews(); int layoutId = 0;
switch (type) {
case Empty:
layoutId = R.layout.gd_action_bar_empty;
break;
case Dashboard:
layoutId = R.layout.gd_action_bar_dashboard;
break;
case Normal:
layoutId = R.layout.gd_action_bar_normal;
break;
} mType = type;
LayoutInflater.from(getContext()).inflate(layoutId, this); // Reset all items
LinkedList<ActionBarItem> itemsCopy = new LinkedList<ActionBarItem>(mItems);
mItems.clear();
for (ActionBarItem item : itemsCopy) {
addItem(item);
}
}
} /**
* @param klass
* @return
*/
public ActionBarItem newActionBarItem(Class<? extends ActionBarItem> klass) {
try {
ActionBarItem item = klass.newInstance();
item.setActionBar(this);
return item;
} catch (Exception e) {
throw new IllegalArgumentException("The given klass must have a default constructor");
}
} private OnClickListener mClickHandler = new OnClickListener() { public void onClick(View v) {
if (mOnActionBarListener != null) { if (v == mHomeButton) {
mOnActionBarListener.onActionBarItemClicked(OnActionBarListener.HOME_ITEM);
return;
} final int itemCount = mItems.size();
for (int i = 0; i < itemCount; i++) {
final ActionBarItem item = mItems.get(i);
final View itemButton = item.getItemView().findViewById(R.id.gd_action_bar_item);
if (v == itemButton) {
item.onItemClicked();
mOnActionBarListener.onActionBarItemClicked(i);
break;
}
}
}
} };}自定义控件Android加载xmlBinary
Normal,
Dashboard,
Empty
} public interface OnActionBarListener { /**
* Index used to indicate the ActionBar home item has been clicked.
*/
int HOME_ITEM = -1; void onActionBarItemClicked(int position);
} private TextView mTitleView;
private ImageButton mHomeButton;
private ImageView mHomeView; private boolean mMerging = false; private CharSequence mTitle;
private ActionBar.Type mType;
private OnActionBarListener mOnActionBarListener;
private LinkedList<ActionBarItem> mItems; private Drawable mDividerDrawable;
private Drawable mHomeDrawable;
private int mDividerWidth; private int mMaxItemsCount; public ActionBar(Context context) {
this(context, null);
} public ActionBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdActionBarStyle);
} public ActionBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs); initActionBar(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0); mTitle = a.getString(R.styleable.ActionBar_title); mDividerDrawable = a.getDrawable(R.styleable.ActionBar_dividerDrawable);
mDividerWidth = a.getDimensionPixelSize(R.styleable.ActionBar_dividerWidth, -1);
mHomeDrawable = a.getDrawable(R.styleable.ActionBar_homeDrawable);
mMaxItemsCount = a.getInt(R.styleable.ActionBar_maxItems, 3);
if (mHomeDrawable == null) {
mHomeDrawable = new ActionBarDrawable(context, R.drawable.gd_action_bar_home);
} int layoutID;
int type = a.getInteger(R.styleable.ActionBar_type, -1);
switch (type) {
case 2:
mType = Type.Empty;
layoutID = R.layout.gd_action_bar_empty;
break;
case 1:
mType = Type.Dashboard;
layoutID = R.layout.gd_action_bar_dashboard;
break;
case 0:
default:
mType = Type.Normal;
layoutID = R.layout.gd_action_bar_normal;
break;
} // HACK Cyril: Without this, the onFinishInflate is called twice !?!
// This issue is due to a bug when Android inflates a layout with a
// parent - which is compulsory with a <merge /> tag. I've reported this
// bug to Romain Guy who fixed it (patch will probably be available in
// the Gingerbread release).
mMerging = true;
LayoutInflater.from(context).inflate(layoutID, this);
mMerging = false; a.recycle();
} private void initActionBar() {
mItems = new LinkedList<ActionBarItem>();
} @Override
protected void onFinishInflate() {
super.onFinishInflate(); if (!mMerging) { switch (mType) {
case Dashboard:
// mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
// mHomeButton.setOnClickListener(mClickHandler);
mHomeView = (ImageView) findViewById(R.id.gd_action_bar_home_item);
mHomeView.setImageDrawable(mHomeDrawable);
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; case Empty:
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; case Normal:
default:
mHomeButton = (ImageButton) findViewById(R.id.gd_action_bar_home_item);
mHomeButton.setOnClickListener(mClickHandler);
mHomeButton.setImageDrawable(mHomeDrawable);
mHomeButton.setContentDescription(getContext().getString(R.string.gd_go_home));
mTitleView = (TextView) findViewById(R.id.gd_action_bar_title);
setTitle(mTitle);
break; }
}
} /**
* Register a callback to be invoked when the user interacts with the
* {@link ActionBar}.
*
* @param listener The callback that will run.
*/
public void setOnActionBarListener(OnActionBarListener listener) {
mOnActionBarListener = listener;
} /**
* @param title The title to set to this {@link ActionBar}
*/
public void setTitle(CharSequence title) {
mTitle = title;
if (mTitleView != null) {
mTitleView.setText(title);
}
} /**
* @param actionBarItemType
* @return
*/
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), NONE);
} /**
* @param actionBarItemType
* @param itemId
* @return
*/
public ActionBarItem addItem(ActionBarItem.Type actionBarItemType, int itemId) {
return addItem(ActionBarItem.createWithType(this, actionBarItemType), itemId);
} /**
* @param item
* @return
*/
public ActionBarItem addItem(ActionBarItem item) {
return addItem(item, NONE);
} /**
* @param item
* @param itemId
* @return
*/
public ActionBarItem addItem(ActionBarItem item, int itemId) { if (mItems.size() >= mMaxItemsCount) {
/*
* An ActionBar must contain as few items as possible. So let's keep
* a limit :)
*/
return null;
} if (item != null) { item.setItemId(itemId); if (mDividerDrawable != null) {
ImageView divider = new ImageView(getContext());
int dividerWidth = (mDividerWidth > 0) ? mDividerWidth : mDividerDrawable.getIntrinsicWidth();
final LinearLayout.LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.FILL_PARENT);
divider.setLayoutParams(lp);
divider.setBackgroundDrawable(mDividerDrawable);
addView(divider);
} final View itemView = item.getItemView();
itemView.findViewById(R.id.gd_action_bar_item).setOnClickListener(mClickHandler); final int size = (int) getResources().getDimension(R.dimen.gd_action_bar_height);
addView(itemView, new LayoutParams(size, LayoutParams.FILL_PARENT)); mItems.add(item);
} return item;
} /**
* @param position
* @return
*/
public ActionBarItem getItem(int position) {
if (position < 0 || position >= mItems.size()) {
return null;
}
return mItems.get(position);
} /**
* @param item
*/
public void removeItem(ActionBarItem item) {
removeItem(mItems.indexOf(item));
} /**
* @param position
*/
public void removeItem(int position) { if (position < 0 || position >= mItems.size()) {
return;
} final int viewIndex = indexOfChild(mItems.get(position).getItemView());
final int increment = (mDividerDrawable != null) ? 1 : 0;
removeViews(viewIndex - increment, 1 + increment);
mItems.remove(position);
} /**
* @param type
*/
public void setType(Type type) {
if (type != mType) { removeAllViews(); int layoutId = 0;
switch (type) {
case Empty:
layoutId = R.layout.gd_action_bar_empty;
break;
case Dashboard:
layoutId = R.layout.gd_action_bar_dashboard;
break;
case Normal:
layoutId = R.layout.gd_action_bar_normal;
break;
} mType = type;
LayoutInflater.from(getContext()).inflate(layoutId, this); // Reset all items
LinkedList<ActionBarItem> itemsCopy = new LinkedList<ActionBarItem>(mItems);
mItems.clear();
for (ActionBarItem item : itemsCopy) {
addItem(item);
}
}
} /**
* @param klass
* @return
*/
public ActionBarItem newActionBarItem(Class<? extends ActionBarItem> klass) {
try {
ActionBarItem item = klass.newInstance();
item.setActionBar(this);
return item;
} catch (Exception e) {
throw new IllegalArgumentException("The given klass must have a default constructor");
}
} private OnClickListener mClickHandler = new OnClickListener() { public void onClick(View v) {
if (mOnActionBarListener != null) { if (v == mHomeButton) {
mOnActionBarListener.onActionBarItemClicked(OnActionBarListener.HOME_ITEM);
return;
} final int itemCount = mItems.size();
for (int i = 0; i < itemCount; i++) {
final ActionBarItem item = mItems.get(i);
final View itemButton = item.getItemView().findViewById(R.id.gd_action_bar_item);
if (v == itemButton) {
item.onItemClicked();
mOnActionBarListener.onActionBarItemClicked(i);
break;
}
}
}
} };}自定义控件Android加载xmlBinary
<!-- 定义一个垂直排列的LinearLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bar="http://schemas.android.com/apk/res/com.ht.pm.activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:divider="?android:attr/dividerHorizontal"
android:orientation="vertical"
android:showDividers="middle" > <com.leaf.actionbar.ActionBar
android:id="@id/gd_action_bar"
android:layout_height="@dimen/gd_action_bar_height"
android:layout_width="fill_parent"
android:background="?attr/gdActionBarBackground"
bar:type="normal"
bar:title="Test ActionBar" />
<FrameLayout
android:id="@+id/discount_fl_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3" />
</LinearLayout>
05-31 10:00:55.340: E/AndroidRuntime(24514): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ht.pm.activity/com.ht.pm.discount.DiscountActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class com.leaf.actionbar.ActionBar
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread.access$600(ActivityThread.java:130)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.os.Handler.dispatchMessage(Handler.java:99)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.os.Looper.loop(Looper.java:137)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread.main(ActivityThread.java:4745)
05-31 10:00:55.340: E/AndroidRuntime(24514): at java.lang.reflect.Method.invokeNative(Native Method)
05-31 10:00:55.340: E/AndroidRuntime(24514): at java.lang.reflect.Method.invoke(Method.java:511)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:810)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:577)
05-31 10:00:55.340: E/AndroidRuntime(24514): at dalvik.system.NativeStart.main(Native Method)
05-31 10:00:55.340: E/AndroidRuntime(24514): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class com.leaf.actionbar.ActionBar
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.createView(LayoutInflater.java:613)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:256)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.Activity.setContentView(Activity.java:1867)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.ht.pm.discount.DiscountActivity.onCreate(DiscountActivity.java:28)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.Activity.performCreate(Activity.java:5008)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
05-31 10:00:55.340: E/AndroidRuntime(24514): ... 11 more
05-31 10:00:55.340: E/AndroidRuntime(24514): Caused by: java.lang.reflect.InvocationTargetException
05-31 10:00:55.340: E/AndroidRuntime(24514): at java.lang.reflect.Constructor.constructNative(Native Method)
05-31 10:00:55.340: E/AndroidRuntime(24514): at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.LayoutInflater.createView(LayoutInflater.java:587)
05-31 10:00:55.340: E/AndroidRuntime(24514): ... 22 more
05-31 10:00:55.340: E/AndroidRuntime(24514): Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f010001 a=-1}
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.content.res.Resources.loadDrawable(Resources.java:1892)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.View.<init>(View.java:3336)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.view.ViewGroup.<init>(ViewGroup.java:427)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.widget.LinearLayout.<init>(LinearLayout.java:176)
05-31 10:00:55.340: E/AndroidRuntime(24514): at android.widget.LinearLayout.<init>(LinearLayout.java:172)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.leaf.actionbar.ActionBar.<init>(ActionBar.java:133)
05-31 10:00:55.340: E/AndroidRuntime(24514): at com.leaf.actionbar.ActionBar.<init>(ActionBar.java:129)
05-31 10:00:55.340: E/AndroidRuntime(24514): ... 25 more
问题是这里导致的 Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f010001 a=-1}