1 package com
.actionbarsherlock
.internal
.widget
;
3 import android
.content
.Context
;
4 import android
.content
.res
.TypedArray
;
5 import android
.graphics
.Canvas
;
6 import android
.graphics
.drawable
.Drawable
;
7 import android
.util
.AttributeSet
;
8 import android
.view
.View
;
9 import android
.widget
.LinearLayout
;
11 import com
.actionbarsherlock
.internal
.nineoldandroids
.widget
.NineLinearLayout
;
14 * A simple extension of a regular linear layout that supports the divider API
15 * of Android 4.0+. The dividers are added adjacent to the children by changing
16 * their layout params. If you need to rely on the margins which fall in the
17 * same orientation as the layout you should wrap the child in a simple
18 * {@link android.widget.FrameLayout} so it can receive the margin.
20 public class IcsLinearLayout
extends NineLinearLayout
{
21 private static final int[] R_styleable_LinearLayout
= new int[] {
22 /* 0 */ android
.R
.attr
.divider
,
23 /* 1 */ android
.R
.attr
.measureWithLargestChild
,
24 /* 2 */ android
.R
.attr
.showDividers
,
25 /* 3 */ android
.R
.attr
.dividerPadding
,
27 private static final int LinearLayout_divider
= 0;
28 private static final int LinearLayout_measureWithLargestChild
= 1;
29 private static final int LinearLayout_showDividers
= 2;
30 private static final int LinearLayout_dividerPadding
= 3;
33 * Don't show any dividers.
35 public static final int SHOW_DIVIDER_NONE
= 0;
37 * Show a divider at the beginning of the group.
39 public static final int SHOW_DIVIDER_BEGINNING
= 1;
41 * Show dividers between each item in the group.
43 public static final int SHOW_DIVIDER_MIDDLE
= 2;
45 * Show a divider at the end of the group.
47 public static final int SHOW_DIVIDER_END
= 4;
50 private Drawable mDivider
;
51 private int mDividerWidth
;
52 private int mDividerHeight
;
53 private int mShowDividers
;
54 private int mDividerPadding
;
56 private boolean mUseLargestChild
;
58 public IcsLinearLayout(Context context
, AttributeSet attrs
) {
59 super(context
, attrs
);
61 TypedArray a
= context
.obtainStyledAttributes(attrs
, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout
);
63 setDividerDrawable(a
.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider
));
64 mShowDividers
= a
.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers
, SHOW_DIVIDER_NONE
);
65 mDividerPadding
= a
.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding
, 0);
66 mUseLargestChild
= a
.getBoolean(/*com.android.internal.R.styleable.*/LinearLayout_measureWithLargestChild
, false
);
72 * Set how dividers should be shown between items in this layout
74 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
75 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
76 * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
78 public void setShowDividers(int showDividers
) {
79 if (showDividers
!= mShowDividers
) {
81 invalidate(); //XXX This is required if you are toggling a divider off
83 mShowDividers
= showDividers
;
87 * @return A flag set indicating how dividers should be shown around items.
88 * @see #setShowDividers(int)
90 public int getShowDividers() {
95 * Set a drawable to be used as a divider between items.
96 * @param divider Drawable that will divide each item.
97 * @see #setShowDividers(int)
99 public void setDividerDrawable(Drawable divider
) {
100 if (divider
== mDivider
) {
104 if (divider
!= null
) {
105 mDividerWidth
= divider
.getIntrinsicWidth();
106 mDividerHeight
= divider
.getIntrinsicHeight();
111 setWillNotDraw(divider
== null
);
116 * Set padding displayed on both ends of dividers.
118 * @param padding Padding value in pixels that will be applied to each end
120 * @see #setShowDividers(int)
121 * @see #setDividerDrawable(Drawable)
122 * @see #getDividerPadding()
124 public void setDividerPadding(int padding
) {
125 mDividerPadding
= padding
;
129 * Get the padding size used to inset dividers in pixels
131 * @see #setShowDividers(int)
132 * @see #setDividerDrawable(Drawable)
133 * @see #setDividerPadding(int)
135 public int getDividerPadding() {
136 return mDividerPadding
;
140 * Get the width of the current divider drawable.
142 * @hide Used internally by framework.
144 public int getDividerWidth() {
145 return mDividerWidth
;
149 protected void measureChildWithMargins(View child
, int parentWidthMeasureSpec
, int widthUsed
, int parentHeightMeasureSpec
, int heightUsed
) {
150 final int index
= indexOfChild(child
);
151 final int orientation
= getOrientation();
152 final LayoutParams params
= (LayoutParams
) child
.getLayoutParams();
153 if (hasDividerBeforeChildAt(index
)) {
154 if (orientation
== VERTICAL
) {
155 //Account for the divider by pushing everything up
156 params
.topMargin
= mDividerHeight
;
158 //Account for the divider by pushing everything left
159 params
.leftMargin
= mDividerWidth
;
163 final int count
= getChildCount();
164 if (index
== count
- 1) {
165 if (hasDividerBeforeChildAt(count
)) {
166 if (orientation
== VERTICAL
) {
167 params
.bottomMargin
= mDividerHeight
;
169 params
.rightMargin
= mDividerWidth
;
173 super.measureChildWithMargins(child
, parentWidthMeasureSpec
, widthUsed
, parentHeightMeasureSpec
, heightUsed
);
177 protected void onDraw(Canvas canvas
) {
178 if (mDivider
!= null
) {
179 if (getOrientation() == VERTICAL
) {
180 drawDividersVertical(canvas
);
182 drawDividersHorizontal(canvas
);
185 super.onDraw(canvas
);
188 void drawDividersVertical(Canvas canvas
) {
189 final int count
= getChildCount();
190 for (int i
= 0; i
< count
; i
++) {
191 final View child
= getChildAt(i
);
193 if (child
!= null
&& child
.getVisibility() != GONE
) {
194 if (hasDividerBeforeChildAt(i
)) {
195 final LayoutParams lp
= (LayoutParams
) child
.getLayoutParams();
196 final int top
= child
.getTop() - lp
.topMargin
/* - mDividerHeight*/;
197 drawHorizontalDivider(canvas
, top
);
202 if (hasDividerBeforeChildAt(count
)) {
203 final View child
= getChildAt(count
- 1);
206 bottom
= getHeight() - getPaddingBottom() - mDividerHeight
;
208 //final LayoutParams lp = (LayoutParams) child.getLayoutParams();
209 bottom
= child
.getBottom()/* + lp.bottomMargin*/;
211 drawHorizontalDivider(canvas
, bottom
);
215 void drawDividersHorizontal(Canvas canvas
) {
216 final int count
= getChildCount();
217 for (int i
= 0; i
< count
; i
++) {
218 final View child
= getChildAt(i
);
220 if (child
!= null
&& child
.getVisibility() != GONE
) {
221 if (hasDividerBeforeChildAt(i
)) {
222 final LayoutParams lp
= (LayoutParams
) child
.getLayoutParams();
223 final int left
= child
.getLeft() - lp
.leftMargin
/* - mDividerWidth*/;
224 drawVerticalDivider(canvas
, left
);
229 if (hasDividerBeforeChildAt(count
)) {
230 final View child
= getChildAt(count
- 1);
233 right
= getWidth() - getPaddingRight() - mDividerWidth
;
235 //final LayoutParams lp = (LayoutParams) child.getLayoutParams();
236 right
= child
.getRight()/* + lp.rightMargin*/;
238 drawVerticalDivider(canvas
, right
);
242 void drawHorizontalDivider(Canvas canvas
, int top
) {
243 mDivider
.setBounds(getPaddingLeft() + mDividerPadding
, top
,
244 getWidth() - getPaddingRight() - mDividerPadding
, top
+ mDividerHeight
);
245 mDivider
.draw(canvas
);
248 void drawVerticalDivider(Canvas canvas
, int left
) {
249 mDivider
.setBounds(left
, getPaddingTop() + mDividerPadding
,
250 left
+ mDividerWidth
, getHeight() - getPaddingBottom() - mDividerPadding
);
251 mDivider
.draw(canvas
);
255 * Determines where to position dividers between children.
257 * @param childIndex Index of child to check for preceding divider
258 * @return true if there should be a divider before the child at childIndex
259 * @hide Pending API consideration. Currently only used internally by the system.
261 protected boolean hasDividerBeforeChildAt(int childIndex
) {
262 if (childIndex
== 0) {
263 return (mShowDividers
& SHOW_DIVIDER_BEGINNING
) != 0;
264 } else if (childIndex
== getChildCount()) {
265 return (mShowDividers
& SHOW_DIVIDER_END
) != 0;
266 } else if ((mShowDividers
& SHOW_DIVIDER_MIDDLE
) != 0) {
267 boolean hasVisibleViewBefore
= false
;
268 for (int i
= childIndex
- 1; i
>= 0; i
--) {
269 if (getChildAt(i
).getVisibility() != GONE
) {
270 hasVisibleViewBefore
= true
;
274 return hasVisibleViewBefore
;
280 * When true, all children with a weight will be considered having
281 * the minimum size of the largest child. If false, all children are
284 * @return True to measure children with a weight using the minimum
285 * size of the largest child, false otherwise.
287 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
289 public boolean isMeasureWithLargestChildEnabled() {
290 return mUseLargestChild
;
294 * When set to true, all children with a weight will be considered having
295 * the minimum size of the largest child. If false, all children are
298 * Disabled by default.
300 * @param enabled True to measure children with a weight using the
301 * minimum size of the largest child, false otherwise.
303 * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
305 public void setMeasureWithLargestChildEnabled(boolean enabled
) {
306 mUseLargestChild
= enabled
;
310 protected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {
311 super.onMeasure(widthMeasureSpec
, heightMeasureSpec
);
313 if (mUseLargestChild
) {
314 final int orientation
= getOrientation();
315 switch (orientation
) {
317 useLargestChildHorizontal();
321 useLargestChildVertical();
327 private void useLargestChildHorizontal() {
328 final int childCount
= getChildCount();
330 // Find largest child width
331 int largestChildWidth
= 0;
332 for (int i
= 0; i
< childCount
; i
++) {
333 final View child
= getChildAt(i
);
334 largestChildWidth
= Math
.max(child
.getMeasuredWidth(), largestChildWidth
);
339 for (int i
= 0; i
< childCount
; i
++) {
340 final View child
= getChildAt(i
);
342 if (child
== null
|| child
.getVisibility() == View
.GONE
) {
346 final LinearLayout
.LayoutParams lp
=
347 (LinearLayout
.LayoutParams
) child
.getLayoutParams();
349 float childExtra
= lp
.weight
;
350 if (childExtra
> 0) {
352 MeasureSpec
.makeMeasureSpec(largestChildWidth
,
353 MeasureSpec
.EXACTLY
),
354 MeasureSpec
.makeMeasureSpec(child
.getMeasuredHeight(),
355 MeasureSpec
.EXACTLY
));
356 totalWidth
+= largestChildWidth
;
359 totalWidth
+= child
.getMeasuredWidth();
362 totalWidth
+= lp
.leftMargin
+ lp
.rightMargin
;
365 totalWidth
+= getPaddingLeft() + getPaddingRight();
366 setMeasuredDimension(totalWidth
, getMeasuredHeight());
369 private void useLargestChildVertical() {
370 final int childCount
= getChildCount();
372 // Find largest child width
373 int largestChildHeight
= 0;
374 for (int i
= 0; i
< childCount
; i
++) {
375 final View child
= getChildAt(i
);
376 largestChildHeight
= Math
.max(child
.getMeasuredHeight(), largestChildHeight
);
381 for (int i
= 0; i
< childCount
; i
++) {
382 final View child
= getChildAt(i
);
384 if (child
== null
|| child
.getVisibility() == View
.GONE
) {
388 final LinearLayout
.LayoutParams lp
=
389 (LinearLayout
.LayoutParams
) child
.getLayoutParams();
391 float childExtra
= lp
.weight
;
392 if (childExtra
> 0) {
394 MeasureSpec
.makeMeasureSpec(child
.getMeasuredWidth(),
395 MeasureSpec
.EXACTLY
),
396 MeasureSpec
.makeMeasureSpec(largestChildHeight
,
397 MeasureSpec
.EXACTLY
));
398 totalHeight
+= largestChildHeight
;
401 totalHeight
+= child
.getMeasuredHeight();
404 totalHeight
+= lp
.leftMargin
+ lp
.rightMargin
;
407 totalHeight
+= getPaddingLeft() + getPaddingRight();
408 setMeasuredDimension(getMeasuredWidth(), totalHeight
);