/ABSherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java
Java | 248 lines | 173 code | 26 blank | 49 comment | 56 complexity | b285683bfbab61431c15e186499a53bb MD5 | raw file
1package com.actionbarsherlock.internal.widget;
2
3import android.content.Context;
4import android.content.res.TypedArray;
5import android.graphics.Canvas;
6import android.graphics.drawable.Drawable;
7import android.util.AttributeSet;
8import android.view.View;
9import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
10
11/**
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.
17 */
18public 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,
23 };
24 private static final int LinearLayout_divider = 0;
25 private static final int LinearLayout_showDividers = 1;
26 private static final int LinearLayout_dividerPadding = 2;
27
28 /**
29 * Don't show any dividers.
30 */
31 public static final int SHOW_DIVIDER_NONE = 0;
32 /**
33 * Show a divider at the beginning of the group.
34 */
35 public static final int SHOW_DIVIDER_BEGINNING = 1;
36 /**
37 * Show dividers between each item in the group.
38 */
39 public static final int SHOW_DIVIDER_MIDDLE = 2;
40 /**
41 * Show a divider at the end of the group.
42 */
43 public static final int SHOW_DIVIDER_END = 4;
44
45
46 private Drawable mDivider;
47 private int mDividerWidth;
48 private int mDividerHeight;
49 private int mShowDividers;
50 private int mDividerPadding;
51
52
53 public IcsLinearLayout(Context context, AttributeSet attrs) {
54 super(context, attrs);
55
56 TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/LinearLayout);
57
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);
61
62 a.recycle();
63 }
64
65 /**
66 * Set how dividers should be shown between items in this layout
67 *
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.
71 */
72 public void setShowDividers(int showDividers) {
73 if (showDividers != mShowDividers) {
74 requestLayout();
75 invalidate(); //XXX This is required if you are toggling a divider off
76 }
77 mShowDividers = showDividers;
78 }
79
80 /**
81 * @return A flag set indicating how dividers should be shown around items.
82 * @see #setShowDividers(int)
83 */
84 public int getShowDividers() {
85 return mShowDividers;
86 }
87
88 /**
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)
92 */
93 public void setDividerDrawable(Drawable divider) {
94 if (divider == mDivider) {
95 return;
96 }
97 mDivider = divider;
98 if (divider != null) {
99 mDividerWidth = divider.getIntrinsicWidth();
100 mDividerHeight = divider.getIntrinsicHeight();
101 } else {
102 mDividerWidth = 0;
103 mDividerHeight = 0;
104 }
105 setWillNotDraw(divider == null);
106 requestLayout();
107 }
108
109 /**
110 * Get the width of the current divider drawable.
111 *
112 * @hide Used internally by framework.
113 */
114 public int getDividerWidth() {
115 return mDividerWidth;
116 }
117
118 @Override
119 protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
120 final int index = indexOfChild(child);
121 final int orientation = getOrientation();
122 final LayoutParams params = (LayoutParams) child.getLayoutParams();
123 if (hasDividerBeforeChildAt(index)) {
124 if (orientation == VERTICAL) {
125 //Account for the divider by pushing everything up
126 params.topMargin = mDividerHeight;
127 } else {
128 //Account for the divider by pushing everything left
129 params.leftMargin = mDividerWidth;
130 }
131 }
132
133 final int count = getChildCount();
134 if (index == count - 1) {
135 if (hasDividerBeforeChildAt(count)) {
136 if (orientation == VERTICAL) {
137 params.bottomMargin = mDividerHeight;
138 } else {
139 params.rightMargin = mDividerWidth;
140 }
141 }
142 }
143 super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
144 }
145
146 @Override
147 protected void onDraw(Canvas canvas) {
148 if (mDivider != null) {
149 if (getOrientation() == VERTICAL) {
150 drawDividersVertical(canvas);
151 } else {
152 drawDividersHorizontal(canvas);
153 }
154 }
155 super.onDraw(canvas);
156 }
157
158 void drawDividersVertical(Canvas canvas) {
159 final int count = getChildCount();
160 for (int i = 0; i < count; i++) {
161 final View child = getChildAt(i);
162
163 if (child != null && child.getVisibility() != GONE) {
164 if (hasDividerBeforeChildAt(i)) {
165 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
166 final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
167 drawHorizontalDivider(canvas, top);
168 }
169 }
170 }
171
172 if (hasDividerBeforeChildAt(count)) {
173 final View child = getChildAt(count - 1);
174 int bottom = 0;
175 if (child == null) {
176 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
177 } else {
178 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
179 bottom = child.getBottom()/* + lp.bottomMargin*/;
180 }
181 drawHorizontalDivider(canvas, bottom);
182 }
183 }
184
185 void drawDividersHorizontal(Canvas canvas) {
186 final int count = getChildCount();
187 for (int i = 0; i < count; i++) {
188 final View child = getChildAt(i);
189
190 if (child != null && child.getVisibility() != GONE) {
191 if (hasDividerBeforeChildAt(i)) {
192 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
193 final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
194 drawVerticalDivider(canvas, left);
195 }
196 }
197 }
198
199 if (hasDividerBeforeChildAt(count)) {
200 final View child = getChildAt(count - 1);
201 int right = 0;
202 if (child == null) {
203 right = getWidth() - getPaddingRight() - mDividerWidth;
204 } else {
205 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
206 right = child.getRight()/* + lp.rightMargin*/;
207 }
208 drawVerticalDivider(canvas, right);
209 }
210 }
211
212 void drawHorizontalDivider(Canvas canvas, int top) {
213 mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
214 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
215 mDivider.draw(canvas);
216 }
217
218 void drawVerticalDivider(Canvas canvas, int left) {
219 mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
220 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
221 mDivider.draw(canvas);
222 }
223
224 /**
225 * Determines where to position dividers between children.
226 *
227 * @param childIndex Index of child to check for preceding divider
228 * @return true if there should be a divider before the child at childIndex
229 * @hide Pending API consideration. Currently only used internally by the system.
230 */
231 protected boolean hasDividerBeforeChildAt(int childIndex) {
232 if (childIndex == 0) {
233 return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
234 } else if (childIndex == getChildCount()) {
235 return (mShowDividers & SHOW_DIVIDER_END) != 0;
236 } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
237 boolean hasVisibleViewBefore = false;
238 for (int i = childIndex - 1; i >= 0; i--) {
239 if (getChildAt(i).getVisibility() != GONE) {
240 hasVisibleViewBefore = true;
241 break;
242 }
243 }
244 return hasVisibleViewBefore;
245 }
246 return false;
247 }
248}