Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit 38ef42e3be7456f280c37a457d3175c7bf1678f5 0 parents
@JakeWharton authored
17 .gitignore
@@ -0,0 +1,17 @@
+#Android generated
+bin
+gen
+
+#Eclipse
+.project
+.classpath
+.settings
+
+#IntelliJ IDEA
+.idea
+*.iml
+
+#Maven
+target
+release.properties
+pom.xml.*
91 README.md
@@ -0,0 +1,91 @@
+Android ViewPagerIndicator
+==========================
+
+Port of [Patrik Åkerfeldt][1]'s paging indicators that are compatible with the
+ViewPager from the [Android Compatibility Library][2] and
+[ActionBarSherlock][3].
+
+
+
+
+Usage
+=====
+
+*For a working implementation of this project see the `sample/` folder.*
+
+ 1. Include one of the widgets in your view. This should usually be placed
+ adjacent to the `ViewPager` it represents.
+
+ <com.jakewharton.android.viewpagerindicator.TitlePageIndicator
+ android:id="@+id/title_indicator"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent" />
+
+ 2. In your `onCreate` method (or `onCreateView` for a fragment), bind the
+ indicator to the `ViewPager`.
+
+ //Set the pager with an adapter
+ ViewPager pager = (ViewPager)findViewById(R.id.pager);
+ pager.setAdapter(new TestAdapter(getSupportFragmentManager()));
+
+ //Bind the title indicator to the adapter
+ TitlePageIndicator titleIndicator = (TitlePageIndicator)findViewById(R.id.titles);
+ titleIndicator.setViewPager(pager);
+
+ 3. *(Optional)* If you use an `OnPageChangeListener` with your view pager
+ you should set it in the indicator rather than on the pager directly.
+
+ //continued from above
+ titleIndicator.setOnPageChangeListener(mPageChangeListener);
+
+
+
+
+Developed By
+============
+
+ * Jake Wharton - <jakewharton@gmail.com>
+
+
+Credits
+-------
+
+ * [Patrik Åkerfeldt][1] - Author of [ViewFlow][4], a precursor to the ViewPager,
+ which supports paged views and is the original source of both the title
+ and circle indicators.
+ * [Francisco Figueiredo Jr.][5] - Idea and [first implementation][6] for
+ fragment support via ViewPager.
+
+
+
+
+License
+=======
+
+ Copyright 2011 Patrik kerfeldt
+ Copyright 2011 Francisco Figueiredo Jr.
+ Copyright 2011 Jake Wharton
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
+
+
+
+ [1]: https://github.com/pakerfeldt
+ [2]: http://developer.android.com/sdk/compatibility-library.html
+ [3]: http://actionbarsherlock.com
+ [4]: https://github.com/pakerfeldt/android-viewflow
+ [5]: https://github.com/franciscojunior
+ [6]: https://gist.github.com/1122947
9 library/AndroidManifest.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.jakewharton.android.viewpagerindicator"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="4" />
+</manifest>
115 library/checkstyle.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
+
+<module name="Checker">
+ <!--module name="NewlineAtEndOfFile"/-->
+ <module name="FileLength"/>
+ <module name="FileTabCharacter"/>
+
+ <!-- Trailing spaces -->
+ <module name="RegexpSingleline">
+ <property name="format" value="\s+$"/>
+ <property name="message" value="Line has trailing spaces."/>
+ </module>
+
+ <module name="TreeWalker">
+ <property name="cacheFile" value="${checkstyle.cache.file}"/>
+
+ <!-- Checks for Javadoc comments. -->
+ <!-- See http://checkstyle.sf.net/config_javadoc.html -->
+ <!--module name="JavadocMethod"/-->
+ <!--module name="JavadocType"/-->
+ <!--module name="JavadocVariable"/-->
+ <!--module name="JavadocStyle"/-->
+
+
+ <!-- Checks for Naming Conventions. -->
+ <!-- See http://checkstyle.sf.net/config_naming.html -->
+ <module name="ConstantName"/>
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName"/>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="StaticVariableName"/>
+ <module name="TypeName"/>
+
+
+ <!-- Checks for imports -->
+ <!-- See http://checkstyle.sf.net/config_import.html -->
+ <module name="AvoidStarImport"/>
+ <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
+ <module name="RedundantImport"/>
+ <module name="UnusedImports"/>
+
+
+ <!-- Checks for Size Violations. -->
+ <!-- See http://checkstyle.sf.net/config_sizes.html -->
+ <!--module name="LineLength"/-->
+ <!--module name="MethodLength"/-->
+ <!--module name="ParameterNumber"/-->
+
+
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <!--module name="EmptyForIteratorPad"/-->
+ <!--module name="MethodParamPad"/-->
+ <!--module name="NoWhitespaceAfter"/-->
+ <!--module name="NoWhitespaceBefore"/-->
+ <!--module name="OperatorWrap"/-->
+ <!--module name="ParenPad"/-->
+ <!--module name="TypecastParenPad"/-->
+ <!--module name="WhitespaceAfter"/-->
+ <!--module name="WhitespaceAround"/-->
+
+
+ <!-- Modifier Checks -->
+ <!-- See http://checkstyle.sf.net/config_modifiers.html -->
+ <!--module name="ModifierOrder"/-->
+ <!--module name="RedundantModifier"/-->
+
+
+ <!-- Checks for blocks. You know, those {}'s -->
+ <!-- See http://checkstyle.sf.net/config_blocks.html -->
+ <!--module name="AvoidNestedBlocks"/-->
+ <!--module name="EmptyBlock"/-->
+ <!--module name="LeftCurly"/-->
+ <!--module name="NeedBraces"/-->
+ <!--module name="RightCurly"/-->
+
+
+ <!-- Checks for common coding problems -->
+ <!-- See http://checkstyle.sf.net/config_coding.html -->
+ <!--module name="AvoidInlineConditionals"/-->
+ <!--module name="DoubleCheckedLocking"/--> <!-- MY FAVOURITE -->
+ <!--module name="EmptyStatement"/-->
+ <!--module name="EqualsHashCode"/-->
+ <!--module name="HiddenField"/-->
+ <!--module name="IllegalInstantiation"/-->
+ <!--module name="InnerAssignment"/-->
+ <!--module name="MagicNumber"/-->
+ <!--module name="MissingSwitchDefault"/-->
+ <!--module name="RedundantThrows"/-->
+ <!--module name="SimplifyBooleanExpression"/-->
+ <!--module name="SimplifyBooleanReturn"/-->
+
+ <!-- Checks for class design -->
+ <!-- See http://checkstyle.sf.net/config_design.html -->
+ <!--module name="DesignForExtension"/-->
+ <!--module name="FinalClass"/-->
+ <!--module name="HideUtilityClassConstructor"/-->
+ <!--module name="InterfaceIsType"/-->
+ <!--module name="VisibilityModifier"/-->
+
+
+ <!-- Miscellaneous other checks. -->
+ <!-- See http://checkstyle.sf.net/config_misc.html -->
+ <!--module name="ArrayTypeStyle"/-->
+ <!--module name="FinalParameters"/-->
+ <!--module name="TodoComment"/-->
+ <!--module name="UpperEll"/-->
+ </module>
+</module>
12 library/default.properties
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
+android.library=true
BIN  library/libs/android-support-v4.jar
Binary file not shown
67 library/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator</artifactId>
+ <name>Android-ViewPagerIndicator</name>
+ <packaging>apklib</packaging>
+
+ <parent>
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>android.support</groupId>
+ <artifactId>compatibility-v4</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+
+ <plugins>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>maven-android-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <configLocation>${project.basedir}/checkstyle.xml</configLocation>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>checkstyle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
36 library/res/values/attrs.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 Patrik Åkerfeldt
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <declare-styleable name="CircleFlowIndicator">
+ <attr name="fillColor" format="color" />
+ <attr name="strokeColor" format="color" />
+ <attr name="radius" format="dimension" />
+ <attr name="centered" format="boolean" />
+ </declare-styleable>
+ <declare-styleable name="TitleFlowIndicator">
+ <attr name="titlePadding" format="dimension" />
+ <!-- Left/right padding of not active view titles. -->
+ <attr name="clipPadding" format="dimension" />
+ <attr name="selectedColor" format="color" />
+ <attr name="selectedBold" format="boolean" />
+ <attr name="textColor" format="color" />
+ <attr name="textSize" format="dimension" />
+ <attr name="footerLineHeight" format="dimension" />
+ <attr name="footerColor" format="color" />
+ <attr name="footerTriangleHeight" format="dimension" />
+ </declare-styleable>
+</resources>
244 library/src/com/jakewharton/android/viewpagerindicator/CirclePageIndicator.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jakewharton.android.viewpagerindicator;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A FlowIndicator which draws circles (one for each view). The current view
+ * position is filled and others are only stroked.<br/><br/>
+ * Available attributes are:<br/>
+ * <ul>fillColor: Define the color used to fill a circle (default to white)</ul>
+ * <ul>strokeColor: Define the color used to stroke a circle (default to white)</ul>
+ * <ul>mRadius: Define the circle mRadius (default to 4.0)</ul>
+ */
+public class CirclePageIndicator extends View implements PageIndicator {
+ private static final float DEFAULT_RADIUS_DP = 3;
+ private static final int DEFAULT_FILL_COLOR = 0xFFFFFFFF;
+ private static final int DEFAULT_STROKE_COLOR = 0xFFDDDDDD;
+
+ private final float mRadius;
+ private final Paint mPaintStroke;
+ private final Paint mPaintFill;
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mListener;
+ private int mCurrentScroll;
+ private int mFlowWidth;
+
+ /**
+ * Default constructor
+ *
+ * @param context
+ */
+ public CirclePageIndicator(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * The constructor used with an inflater
+ *
+ * @param context
+ * @param attrs
+ */
+ public CirclePageIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final float density = getResources().getDisplayMetrics().density;
+ final float defaultRadius = DEFAULT_RADIUS_DP * density;
+
+ // Retrieve styles attributs
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleFlowIndicator);
+
+ // Retrieve the colors to be used for this view and apply them.
+ final int fillColor = a.getColor(R.styleable.CircleFlowIndicator_fillColor, DEFAULT_FILL_COLOR);
+ final int strokeColor = a.getColor(R.styleable.CircleFlowIndicator_strokeColor, DEFAULT_STROKE_COLOR);
+ // Retrieve the mRadius
+ mRadius = a.getDimension(R.styleable.CircleFlowIndicator_radius, defaultRadius);
+
+ a.recycle();
+
+ mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintStroke.setStyle(Style.STROKE);
+ mPaintStroke.setColor(strokeColor);
+ mPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaintFill.setStyle(Style.FILL);
+ mPaintFill.setColor(fillColor);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onDraw(android.graphics.Canvas)
+ */
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ int count = (mViewPager != null && mViewPager.getAdapter() != null) ? mViewPager.getAdapter().getCount() : 1;
+ // Draw stroked circles
+ for (int iLoop = 0; iLoop < count; iLoop++) {
+ canvas.drawCircle(getPaddingLeft() + mRadius
+ + (iLoop * (2 * mRadius + mRadius)),
+ getPaddingTop() + mRadius, mRadius, mPaintStroke);
+ }
+ float cx = 0;
+ if (mFlowWidth != 0) {
+ // Draw the filled circle according to the current scroll
+ cx = (mCurrentScroll * (2 * mRadius + mRadius)) / mFlowWidth;
+ }
+ // The flow width has been updated yet. Draw the default position
+ canvas.drawCircle(getPaddingLeft() + mRadius + cx,
+ getPaddingTop() + mRadius, mRadius, mPaintFill);
+
+ }
+
+ @Override
+ public void setViewPager(ViewPager view) {
+ mViewPager = view;
+ mViewPager.setOnPageChangeListener(this);
+ mFlowWidth = mViewPager.getWidth();
+ invalidate();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mCurrentScroll = (position * mViewPager.getWidth()) + positionOffsetPixels;
+ mFlowWidth = mViewPager.getWidth();
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mListener != null) {
+ mListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void setOnPageChangeListener(OnPageChangeListener listener) {
+ mListener = listener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onMeasure(int, int)
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec),
+ measureHeight(heightMeasureSpec));
+ }
+
+ /**
+ * Determines the width of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ // We were told how big to be
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ }
+ // Calculate the width according the views count
+ else {
+ int count = (mViewPager != null && mViewPager.getAdapter() != null) ? mViewPager.getAdapter().getCount() : 1;
+ result = (int)(getPaddingLeft() + getPaddingRight()
+ + (count * 2 * mRadius) + (count - 1) * mRadius + 1);
+ // Respect AT_MOST value if that was what is called for by
+ // measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines the height of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The height of the view, honoring constraints from measureSpec
+ */
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ // We were told how big to be
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ }
+ // Measure the height
+ else {
+ result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);
+ // Respect AT_MOST value if that was what is called for by
+ // measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Sets the fill color
+ *
+ * @param color
+ * ARGB value for the text
+ */
+ public void setFillColor(int color) {
+ mPaintFill.setColor(color);
+ invalidate();
+ }
+
+ /**
+ * Sets the stroke color
+ *
+ * @param color
+ * ARGB value for the text
+ */
+ public void setStrokeColor(int color) {
+ mPaintStroke.setColor(color);
+ invalidate();
+ }
+}
45 library/src/com/jakewharton/android/viewpagerindicator/PageIndicator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jakewharton.android.viewpagerindicator;
+
+import android.support.v4.view.ViewPager;
+
+
+/**
+ * An interface which defines the contract between a ViewFlow and a
+ * PageIndicator.<br/>
+ * A PageIndicator is responsible to show an visual indicator on the total views
+ * number and the current visible view.<br/>
+ *
+ */
+public interface PageIndicator extends ViewPager.OnPageChangeListener {
+
+ /**
+ * Set the current ViewFlow. This method is called by the ViewFlow when the
+ * PageIndicator is attached to it.
+ *
+ * @param view
+ */
+ public void setViewPager(ViewPager view);
+
+ /**
+ * Set a page change listener which will receive forwarded events.
+ *
+ * @param listener
+ */
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
+}
406 library/src/com/jakewharton/android/viewpagerindicator/TitlePageIndicator.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Francisco Figueiredo Jr.
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jakewharton.android.viewpagerindicator;
+
+import java.util.ArrayList;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * A TitlePageIndicator is a PageIndicator which displays the title of left view
+ * (if exist), the title of the current select view (centered) and the title of
+ * the right view (if exist). When the user scrolls the ViewFlow then titles are
+ * also scrolled.
+ */
+public class TitlePageIndicator extends TextView implements PageIndicator {
+ private static final float DEFAULT_TITLE_PADDING_DP = 5;
+ private static final float DEFAULT_CLIP_PADDING_DP = 0;
+ private static final int DEFAULT_SELECTED_COLOR = 0xFFFFFFFF;
+ private static final boolean DEFAULT_SELECTED_BOLD = true;
+ private static final int DEFAULT_TEXT_COLOR = 0xFFAAAAAA;
+ private static final int DEFAULT_TEXT_SIZE_DP = 18;
+ private static final float DEFAULT_FOOTER_LINE_HEIGHT = 1;
+ private static final int DEFAULT_FOOTER_COLOR = 0xFF6899FF;
+ private static final float DEFAULT_FOOTER_TRIANGLE_HEIGHT = 7;
+
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mListener;
+ private int mCurrentScroll;
+ private TitleProvider mTitleProvider;
+ private int mCurrentPosition;
+ private final Paint mPaintText;
+ private final Paint mPaintSelected;
+ private Path mPath;
+ private final Paint mPaintFooterLine;
+ private final Paint mPaintFooterTriangle;
+ private final float mFooterTriangleHeight;
+ private final float mTitlePadding;
+ /** Left and right side padding for not active view titles. */
+ private final float mClipPadding;
+ private final float mFooterLineHeight;
+
+ /**
+ * Default constructor
+ */
+ public TitlePageIndicator(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * The constructor used with an inflater
+ *
+ * @param context
+ * @param attrs
+ */
+ public TitlePageIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final float density = getResources().getDisplayMetrics().density;
+ final float defaultTextSize = DEFAULT_TEXT_SIZE_DP * density;
+ final float defaultTitlePadding = DEFAULT_TITLE_PADDING_DP * density;
+ final float defaultClipPadding = DEFAULT_CLIP_PADDING_DP * density;
+
+ // Retrieve styles attributes
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleFlowIndicator);
+
+ // Retrieve the colors to be used for this view and apply them.
+ final int footerColor = a.getColor(R.styleable.TitleFlowIndicator_footerColor, DEFAULT_FOOTER_COLOR);
+ mFooterLineHeight = a.getDimension(R.styleable.TitleFlowIndicator_footerLineHeight, DEFAULT_FOOTER_LINE_HEIGHT);
+ mFooterTriangleHeight = a.getDimension(R.styleable.TitleFlowIndicator_footerTriangleHeight, DEFAULT_FOOTER_TRIANGLE_HEIGHT);
+ final int selectedColor = a.getColor(R.styleable.TitleFlowIndicator_selectedColor, DEFAULT_SELECTED_COLOR);
+ final boolean selectedBold = a.getBoolean(R.styleable.TitleFlowIndicator_selectedColor, DEFAULT_SELECTED_BOLD);
+ final int textColor = a.getColor(R.styleable.TitleFlowIndicator_textColor, DEFAULT_TEXT_COLOR);
+ final float textSize = a.getDimension(R.styleable.TitleFlowIndicator_textSize, defaultTextSize);
+ mTitlePadding = a.getDimension(R.styleable.TitleFlowIndicator_titlePadding, defaultTitlePadding);
+ mClipPadding = a.getDimension(R.styleable.TitleFlowIndicator_clipPadding, defaultClipPadding);
+
+ a.recycle();
+
+ mPaintText = new Paint();
+ mPaintText.setColor(textColor);
+ mPaintText.setTextSize(textSize);
+ mPaintText.setAntiAlias(true);
+ mPaintSelected = new Paint();
+ mPaintSelected.setColor(selectedColor);
+ mPaintSelected.setTextSize(textSize);
+ mPaintSelected.setFakeBoldText(selectedBold);
+ mPaintSelected.setAntiAlias(true);
+ mPaintFooterLine = new Paint();
+ mPaintFooterLine.setStyle(Paint.Style.FILL_AND_STROKE);
+ mPaintFooterLine.setStrokeWidth(mFooterLineHeight);
+ mPaintFooterLine.setColor(footerColor);
+ mPaintFooterTriangle = new Paint();
+ mPaintFooterTriangle.setStyle(Paint.Style.FILL_AND_STROKE);
+ mPaintFooterTriangle.setColor(footerColor);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onDraw(android.graphics.Canvas)
+ */
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // Calculate views bounds
+ ArrayList<Rect> bounds = calculateAllBounds(mPaintText);
+
+ // If no value then add a fake one
+ int count = (mViewPager != null && mViewPager.getAdapter() != null) ? mViewPager.getAdapter().getCount() : 1;
+
+ // Verify if the current view must be clipped to the screen
+ Rect curViewBound = bounds.get(mCurrentPosition);
+ int curViewWidth = curViewBound.right - curViewBound.left;
+ if (curViewBound.left < 0) {
+ // Try to clip to the screen (left side)
+ clipViewOnTheLeft(curViewBound, curViewWidth);
+ }
+ if (curViewBound.right > getLeft() + getWidth()) {
+ // Try to clip to the screen (right side)
+ clipViewOnTheRight(curViewBound, curViewWidth);
+ }
+
+ // Left views starting from the current position
+ if (mCurrentPosition > 0) {
+ for (int iLoop = mCurrentPosition - 1; iLoop >= 0; iLoop--) {
+ Rect bound = bounds.get(iLoop);
+ int w = bound.right - bound.left;
+ // Si left side is outside the screen
+ if (bound.left < 0) {
+ // Try to clip to the screen (left side)
+ clipViewOnTheLeft(bound, w);
+ // Except if there's an intersection with the right view
+ if (iLoop < count - 1 && mCurrentPosition != iLoop) {
+ Rect rightBound = bounds.get(iLoop + 1);
+ // Intersection
+ if (bound.right + (int)mTitlePadding > rightBound.left) {
+ bound.left = rightBound.left - (w + (int)mTitlePadding);
+ }
+ }
+ }
+ }
+ }
+ // Right views starting from the current position
+ if (mCurrentPosition < count - 1) {
+ for (int iLoop = mCurrentPosition + 1 ; iLoop < count; iLoop++) {
+ Rect bound = bounds.get(iLoop);
+ int w = bound.right - bound.left;
+ // If right side is outside the screen
+ if (bound.right > getLeft() + getWidth()) {
+ // Try to clip to the screen (right side)
+ clipViewOnTheRight(bound, w);
+ // Except if there's an intersection with the left view
+ if (iLoop > 0 && mCurrentPosition != iLoop) {
+ Rect leftBound = bounds.get(iLoop - 1);
+ // Intersection
+ if (bound.left - (int)mTitlePadding < leftBound.right) {
+ bound.left = leftBound.right + (int)mTitlePadding;
+ }
+ }
+ }
+ }
+ }
+
+ // Now draw views
+ for (int iLoop = 0; iLoop < count; iLoop++) {
+ // Get the title
+ String title = getTitle(iLoop);
+ Rect bound = bounds.get(iLoop);
+ // Only if one side is visible
+ if ((bound.left > getLeft() && bound.left < getLeft() + getWidth()) || (bound.right > getLeft() && bound.right < getLeft() + getWidth())) {
+ Paint paint = mPaintText;
+ // Change the color is the title is closed to the center
+ int middle = (bound.left + bound.right) / 2;
+ if (Math.abs(middle - (getWidth() / 2)) < 20) {
+ paint = mPaintSelected;
+ }
+ canvas.drawText(title, bound.left, bound.bottom, paint);
+ }
+ }
+
+ // Draw the footer line
+ mPath = new Path();
+ mPath.moveTo(0, getHeight()-mFooterLineHeight);
+ mPath.lineTo(getWidth(), getHeight()-mFooterLineHeight);
+ mPath.close();
+ canvas.drawPath(mPath, mPaintFooterLine);
+ // Draw the footer triangle
+ mPath = new Path();
+ mPath.moveTo(getWidth() / 2, getHeight()-mFooterLineHeight-mFooterTriangleHeight);
+ mPath.lineTo(getWidth() / 2 + mFooterTriangleHeight, getHeight()-mFooterLineHeight);
+ mPath.lineTo(getWidth() / 2 - mFooterTriangleHeight, getHeight()-mFooterLineHeight);
+ mPath.close();
+ canvas.drawPath(mPath, mPaintFooterTriangle);
+
+ }
+
+ /**
+ * Set bounds for the right textView including clip padding.
+ *
+ * @param curViewBound
+ * current bounds.
+ * @param curViewWidth
+ * width of the view.
+ */
+ private void clipViewOnTheRight(Rect curViewBound, int curViewWidth) {
+ curViewBound.right = getLeft() + getWidth() - (int)mClipPadding;
+ curViewBound.left = curViewBound.right - curViewWidth;
+ }
+
+ /**
+ * Set bounds for the left textView including clip padding.
+ *
+ * @param curViewBound
+ * current bounds.
+ * @param curViewWidth
+ * width of the view.
+ */
+ private void clipViewOnTheLeft(Rect curViewBound, int curViewWidth) {
+ curViewBound.left = 0 + (int)mClipPadding;
+ curViewBound.right = curViewWidth;
+ }
+
+ /**
+ * Calculate views bounds and scroll them according to the current index
+ *
+ * @param paint
+ * @param currentIndex
+ * @return
+ */
+ private ArrayList<Rect> calculateAllBounds(Paint paint) {
+ ArrayList<Rect> list = new ArrayList<Rect>();
+ // For each views (If no values then add a fake one)
+ int count = (mViewPager != null && mViewPager.getAdapter() != null) ? mViewPager.getAdapter().getCount() : 1;
+ for (int iLoop = 0; iLoop < count; iLoop++) {
+ Rect bounds = calcBounds(iLoop, paint);
+ int w = (bounds.right - bounds.left);
+ int h = (bounds.bottom - bounds.top);
+ bounds.left = (getWidth() / 2) - (w / 2) - mCurrentScroll + (iLoop * getWidth());
+ bounds.right = bounds.left + w;
+ bounds.top = 0;
+ bounds.bottom = h;
+ list.add(bounds);
+ }
+
+ return list;
+ }
+
+ /**
+ * Calculate the bounds for a view's title
+ *
+ * @param index
+ * @param paint
+ * @return
+ */
+ private Rect calcBounds(int index, Paint paint) {
+ // Get the title
+ String title = getTitle(index);
+ // Calculate the text bounds
+ Rect bounds = new Rect();
+ bounds.right = (int) paint.measureText(title);
+ bounds.bottom = (int) (paint.descent()-paint.ascent());
+ return bounds;
+ }
+
+ /**
+ * Returns the title
+ *
+ * @param pos
+ * @return
+ */
+ private String getTitle(int pos) {
+ // If the TitleProvider exist
+ if (mTitleProvider != null) {
+ return mTitleProvider.getTitle(pos);
+ }
+ // Set the default title
+ return "Page " + (pos + 1);
+ }
+
+ @Override
+ public void setViewPager(ViewPager view) {
+ if (view.getAdapter() == null) {
+ throw new IllegalStateException("ViewPager does not have adapter instance.");
+ }
+ if (!(view.getAdapter() instanceof TitleProvider)) {
+ throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
+ }
+ mViewPager = view;
+ mViewPager.setOnPageChangeListener(this);
+ mTitleProvider = (TitleProvider)mViewPager.getAdapter();
+ invalidate();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mCurrentScroll = (position * mViewPager.getWidth()) + positionOffsetPixels;
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ mCurrentPosition = position;
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mListener = listener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onMeasure(int, int)
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec),
+ measureHeight(heightMeasureSpec));
+ }
+
+ /**
+ * Determines the width of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureWidth(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode != MeasureSpec.EXACTLY) {
+ throw new IllegalStateException(
+ "ViewFlow can only be used in EXACTLY mode.");
+ }
+ result = specSize;
+ return result;
+ }
+
+ /**
+ * Determines the height of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The height of the view, honoring constraints from measureSpec
+ */
+ private int measureHeight(int measureSpec) {
+ int result = 0;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ // We were told how big to be
+ if (specMode == MeasureSpec.EXACTLY) {
+ result = specSize;
+ }
+ // Measure the height
+ else {
+ // Calculate the text bounds
+ Rect bounds = new Rect();
+ bounds.bottom = (int) (mPaintText.descent()-mPaintText.ascent());
+ result = bounds.bottom - bounds.top + (int)mFooterTriangleHeight + (int)mFooterLineHeight + 10;
+ return result;
+ }
+ return result;
+ }
+}
28 library/src/com/jakewharton/android/viewpagerindicator/TitleProvider.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jakewharton.android.viewpagerindicator;
+
+/**
+ * A TitleProvider provides the title to display according to a view.
+ */
+public interface TitleProvider {
+ /**
+ * Returns the title of the view at position
+ * @param position
+ * @return
+ */
+ public String getTitle(int position);
+}
164 pom.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator-parent</artifactId>
+ <packaging>pom</packaging>
+ <version>1.0.0-SNAPSHOT</version>
+
+ <name>Android-ViewPagerIndicator (Parent)</name>
+ <description>Android library for.</description>
+ <url>https://github.com/JakeWharton/Android-ViewPagerIndicator</url>
+ <inceptionYear>2011</inceptionYear>
+
+ <modules>
+ <module>library</module>
+ <module>sample</module>
+ </modules>
+
+ <scm>
+ <url>http://github.com/JakeWharton/Android-ViewPagerIndicator/</url>
+ <connection>scm:git:git://github.com/JakeWharton/Android-ViewPagerIndicator.git</connection>
+ <developerConnection>scm:git:git@github.com:JakeWharton/Android-ViewPagerIndicator.git</developerConnection>
+ </scm>
+
+ <developers>
+ <developer>
+ <name>Jake Wharton</name>
+ <email>jakewharton@gmail.com</email>
+ <id>jakewharton</id>
+ <url>http://jakewharton.com</url>
+ <timezone>-5</timezone>
+ <roles>
+ <role>developer</role>
+ </roles>
+ </developer>
+ </developers>
+
+ <licenses>
+ <license>
+ <name>Apache License Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <distributionManagement>
+ <repository>
+ <id>personal-repository</id>
+ <name>JakeWharton.com Maven Repository</name>
+ <url>scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/release/</url>
+ </repository>
+ <snapshotRepository>
+ <id>personal-repository</id>
+ <name>JakeWharton.com Maven Repository</name>
+ <url>scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/snapshot/</url>
+ </snapshotRepository>
+ </distributionManagement>
+
+ <organization>
+ <name>Jake Wharton</name>
+ <url>http://jakewharton.com</url>
+ </organization>
+
+ <issueManagement>
+ <system>GitHub Issues</system>
+ <url>https://github.com/JakeWharton/Android-ViewPagerIndicator/issues</url>
+ </issueManagement>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+ <java.version>1.6</java.version>
+ <android.version>1.6_r3</android.version>
+ <android.platform>4</android.platform>
+ <android.support.version>r3</android.support.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>android</groupId>
+ <artifactId>android</artifactId>
+ <version>${android.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>android.support</groupId>
+ <artifactId>compatibility-v4</artifactId>
+ <version>${android.support.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.8</version>
+ </plugin>
+
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>maven-android-plugin</artifactId>
+ <version>2.9.0-beta-5</version>
+ <configuration>
+ <sdk>
+ <platform>${android.platform}</platform>
+ </sdk>
+ <undeployBeforeDeploy>true</undeployBeforeDeploy>
+ </configuration>
+ <extensions>true</extensions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <failsOnError>true</failsOnError>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.6</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.wagon</groupId>
+ <artifactId>wagon-ssh</artifactId>
+ <version>1.0-beta-7</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+</project>
17 sample/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.jakewharton.android.viewpagerindicator.sample"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk android:minSdkVersion="4" />
+
+ <application android:label="ViewPagerIndicator Sample">
+ <activity android:name=".SampleActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
12 sample/default.properties
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
+android.library.reference.1=../library
BIN  sample/libs/android-support-v4.jar
Binary file not shown
94 sample/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator-sample</artifactId>
+ <name>Android-ViewPagerIndicator Sample</name>
+ <packaging>apk</packaging>
+
+ <parent>
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator-parent</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>android</groupId>
+ <artifactId>android</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>android.support</groupId>
+ <artifactId>compatibility-v4</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.jakewharton</groupId>
+ <artifactId>android-viewpagerindicator</artifactId>
+ <version>${project.version}</version>
+ <type>apklib</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <finalName>${project.artifactId}-unaligned</finalName>
+
+ <plugins>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>maven-android-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.jayway.maven.plugins.android.generation2</groupId>
+ <artifactId>maven-android-plugin</artifactId>
+ <inherited>true</inherited>
+ <configuration>
+ <zipalign>
+ <inputApk>${project.build.directory}/${project.build.finalName}.apk</inputApk>
+ <outputApk>${project.build.directory}/${project.artifactId}.apk</outputApk>
+ </zipalign>
+ </configuration>
+ <executions>
+ <execution>
+ <id>alignApk</id>
+ <phase>package</phase>
+ <goals>
+ <goal>zipalign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
49 sample/res/layout/main.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res/com.jakewharton.android.viewtitlepager"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:gravity="center_horizontal"
+ android:id="@+id/header_layout"
+ android:orientation="vertical"
+ android:layout_height="wrap_content">
+ <com.jakewharton.android.viewpagerindicator.TitlePageIndicator
+ android:id="@+id/titles"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_marginTop="5dip" />
+ </LinearLayout>
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager_titles"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:gravity="center_horizontal"
+ android:id="@+id/header_layout"
+ android:orientation="vertical"
+ android:layout_height="wrap_content">
+ <com.jakewharton.android.viewpagerindicator.CirclePageIndicator
+ android:id="@+id/circles"
+ android:padding="10dip"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:background="#00000000" />
+ </LinearLayout>
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager_circles"
+ android:layout_width="fill_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+</LinearLayout>
91 sample/src/com/jakewharton/android/viewpagerindicator/sample/SampleActivity.java
@@ -0,0 +1,91 @@
+package com.jakewharton.android.viewpagerindicator.sample;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.jakewharton.android.viewpagerindicator.CirclePageIndicator;
+import com.jakewharton.android.viewpagerindicator.TitlePageIndicator;
+import com.jakewharton.android.viewpagerindicator.TitleProvider;
+
+public class SampleActivity extends FragmentActivity {
+ @Override
+ protected void onCreate(Bundle arg0) {
+ super.onCreate(arg0);
+ setContentView(R.layout.main);
+
+ //TITLES
+ ViewPager pagerTitles = (ViewPager)findViewById(R.id.pager_titles);
+ pagerTitles.setAdapter(new TestFragmentAdapter(getSupportFragmentManager()));
+
+ TitlePageIndicator pageIndicatorTitles = (TitlePageIndicator)findViewById(R.id.titles);
+ pageIndicatorTitles.setViewPager(pagerTitles);
+
+ //CIRCLES
+ ViewPager pagerCircles = (ViewPager)findViewById(R.id.pager_circles);
+ pagerCircles.setAdapter(new TestFragmentAdapter(getSupportFragmentManager()));
+
+ CirclePageIndicator pageIndicatorCircles = (CirclePageIndicator)findViewById(R.id.circles);
+ pageIndicatorCircles.setViewPager(pagerCircles);
+ }
+
+ private static final class TestFragmentAdapter extends FragmentPagerAdapter implements TitleProvider {
+ private static final String[] CONTENT = new String[] { "This", "Is", "A", "Test", };
+
+ public TestFragmentAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return new TestFragment(CONTENT[position]);
+ }
+
+ @Override
+ public int getCount() {
+ return CONTENT.length;
+ }
+
+ @Override
+ public String getTitle(int position) {
+ return CONTENT[position];
+ }
+ }
+
+ private static final class TestFragment extends Fragment {
+ private final String mContent;
+
+ public TestFragment(String content) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 20; i++) {
+ builder.append(content).append(" ");
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ mContent = builder.toString();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ TextView text = new TextView(getActivity());
+ text.setText(mContent);
+ text.setTextSize(20 * getResources().getDisplayMetrics().density);
+ text.setPadding(20, 20, 20, 20);
+
+ LinearLayout layout = new LinearLayout(getActivity());
+ layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
+ layout.setGravity(Gravity.CENTER);
+ layout.addView(text);
+
+ return layout;
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.