/*
* Copyright (C) 2010 Cyril Mottier (http://www.cyrilmottier.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mfh.comna.actionbar;
import java.util.LinkedList;
import com.mfh.comna.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
/**
*
* @author Cyril Mottier
*/
public abstract class BaseActionBar extends LinearLayout {
/**
* Default identifier applied to a newly added {@link com.mfh.comna.actionbar.ActionBarItem}s.
*
* @deprecated Adding items to the ActionBar with no identifier does not
* allow client to retrieve a particular {@link com.mfh.comna.actionbar.ActionBarItem}
* safely. In order to avoid this problem, {@link com.mfh.comna.actionbar.ActionBarItem}
* s should be added with methods that requires explicit
* identifiers such as
* {@link com.mfh.comna.actionbar.ActionBar#addItem(com.mfh.comna.actionbar.ActionBarItem, int)}
*/
public static final int NONE = 0;
/**
* The Type specifies the layout of the ActionBar.
*
* @author Cyril Mottier
*/
public enum Type {
/**
* ActionBar layout will contain a home item on the left and optional
* {@link com.mfh.comna.actionbar.ActionBarItem}s on the right. The space that left between is
* used to display the title of the current Activity.
*/
Normal,
/**
* ActionBar layout will contain the application Drawable on the left
* and optional {@link com.mfh.comna.actionbar.ActionBarItem}s on the right. Please note the
* Dashboard type does not display the title of the current Activity.
*
* @see R.attr#gdActionBarApplicationDrawable
*/
Dashboard,
/**
* ActionBar layout will contain optional {@link com.mfh.comna.actionbar.ActionBarItem}s on the
* right. The space that left will be used to display the title of the
* current Activity.
*/
Empty
}
/**
* Interface definition for a callback to be invoked when a user is
* interacting with an {@link com.mfh.comna.actionbar.ActionBar}.
*
* @author Cyril Mottier
*/
public interface OnActionBarListener {
/**
* Index used to indicate the ActionBar home item has been clicked.
*/
int HOME_ITEM = -1;
/**
* Clients may listen to this method in order to be notified the user
* has clicked on an item.
*
* @param position The position of the item in the action bar.
* {@link com.mfh.comna.actionbar.BaseActionBar.OnActionBarListener#HOME_ITEM} means the user
* pressed the "Home" button. 0 means the user clicked the
* first {@link com.mfh.comna.actionbar.ActionBarItem} (the leftmost item) and so on.
*/
void onActionBarItemClicked(int position);
}
//private TextView mTitleView;
private ImageButton mHomeButton;
private boolean mMerging = false;
//private CharSequence mTitle;
protected Type mType;
private OnActionBarListener mOnActionBarListener;
private LinkedList<ActionBarItem> mItems;
private Drawable mDividerDrawable;
private Drawable mHomeDrawable;
private int mDividerWidth;
private int mMaxItemsCount;
public BaseActionBar(Context context) {
this(context, null);
}
public BaseActionBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.gdActionBarStyle);
}
protected void otherInit (TypedArray a) {
;
}
/**
* 获取actionbar layout资源文件
* @return
* @author zhangyz created on 2013-4-10
*/
protected abstract int getLayoutId(TypedArray a);
public BaseActionBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
initActionBar();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar, defStyle, 0);
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 = getLayoutId(a);
// 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);
otherInit(a);
mMerging = false;
a.recycle();
}
private void initActionBar() {
mItems = new LinkedList<ActionBarItem>();
}
public ImageButton getmHomeButton() {
return mHomeButton;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (!mMerging) {
switch (mType) {
/*case Dashboard:
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);
if (mHomeButton != null) {
mHomeButton.setOnClickListener(mClickHandler);
mHomeButton.setImageDrawable(mHomeDrawable);
mHomeButton.setContentDescription(getContext().getString(R.string.gd_go_home));
}
break;
}
}
}
/**
* Register a callback to be invoked when the user interacts with the
* {@link com.mfh.comna.actionbar.ActionBar}.
*
* @param listener The callback that will run.
*/
public void setOnActionBarListener(OnActionBarListener listener) {
mOnActionBarListener = listener;
}
/**
* @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
*/
@SuppressWarnings("deprecation")
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 LayoutParams lp = new LayoutParams(dividerWidth, LayoutParams.MATCH_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.MATCH_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;
}*/
layoutId = R.layout.gd_action_bar_normal;
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;
}
}
}
}
};
}