FragmentBreadCrumbspublic class FragmentBreadCrumbs extends android.view.ViewGroup implements FragmentManager.OnBackStackChangedListenerHelper class for showing "bread crumbs" representing the fragment
stack in an activity. This is intended to be used with
{@link ActionBar#setCustomView(View)
ActionBar.setCustomView(View)} to place the bread crumbs in
the action bar.
The default style for this view is
{@link android.R.style#Widget_FragmentBreadCrumbs}. |
Fields Summary |
---|
Activity | mActivity | android.view.LayoutInflater | mInflater | android.widget.LinearLayout | mContainer | int | mMaxVisible | BackStackRecord | mTopEntry | BackStackRecord | mParentEntry | private OnClickListener | mParentClickListenerListener to inform when a parent entry is clicked | private OnBreadCrumbClickListener | mOnBreadCrumbClickListener | private int | mGravity | private int | mLayoutResId | private int | mTextColor | private static final int | DEFAULT_GRAVITY | private OnClickListener | mOnClickListener |
Constructors Summary |
---|
public FragmentBreadCrumbs(android.content.Context context)
this(context, null);
| public FragmentBreadCrumbs(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, com.android.internal.R.attr.fragmentBreadCrumbsStyle);
| public FragmentBreadCrumbs(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
this(context, attrs, defStyleAttr, 0);
| public FragmentBreadCrumbs(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.FragmentBreadCrumbs, defStyleAttr, defStyleRes);
mGravity = a.getInt(com.android.internal.R.styleable.FragmentBreadCrumbs_gravity,
DEFAULT_GRAVITY);
mLayoutResId = a.getResourceId(
com.android.internal.R.styleable.FragmentBreadCrumbs_itemLayout,
com.android.internal.R.layout.fragment_bread_crumb_item);
mTextColor = a.getColor(
com.android.internal.R.styleable.FragmentBreadCrumbs_itemColor,
0);
a.recycle();
|
Methods Summary |
---|
private BackStackRecord | createBackStackEntry(java.lang.CharSequence title, java.lang.CharSequence shortTitle)
if (title == null) return null;
final BackStackRecord entry = new BackStackRecord(
(FragmentManagerImpl) mActivity.getFragmentManager());
entry.setBreadCrumbTitle(title);
entry.setBreadCrumbShortTitle(shortTitle);
return entry;
| private android.app.FragmentManager.BackStackEntry | getPreEntry(int index)Returns the pre-entry corresponding to the index. If there is a parent and a top entry
set, parent has an index of zero and top entry has an index of 1. Returns null if the
specified index doesn't exist or is null.
// If there's a parent entry, then return that for zero'th item, else top entry.
if (mParentEntry != null) {
return index == 0 ? mParentEntry : mTopEntry;
} else {
return mTopEntry;
}
| private int | getPreEntryCount()Returns the number of entries before the backstack, including the title of the current
fragment and any custom parent title that was set.
return (mTopEntry != null ? 1 : 0) + (mParentEntry != null ? 1 : 0);
| public void | onBackStackChanged()
updateCrumbs();
| protected void | onLayout(boolean changed, int l, int t, int r, int b)
// Eventually we should implement our own layout of the views, rather than relying on
// a single linear layout.
final int childCount = getChildCount();
if (childCount == 0) {
return;
}
final View child = getChildAt(0);
final int childTop = mPaddingTop;
final int childBottom = mPaddingTop + child.getMeasuredHeight() - mPaddingBottom;
int childLeft;
int childRight;
final int layoutDirection = getLayoutDirection();
final int horizontalGravity = mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
switch (Gravity.getAbsoluteGravity(horizontalGravity, layoutDirection)) {
case Gravity.RIGHT:
childRight = mRight - mLeft - mPaddingRight;
childLeft = childRight - child.getMeasuredWidth();
break;
case Gravity.CENTER_HORIZONTAL:
childLeft = mPaddingLeft + (mRight - mLeft - child.getMeasuredWidth()) / 2;
childRight = childLeft + child.getMeasuredWidth();
break;
case Gravity.LEFT:
default:
childLeft = mPaddingLeft;
childRight = childLeft + child.getMeasuredWidth();
break;
}
if (childLeft < mPaddingLeft) {
childLeft = mPaddingLeft;
}
if (childRight > mRight - mLeft - mPaddingRight) {
childRight = mRight - mLeft - mPaddingRight;
}
child.layout(childLeft, childTop, childRight, childBottom);
| protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec)
final int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
int measuredChildState = 0;
// Find rightmost and bottom-most child
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
measuredChildState = combineMeasuredStates(measuredChildState,
child.getMeasuredState());
}
}
// Account for padding too
maxWidth += mPaddingLeft + mPaddingRight;
maxHeight += mPaddingTop + mPaddingBottom;
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, measuredChildState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
measuredChildState<<MEASURED_HEIGHT_STATE_SHIFT));
| public void | setActivity(Activity a)Attach the bread crumbs to their activity. This must be called once
when creating the bread crumbs.
mActivity = a;
mInflater = (LayoutInflater)a.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContainer = (LinearLayout)mInflater.inflate(
com.android.internal.R.layout.fragment_bread_crumbs,
this, false);
addView(mContainer);
a.getFragmentManager().addOnBackStackChangedListener(this);
updateCrumbs();
setLayoutTransition(new LayoutTransition());
| public void | setMaxVisible(int visibleCrumbs)The maximum number of breadcrumbs to show. Older fragment headers will be hidden from view.
if (visibleCrumbs < 1) {
throw new IllegalArgumentException("visibleCrumbs must be greater than zero");
}
mMaxVisible = visibleCrumbs;
| public void | setOnBreadCrumbClickListener(android.app.FragmentBreadCrumbs$OnBreadCrumbClickListener listener)Sets a listener for clicks on the bread crumbs. This will be called before
the default click action is performed.
mOnBreadCrumbClickListener = listener;
| public void | setParentTitle(java.lang.CharSequence title, java.lang.CharSequence shortTitle, OnClickListener listener)Inserts an optional parent entry at the first position in the breadcrumbs. Selecting this
entry will result in a call to the specified listener's
{@link android.view.View.OnClickListener#onClick(View)}
method.
mParentEntry = createBackStackEntry(title, shortTitle);
mParentClickListener = listener;
updateCrumbs();
| public void | setTitle(java.lang.CharSequence title, java.lang.CharSequence shortTitle)Set a custom title for the bread crumbs. This will be the first entry
shown at the left, representing the root of the bread crumbs. If the
title is null, it will not be shown.
mTopEntry = createBackStackEntry(title, shortTitle);
updateCrumbs();
| void | updateCrumbs()
FragmentManager fm = mActivity.getFragmentManager();
int numEntries = fm.getBackStackEntryCount();
int numPreEntries = getPreEntryCount();
int numViews = mContainer.getChildCount();
for (int i = 0; i < numEntries + numPreEntries; i++) {
BackStackEntry bse = i < numPreEntries
? getPreEntry(i)
: fm.getBackStackEntryAt(i - numPreEntries);
if (i < numViews) {
View v = mContainer.getChildAt(i);
Object tag = v.getTag();
if (tag != bse) {
for (int j = i; j < numViews; j++) {
mContainer.removeViewAt(i);
}
numViews = i;
}
}
if (i >= numViews) {
final View item = mInflater.inflate(mLayoutResId, this, false);
final TextView text = (TextView) item.findViewById(com.android.internal.R.id.title);
text.setText(bse.getBreadCrumbTitle());
text.setTag(bse);
text.setTextColor(mTextColor);
if (i == 0) {
item.findViewById(com.android.internal.R.id.left_icon).setVisibility(View.GONE);
}
mContainer.addView(item);
text.setOnClickListener(mOnClickListener);
}
}
int viewI = numEntries + numPreEntries;
numViews = mContainer.getChildCount();
while (numViews > viewI) {
mContainer.removeViewAt(numViews - 1);
numViews--;
}
// Adjust the visibility and availability of the bread crumbs and divider
for (int i = 0; i < numViews; i++) {
final View child = mContainer.getChildAt(i);
// Disable the last one
child.findViewById(com.android.internal.R.id.title).setEnabled(i < numViews - 1);
if (mMaxVisible > 0) {
// Make only the last mMaxVisible crumbs visible
child.setVisibility(i < numViews - mMaxVisible ? View.GONE : View.VISIBLE);
final View leftIcon = child.findViewById(com.android.internal.R.id.left_icon);
// Remove the divider for all but the last mMaxVisible - 1
leftIcon.setVisibility(i > numViews - mMaxVisible && i != 0 ? View.VISIBLE
: View.GONE);
}
}
|
|