ActionBarContextView.java revision dcdefbbff2bfecbfeb7b6459de130f376595c590
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.internal.widget; 17 18import com.android.internal.R; 19import com.android.internal.app.ActionBarImpl; 20 21import android.app.ActionBar; 22import android.content.Context; 23import android.content.res.TypedArray; 24import android.graphics.drawable.Drawable; 25import android.util.AttributeSet; 26import android.view.LayoutInflater; 27import android.view.Menu; 28import android.view.MenuItem; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.View.MeasureSpec; 32import android.view.ViewGroup.LayoutParams; 33import android.widget.ImageButton; 34import android.widget.LinearLayout; 35import android.widget.TextView; 36 37/** 38 * @hide 39 */ 40public class ActionBarContextView extends ViewGroup { 41 // TODO: This must be defined in the default theme 42 private static final int CONTENT_HEIGHT_DIP = 50; 43 44 private int mItemPadding; 45 private int mItemMargin; 46 private int mContentHeight; 47 48 private CharSequence mTitle; 49 private CharSequence mSubtitle; 50 51 private ImageButton mCloseButton; 52 private View mCustomView; 53 private LinearLayout mTitleLayout; 54 private TextView mTitleView; 55 private TextView mSubtitleView; 56 private Drawable mCloseDrawable; 57 58 public ActionBarContextView(Context context) { 59 this(context, null, 0); 60 } 61 62 public ActionBarContextView(Context context, AttributeSet attrs) { 63 this(context, attrs, 0); 64 } 65 66 public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) { 67 super(context, attrs, defStyle); 68 69 TypedArray a = context.obtainStyledAttributes(attrs, 70 com.android.internal.R.styleable.Theme); 71 mItemPadding = a.getDimensionPixelOffset( 72 com.android.internal.R.styleable.Theme_actionButtonPadding, 0); 73 setBackgroundDrawable(a.getDrawable( 74 com.android.internal.R.styleable.Theme_actionBarContextBackground)); 75 mCloseDrawable = a.getDrawable( 76 com.android.internal.R.styleable.Theme_actionBarCloseContextDrawable); 77 mItemMargin = mItemPadding / 2; 78 79 mContentHeight = 80 (int) (CONTENT_HEIGHT_DIP * getResources().getDisplayMetrics().density + 0.5f); 81 a.recycle(); 82 } 83 84 public void setCustomView(View view) { 85 if (mCustomView != null) { 86 removeView(mCustomView); 87 } 88 mCustomView = view; 89 if (mTitleLayout != null) { 90 removeView(mTitleLayout); 91 mTitleLayout = null; 92 } 93 if (view != null) { 94 addView(view); 95 } 96 requestLayout(); 97 } 98 99 public void setTitle(CharSequence title) { 100 mTitle = title; 101 initTitle(); 102 } 103 104 public void setSubtitle(CharSequence subtitle) { 105 mSubtitle = subtitle; 106 initTitle(); 107 } 108 109 public CharSequence getTitle() { 110 return mTitle; 111 } 112 113 public CharSequence getSubtitle() { 114 return mSubtitle; 115 } 116 117 private void initTitle() { 118 if (mTitleLayout == null) { 119 LayoutInflater inflater = LayoutInflater.from(getContext()); 120 mTitleLayout = (LinearLayout) inflater.inflate(R.layout.action_bar_title_item, null); 121 mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title); 122 mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle); 123 if (mTitle != null) { 124 mTitleView.setText(mTitle); 125 } 126 if (mSubtitle != null) { 127 mSubtitleView.setText(mSubtitle); 128 } 129 addView(mTitleLayout); 130 } else { 131 mTitleView.setText(mTitle); 132 mSubtitleView.setText(mSubtitle); 133 if (mTitleLayout.getParent() == null) { 134 addView(mTitleLayout); 135 } 136 } 137 } 138 139 public void initForMode(final ActionBar.ContextMode mode) { 140 final ActionBarImpl.ContextMode implMode = (ActionBarImpl.ContextMode) mode; 141 142 if (mCloseButton == null) { 143 mCloseButton = new ImageButton(getContext()); 144 mCloseButton.setImageDrawable(mCloseDrawable); 145 mCloseButton.setBackgroundDrawable(null); 146 mCloseButton.setOnClickListener(new OnClickListener() { 147 public void onClick(View v) { 148 mode.finish(); 149 } 150 }); 151 } 152 addView(mCloseButton); 153 154 final Context context = getContext(); 155 final Menu menu = mode.getMenu(); 156 final int itemCount = menu.size(); 157 for (int i = 0; i < itemCount; i++) { 158 final MenuItem item = menu.getItem(i); 159 final ImageButton button = new ImageButton(context, null, 160 com.android.internal.R.attr.actionButtonStyle); 161 button.setClickable(true); 162 button.setFocusable(true); 163 button.setImageDrawable(item.getIcon()); 164 button.setId(item.getItemId()); 165 button.setVisibility(item.isVisible() ? VISIBLE : GONE); 166 button.setEnabled(item.isEnabled()); 167 168 button.setOnClickListener(new OnClickListener() { 169 public void onClick(View v) { 170 implMode.dispatchOnContextItemClicked(item); 171 } 172 }); 173 174 addView(button); 175 } 176 requestLayout(); 177 } 178 179 public void closeMode() { 180 removeAllViews(); 181 mCustomView = null; 182 } 183 184 @Override 185 protected LayoutParams generateDefaultLayoutParams() { 186 // Used by custom views if they don't supply layout params. Everything else 187 // added to an ActionBarContextView should have them already. 188 return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 189 } 190 191 @Override 192 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 193 final int widthMode = MeasureSpec.getMode(widthMeasureSpec); 194 if (widthMode != MeasureSpec.EXACTLY) { 195 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 196 "with android:layout_width=\"match_parent\" (or fill_parent)"); 197 } 198 199 final int heightMode = MeasureSpec.getMode(heightMeasureSpec); 200 if (heightMode != MeasureSpec.AT_MOST) { 201 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 202 "with android:layout_height=\"wrap_content\""); 203 } 204 205 final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 206 final int itemMargin = mItemPadding; 207 208 int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); 209 final int height = mContentHeight - getPaddingTop() - getPaddingBottom(); 210 final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); 211 212 if (mCloseButton != null) { 213 availableWidth = measureChildView(mCloseButton, availableWidth, 214 childSpecHeight, itemMargin); 215 } 216 217 if (mTitleLayout != null && mCustomView == null) { 218 availableWidth = measureChildView(mTitleLayout, availableWidth, 219 childSpecHeight, itemMargin); 220 } 221 222 final int childCount = getChildCount(); 223 for (int i = 0; i < childCount; i++) { 224 final View child = getChildAt(i); 225 if (child == mCloseButton || child == mTitleLayout || child == mCustomView) { 226 continue; 227 } 228 229 availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin); 230 } 231 232 if (mCustomView != null) { 233 LayoutParams lp = mCustomView.getLayoutParams(); 234 final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? 235 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 236 final int customWidth = lp.width >= 0 ? 237 Math.min(lp.width, availableWidth) : availableWidth; 238 final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? 239 MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; 240 final int customHeight = lp.height >= 0 ? 241 Math.min(lp.height, height) : height; 242 mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode), 243 MeasureSpec.makeMeasureSpec(customHeight, customHeightMode)); 244 } 245 246 setMeasuredDimension(contentWidth, mContentHeight); 247 } 248 249 @Override 250 protected void onLayout(boolean changed, int l, int t, int r, int b) { 251 int x = getPaddingLeft(); 252 final int y = getPaddingTop(); 253 final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); 254 final int itemMargin = mItemPadding; 255 256 if (mCloseButton != null && mCloseButton.getVisibility() != GONE) { 257 x += positionChild(mCloseButton, x, y, contentHeight); 258 } 259 260 if (mTitleLayout != null && mCustomView == null) { 261 x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin; 262 } 263 264 if (mCustomView != null) { 265 x += positionChild(mCustomView, x, y, contentHeight) + itemMargin; 266 } 267 268 x = r - l - getPaddingRight(); 269 270 final int childCount = getChildCount(); 271 for (int i = 0; i < childCount; i++) { 272 final View child = getChildAt(i); 273 if (child == mCloseButton || child == mTitleLayout || child == mCustomView) { 274 continue; 275 } 276 277 x -= positionChildInverse(child, x, y, contentHeight) + itemMargin; 278 } 279 } 280 281 private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) { 282 child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), 283 childSpecHeight); 284 285 availableWidth -= child.getMeasuredWidth(); 286 availableWidth -= spacing; 287 288 return availableWidth; 289 } 290 291 private int positionChild(View child, int x, int y, int contentHeight) { 292 int childWidth = child.getMeasuredWidth(); 293 int childHeight = child.getMeasuredHeight(); 294 int childTop = y + (contentHeight - childHeight) / 2; 295 296 child.layout(x, childTop, x + childWidth, childTop + childHeight); 297 298 return childWidth; 299 } 300 301 private int positionChildInverse(View child, int x, int y, int contentHeight) { 302 int childWidth = child.getMeasuredWidth(); 303 int childHeight = child.getMeasuredHeight(); 304 int childTop = y + (contentHeight - childHeight) / 2; 305 306 child.layout(x - childWidth, childTop, x, childTop + childHeight); 307 308 return childWidth; 309 } 310} 311