Skip to content

Commit 92b6869

Browse files
committed
Add support for LinearLayout ICS-style dividers. Closes JakeWharton#125.
1 parent a531924 commit 92b6869

File tree

10 files changed

+194
-7
lines changed

10 files changed

+194
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Version 2.4 *(In Development)*
77
* Support `android:background` attribute on `Canvas`-based views.
88
* Title indicator allows for drawing its line, underline, and/or triangle on
99
top of the titles for placement underneath a `ViewPager`.
10+
* Tab indicator now supports ICS-style dividers (see styled sample).
1011
* Fix: Do not attempt to change the `ViewPager` page when a motion is
1112
cancelled.
1213
* Fix: Long titles no longer overlap when swiping to the right.

library/project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99

1010
android.library=true
1111
# Project target.
12-
target=android-4
12+
target=android-14
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package com.viewpagerindicator;
2+
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.view.View;
8+
import android.widget.LinearLayout;
9+
10+
/**
11+
* A simple extension of a regular linear layout that supports the divider API
12+
* of Android 4.0+. The dividers are added adjacent to the children by changing
13+
* their layout params. If you need to rely on the margins which fall in the
14+
* same orientation as the layout you should wrap the child in a simple
15+
* {@link android.widget.FrameLayout} so it can receive the margin.
16+
*/
17+
class IcsLinearLayout extends LinearLayout {
18+
private static final int[] LL = new int[] {
19+
/* 0 */ android.R.attr.divider,
20+
/* 1 */ android.R.attr.showDividers,
21+
/* 2 */ android.R.attr.dividerPadding,
22+
};
23+
private static final int LL_DIVIDER = 0;
24+
private static final int LL_SHOW_DIVIDER = 1;
25+
private static final int LL_DIVIDER_PADDING = 2;
26+
27+
private Drawable mDivider;
28+
private int mDividerWidth;
29+
private int mDividerHeight;
30+
private int mShowDividers;
31+
private int mDividerPadding;
32+
33+
34+
public IcsLinearLayout(Context context) {
35+
super(context);
36+
37+
TypedArray a = context.obtainStyledAttributes(null, LL, R.attr.vpiTabPageIndicatorStyle, 0);
38+
setDividerDrawable(a.getDrawable(IcsLinearLayout.LL_DIVIDER));
39+
mDividerPadding = a.getDimensionPixelSize(LL_DIVIDER_PADDING, 0);
40+
mShowDividers = a.getInteger(LL_SHOW_DIVIDER, SHOW_DIVIDER_NONE);
41+
a.recycle();
42+
}
43+
44+
public void setDividerDrawable(Drawable divider) {
45+
if (divider == mDivider) {
46+
return;
47+
}
48+
mDivider = divider;
49+
if (divider != null) {
50+
mDividerWidth = divider.getIntrinsicWidth();
51+
mDividerHeight = divider.getIntrinsicHeight();
52+
} else {
53+
mDividerWidth = 0;
54+
mDividerHeight = 0;
55+
}
56+
setWillNotDraw(divider == null);
57+
requestLayout();
58+
}
59+
60+
@Override
61+
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
62+
final int index = indexOfChild(child);
63+
final int orientation = getOrientation();
64+
final LayoutParams params = (LayoutParams) child.getLayoutParams();
65+
if (hasDividerBeforeChildAt(index)) {
66+
if (orientation == VERTICAL) {
67+
//Account for the divider by pushing everything up
68+
params.topMargin = mDividerHeight;
69+
} else {
70+
//Account for the divider by pushing everything left
71+
params.leftMargin = mDividerWidth;
72+
}
73+
}
74+
75+
final int count = getChildCount();
76+
if (index == count - 1) {
77+
if (hasDividerBeforeChildAt(count)) {
78+
if (orientation == VERTICAL) {
79+
params.bottomMargin = mDividerHeight;
80+
} else {
81+
params.rightMargin = mDividerWidth;
82+
}
83+
}
84+
}
85+
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
86+
}
87+
88+
@Override
89+
protected void onDraw(Canvas canvas) {
90+
if (mDivider != null) {
91+
if (getOrientation() == VERTICAL) {
92+
drawDividersVertical(canvas);
93+
} else {
94+
drawDividersHorizontal(canvas);
95+
}
96+
}
97+
super.onDraw(canvas);
98+
}
99+
100+
private void drawDividersVertical(Canvas canvas) {
101+
final int count = getChildCount();
102+
for (int i = 0; i < count; i++) {
103+
final View child = getChildAt(i);
104+
105+
if (child != null && child.getVisibility() != GONE) {
106+
if (hasDividerBeforeChildAt(i)) {
107+
final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child.getLayoutParams();
108+
final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
109+
drawHorizontalDivider(canvas, top);
110+
}
111+
}
112+
}
113+
114+
if (hasDividerBeforeChildAt(count)) {
115+
final View child = getChildAt(count - 1);
116+
int bottom = 0;
117+
if (child == null) {
118+
bottom = getHeight() - getPaddingBottom() - mDividerHeight;
119+
} else {
120+
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
121+
bottom = child.getBottom()/* + lp.bottomMargin*/;
122+
}
123+
drawHorizontalDivider(canvas, bottom);
124+
}
125+
}
126+
127+
private void drawDividersHorizontal(Canvas canvas) {
128+
final int count = getChildCount();
129+
for (int i = 0; i < count; i++) {
130+
final View child = getChildAt(i);
131+
132+
if (child != null && child.getVisibility() != GONE) {
133+
if (hasDividerBeforeChildAt(i)) {
134+
final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child.getLayoutParams();
135+
final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
136+
drawVerticalDivider(canvas, left);
137+
}
138+
}
139+
}
140+
141+
if (hasDividerBeforeChildAt(count)) {
142+
final View child = getChildAt(count - 1);
143+
int right = 0;
144+
if (child == null) {
145+
right = getWidth() - getPaddingRight() - mDividerWidth;
146+
} else {
147+
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
148+
right = child.getRight()/* + lp.rightMargin*/;
149+
}
150+
drawVerticalDivider(canvas, right);
151+
}
152+
}
153+
154+
private void drawHorizontalDivider(Canvas canvas, int top) {
155+
mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
156+
getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
157+
mDivider.draw(canvas);
158+
}
159+
160+
private void drawVerticalDivider(Canvas canvas, int left) {
161+
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
162+
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
163+
mDivider.draw(canvas);
164+
}
165+
166+
private boolean hasDividerBeforeChildAt(int childIndex) {
167+
if (childIndex == 0 || childIndex == getChildCount()) {
168+
return false;
169+
}
170+
if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
171+
boolean hasVisibleViewBefore = false;
172+
for (int i = childIndex - 1; i >= 0; i--) {
173+
if (getChildAt(i).getVisibility() != GONE) {
174+
hasVisibleViewBefore = true;
175+
break;
176+
}
177+
}
178+
return hasVisibleViewBefore;
179+
}
180+
return false;
181+
}
182+
}

library/src/com/viewpagerindicator/TabPageIndicator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public void onClick(View view) {
6464
}
6565
};
6666

67-
private final LinearLayout mTabLayout;
67+
private final IcsLinearLayout mTabLayout;
68+
6869
private ViewPager mViewPager;
6970
private ViewPager.OnPageChangeListener mListener;
7071

@@ -81,7 +82,7 @@ public TabPageIndicator(Context context, AttributeSet attrs) {
8182
super(context, attrs);
8283
setHorizontalScrollBarEnabled(false);
8384

84-
mTabLayout = new LinearLayout(getContext());
85+
mTabLayout = new IcsLinearLayout(context);
8586
addView(mTabLayout, new ViewGroup.LayoutParams(WRAP_CONTENT, FILL_PARENT));
8687
}
8788

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@
6666
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
6767

6868
<java.version>1.6</java.version>
69-
<android.version>1.6_r2</android.version>
70-
<android.platform>4</android.platform>
69+
<android.version>4.0.1.2</android.version>
70+
<android.platform>14</android.platform>
7171
<android.support.version>r7</android.support.version>
7272

73-
<android-maven.version>3.2.0</android-maven.version>
73+
<android-maven.version>3.3.0</android-maven.version>
7474
</properties>
7575

7676
<dependencyManagement>

sample/project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
# project structure.
99

1010
# Project target.
11-
target=android-4
11+
target=android-14
1212
android.library.reference.1=../library
Loading
Loading
Loading

sample/res/values/styles.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
<style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
5353
<item name="android:background">@drawable/custom_tab_indicator</item>
5454
<item name="android:textColor">#FF555555</item>
55+
<item name="android:divider">@drawable/custom_tab_indicator_divider</item>
56+
<item name="android:dividerPadding">8dp</item>
57+
<item name="android:showDividers">middle</item>
5558
</style>
5659

5760
<style name="CustomUnderlinePageIndicator">

0 commit comments

Comments
 (0)