/ABSherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java

https://bitbucket.org/ayastrebov/android-actionbarsherlock · Java · 248 lines · 173 code · 26 blank · 49 comment · 56 complexity · b285683bfbab61431c15e186499a53bb MD5 · raw file

  1. package com.actionbarsherlock.internal.widget;
  2. import android.content.Context;
  3. import android.content.res.TypedArray;
  4. import android.graphics.Canvas;
  5. import android.graphics.drawable.Drawable;
  6. import android.util.AttributeSet;
  7. import android.view.View;
  8. import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
  9. /**
  10. * A simple extension of a regular linear layout that supports the divider API
  11. * of Android 4.0+. The dividers are added adjacent to the children by changing
  12. * their layout params. If you need to rely on the margins which fall in the
  13. * same orientation as the layout you should wrap the child in a simple
  14. * {@link android.widget.FrameLayout} so it can receive the margin.
  15. */
  16. public class IcsLinearLayout extends NineLinearLayout {
  17. private static final int[] LinearLayout = new int[] {
  18. /* 0 */ android.R.attr.divider,
  19. /* 1 */ android.R.attr.showDividers,
  20. /* 2 */ android.R.attr.dividerPadding,
  21. };
  22. private static final int LinearLayout_divider = 0;
  23. private static final int LinearLayout_showDividers = 1;
  24. private static final int LinearLayout_dividerPadding = 2;
  25. /**
  26. * Don't show any dividers.
  27. */
  28. public static final int SHOW_DIVIDER_NONE = 0;
  29. /**
  30. * Show a divider at the beginning of the group.
  31. */
  32. public static final int SHOW_DIVIDER_BEGINNING = 1;
  33. /**
  34. * Show dividers between each item in the group.
  35. */
  36. public static final int SHOW_DIVIDER_MIDDLE = 2;
  37. /**
  38. * Show a divider at the end of the group.
  39. */
  40. public static final int SHOW_DIVIDER_END = 4;
  41. private Drawable mDivider;
  42. private int mDividerWidth;
  43. private int mDividerHeight;
  44. private int mShowDividers;
  45. private int mDividerPadding;
  46. public IcsLinearLayout(Context context, AttributeSet attrs) {
  47. super(context, attrs);
  48. TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/LinearLayout);
  49. setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
  50. mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
  51. mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
  52. a.recycle();
  53. }
  54. /**
  55. * Set how dividers should be shown between items in this layout
  56. *
  57. * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
  58. * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
  59. * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
  60. */
  61. public void setShowDividers(int showDividers) {
  62. if (showDividers != mShowDividers) {
  63. requestLayout();
  64. invalidate(); //XXX This is required if you are toggling a divider off
  65. }
  66. mShowDividers = showDividers;
  67. }
  68. /**
  69. * @return A flag set indicating how dividers should be shown around items.
  70. * @see #setShowDividers(int)
  71. */
  72. public int getShowDividers() {
  73. return mShowDividers;
  74. }
  75. /**
  76. * Set a drawable to be used as a divider between items.
  77. * @param divider Drawable that will divide each item.
  78. * @see #setShowDividers(int)
  79. */
  80. public void setDividerDrawable(Drawable divider) {
  81. if (divider == mDivider) {
  82. return;
  83. }
  84. mDivider = divider;
  85. if (divider != null) {
  86. mDividerWidth = divider.getIntrinsicWidth();
  87. mDividerHeight = divider.getIntrinsicHeight();
  88. } else {
  89. mDividerWidth = 0;
  90. mDividerHeight = 0;
  91. }
  92. setWillNotDraw(divider == null);
  93. requestLayout();
  94. }
  95. /**
  96. * Get the width of the current divider drawable.
  97. *
  98. * @hide Used internally by framework.
  99. */
  100. public int getDividerWidth() {
  101. return mDividerWidth;
  102. }
  103. @Override
  104. protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
  105. final int index = indexOfChild(child);
  106. final int orientation = getOrientation();
  107. final LayoutParams params = (LayoutParams) child.getLayoutParams();
  108. if (hasDividerBeforeChildAt(index)) {
  109. if (orientation == VERTICAL) {
  110. //Account for the divider by pushing everything up
  111. params.topMargin = mDividerHeight;
  112. } else {
  113. //Account for the divider by pushing everything left
  114. params.leftMargin = mDividerWidth;
  115. }
  116. }
  117. final int count = getChildCount();
  118. if (index == count - 1) {
  119. if (hasDividerBeforeChildAt(count)) {
  120. if (orientation == VERTICAL) {
  121. params.bottomMargin = mDividerHeight;
  122. } else {
  123. params.rightMargin = mDividerWidth;
  124. }
  125. }
  126. }
  127. super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
  128. }
  129. @Override
  130. protected void onDraw(Canvas canvas) {
  131. if (mDivider != null) {
  132. if (getOrientation() == VERTICAL) {
  133. drawDividersVertical(canvas);
  134. } else {
  135. drawDividersHorizontal(canvas);
  136. }
  137. }
  138. super.onDraw(canvas);
  139. }
  140. void drawDividersVertical(Canvas canvas) {
  141. final int count = getChildCount();
  142. for (int i = 0; i < count; i++) {
  143. final View child = getChildAt(i);
  144. if (child != null && child.getVisibility() != GONE) {
  145. if (hasDividerBeforeChildAt(i)) {
  146. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  147. final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
  148. drawHorizontalDivider(canvas, top);
  149. }
  150. }
  151. }
  152. if (hasDividerBeforeChildAt(count)) {
  153. final View child = getChildAt(count - 1);
  154. int bottom = 0;
  155. if (child == null) {
  156. bottom = getHeight() - getPaddingBottom() - mDividerHeight;
  157. } else {
  158. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  159. bottom = child.getBottom()/* + lp.bottomMargin*/;
  160. }
  161. drawHorizontalDivider(canvas, bottom);
  162. }
  163. }
  164. void drawDividersHorizontal(Canvas canvas) {
  165. final int count = getChildCount();
  166. for (int i = 0; i < count; i++) {
  167. final View child = getChildAt(i);
  168. if (child != null && child.getVisibility() != GONE) {
  169. if (hasDividerBeforeChildAt(i)) {
  170. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  171. final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
  172. drawVerticalDivider(canvas, left);
  173. }
  174. }
  175. }
  176. if (hasDividerBeforeChildAt(count)) {
  177. final View child = getChildAt(count - 1);
  178. int right = 0;
  179. if (child == null) {
  180. right = getWidth() - getPaddingRight() - mDividerWidth;
  181. } else {
  182. final LayoutParams lp = (LayoutParams) child.getLayoutParams();
  183. right = child.getRight()/* + lp.rightMargin*/;
  184. }
  185. drawVerticalDivider(canvas, right);
  186. }
  187. }
  188. void drawHorizontalDivider(Canvas canvas, int top) {
  189. mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
  190. getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
  191. mDivider.draw(canvas);
  192. }
  193. void drawVerticalDivider(Canvas canvas, int left) {
  194. mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
  195. left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
  196. mDivider.draw(canvas);
  197. }
  198. /**
  199. * Determines where to position dividers between children.
  200. *
  201. * @param childIndex Index of child to check for preceding divider
  202. * @return true if there should be a divider before the child at childIndex
  203. * @hide Pending API consideration. Currently only used internally by the system.
  204. */
  205. protected boolean hasDividerBeforeChildAt(int childIndex) {
  206. if (childIndex == 0) {
  207. return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
  208. } else if (childIndex == getChildCount()) {
  209. return (mShowDividers & SHOW_DIVIDER_END) != 0;
  210. } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
  211. boolean hasVisibleViewBefore = false;
  212. for (int i = childIndex - 1; i >= 0; i--) {
  213. if (getChildAt(i).getVisibility() != GONE) {
  214. hasVisibleViewBefore = true;
  215. break;
  216. }
  217. }
  218. return hasVisibleViewBefore;
  219. }
  220. return false;
  221. }
  222. }