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 com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
12 * A simple extension of a regular linear layout that supports the divider API
13 * of Android 4.0+. The dividers are added adjacent to the children by changing
14 * their layout params. If you need to rely on the margins which fall in the
15 * same orientation as the layout you should wrap the child in a simple
16 * {@link android.widget.FrameLayout} so it can receive the margin.
18 public class IcsLinearLayout extends NineLinearLayout {
19 private static final int[] LinearLayout = new int[] {
20 /* 0 */ android.R.attr.divider,
21 /* 1 */ android.R.attr.showDividers,
22 /* 2 */ android.R.attr.dividerPadding,
24 private static final int LinearLayout_divider = 0;
25 private static final int LinearLayout_showDividers = 1;
26 private static final int LinearLayout_dividerPadding = 2;
29 * Don't show any dividers.
31 public static final int SHOW_DIVIDER_NONE = 0;
33 * Show a divider at the beginning of the group.
35 public static final int SHOW_DIVIDER_BEGINNING = 1;
37 * Show dividers between each item in the group.
39 public static final int SHOW_DIVIDER_MIDDLE = 2;
41 * Show a divider at the end of the group.
43 public static final int SHOW_DIVIDER_END = 4;
46 private Drawable mDivider;
47 private int mDividerWidth;
48 private int mDividerHeight;
49 private int mShowDividers;
50 private int mDividerPadding;
53 public IcsLinearLayout(Context context, AttributeSet attrs) {
54 super(context, attrs);
56 TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/LinearLayout);
58 setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
59 mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
60 mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
66 * Set how dividers should be shown between items in this layout
68 * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
69 * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
70 * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
72 public void setShowDividers(int showDividers) {
73 if (showDividers != mShowDividers) {
75 invalidate(); //XXX This is required if you are toggling a divider off
77 mShowDividers = showDividers;
81 * @return A flag set indicating how dividers should be shown around items.
82 * @see #setShowDividers(int)
84 public int getShowDividers() {
89 * Set a drawable to be used as a divider between items.
90 * @param divider Drawable that will divide each item.
91 * @see #setShowDividers(int)
93 public void setDividerDrawable(Drawable divider) {
94 if (divider == mDivider) {
98 if (divider != null) {
99 mDividerWidth = divider.getIntrinsicWidth();
100 mDividerHeight = divider.getIntrinsicHeight();
105 setWillNotDraw(divider == null);
110 * Set padding displayed on both ends of dividers.
112 * @param padding Padding value in pixels that will be applied to each end
114 * @see #setShowDividers(int)
115 * @see #setDividerDrawable(Drawable)
116 * @see #getDividerPadding()
118 public void setDividerPadding(int padding) {
119 mDividerPadding = padding;
123 * Get the padding size used to inset dividers in pixels
125 * @see #setShowDividers(int)
126 * @see #setDividerDrawable(Drawable)
127 * @see #setDividerPadding(int)
129 public int getDividerPadding() {
130 return mDividerPadding;
134 * Get the width of the current divider drawable.
136 * @hide Used internally by framework.
138 public int getDividerWidth() {
139 return mDividerWidth;
143 protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
144 final int index = indexOfChild(child);
145 final int orientation = getOrientation();
146 final LayoutParams params = (LayoutParams) child.getLayoutParams();
147 if (hasDividerBeforeChildAt(index)) {
148 if (orientation == VERTICAL) {
149 //Account for the divider by pushing everything up
150 params.topMargin = mDividerHeight;
152 //Account for the divider by pushing everything left
153 params.leftMargin = mDividerWidth;
157 final int count = getChildCount();
158 if (index == count - 1) {
159 if (hasDividerBeforeChildAt(count)) {
160 if (orientation == VERTICAL) {
161 params.bottomMargin = mDividerHeight;
163 params.rightMargin = mDividerWidth;
167 super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
171 protected void onDraw(Canvas canvas) {
172 if (mDivider != null) {
173 if (getOrientation() == VERTICAL) {
174 drawDividersVertical(canvas);
176 drawDividersHorizontal(canvas);
179 super.onDraw(canvas);
182 void drawDividersVertical(Canvas canvas) {
183 final int count = getChildCount();
184 for (int i = 0; i < count; i++) {
185 final View child = getChildAt(i);
187 if (child != null && child.getVisibility() != GONE) {
188 if (hasDividerBeforeChildAt(i)) {
189 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
190 final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
191 drawHorizontalDivider(canvas, top);
196 if (hasDividerBeforeChildAt(count)) {
197 final View child = getChildAt(count - 1);
200 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
202 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
203 bottom = child.getBottom()/* + lp.bottomMargin*/;
205 drawHorizontalDivider(canvas, bottom);
209 void drawDividersHorizontal(Canvas canvas) {
210 final int count = getChildCount();
211 for (int i = 0; i < count; i++) {
212 final View child = getChildAt(i);
214 if (child != null && child.getVisibility() != GONE) {
215 if (hasDividerBeforeChildAt(i)) {
216 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
217 final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
218 drawVerticalDivider(canvas, left);
223 if (hasDividerBeforeChildAt(count)) {
224 final View child = getChildAt(count - 1);
227 right = getWidth() - getPaddingRight() - mDividerWidth;
229 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
230 right = child.getRight()/* + lp.rightMargin*/;
232 drawVerticalDivider(canvas, right);
236 void drawHorizontalDivider(Canvas canvas, int top) {
237 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
238 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
239 mDivider.draw(canvas);
242 void drawVerticalDivider(Canvas canvas, int left) {
243 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
244 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
245 mDivider.draw(canvas);
249 * Determines where to position dividers between children.
251 * @param childIndex Index of child to check for preceding divider
252 * @return true if there should be a divider before the child at childIndex
253 * @hide Pending API consideration. Currently only used internally by the system.
255 protected boolean hasDividerBeforeChildAt(int childIndex) {
256 if (childIndex == 0) {
257 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
258 } else if (childIndex == getChildCount()) {
259 return (mShowDividers & SHOW_DIVIDER_END) != 0;
260 } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
261 boolean hasVisibleViewBefore = false;
262 for (int i = childIndex - 1; i >= 0; i--) {
263 if (getChildAt(i).getVisibility() != GONE) {
264 hasVisibleViewBefore = true;
268 return hasVisibleViewBefore;