├── .gitignore
├── CHANGELOG.md
├── README.md
├── art
├── material_tabs.gif
└── material_tabs_middle.gif
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── project.properties
├── res
│ ├── drawable-v21
│ │ └── psts_background_tab.xml
│ ├── drawable
│ │ └── psts_background_tab.xml
│ ├── layout
│ │ └── psts_tab.xml
│ └── values
│ │ ├── attrs.xml
│ │ └── colors.xml
└── src
│ └── com
│ └── astuetz
│ └── PagerSlidingTabStrip.java
├── sample
├── AndroidManifest.xml
├── build.gradle
├── ic_launcher-web.png
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_actionbar.png
│ ├── drawable-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_actionbar.png
│ ├── drawable-xhdpi
│ │ ├── actionbar_bottom.9.png
│ │ ├── background_card.9.png
│ │ ├── contact.png
│ │ ├── ic_action_user.png
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_actionbar.png
│ │ ├── ic_launcher_chrome.png
│ │ ├── ic_launcher_gmail.png
│ │ ├── ic_launcher_gmaps.png
│ │ ├── ic_launcher_gplus.png
│ │ ├── tabs_pattern.png
│ │ └── tabs_pattern_diagonal.png
│ ├── drawable-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_actionbar.png
│ ├── drawable
│ │ ├── background_tabs.xml
│ │ └── background_tabs_diagonal.xml
│ ├── layout-land
│ │ └── fragment_quick_contact.xml
│ ├── layout-v11
│ │ └── custom_tab.xml
│ ├── layout
│ │ ├── activity_main.xml
│ │ ├── custom_tab.xml
│ │ ├── fragment_card.xml
│ │ ├── fragment_quick_contact.xml
│ │ ├── fragment_quickcontact.xml
│ │ └── toolbar.xml
│ ├── menu
│ │ └── main.xml
│ ├── values-sw600dp
│ │ └── dimens.xml
│ ├── values-sw720dp-land
│ │ └── dimens.xml
│ ├── values-v11
│ │ ├── styles.xml
│ │ └── themes.xml
│ ├── values-v19
│ │ └── themes.xml
│ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
└── src
│ └── com
│ └── astuetz
│ └── viewpager
│ └── extensions
│ └── sample
│ ├── LinearLayoutFeedback.java
│ ├── MainActivity.java
│ ├── QuickContactFragment.java
│ └── SuperAwesomeCardFragment.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 | gen*
5 |
6 | #Eclipse
7 | .project
8 | .classpath
9 | .settings
10 |
11 | #IntelliJ IDEA
12 | .idea
13 | *.iml
14 | *.ipr
15 | *.iws
16 | out
17 |
18 | #Maven
19 | target
20 | release.properties
21 | pom.xml.*
22 |
23 | #Ant
24 | build.xml
25 | local.properties
26 | proguard.cfg
27 |
28 | #Gradle
29 | .gradle
30 | build
31 |
32 | #OSX
33 | .DS_Store
34 |
35 | #Personal Files
36 | signing.properties
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | Version 1.1.1 *(04-09-2016)*
5 | ---------------------------------
6 | * Bug fixes
7 | * Allow create custom animation for the tab indicator line #155
8 |
9 | Version 1.1.0 *(01-06-2015)*
10 | ---------------------------------
11 | * Bug fixes
12 | * Rename some custom attributes.
13 | * Default ripple effect selector in 21+
14 | * Default sans-serif-medium tab's text in API 21+
15 | * app:pstsTextFontFamily for overriding the typeface from the XML. The attribute works exactly like android:fontFamily for TextViews.
16 | * Remove custom attire `pstsTextColorSelected ` and `pstsTextSelectedStyle`.
17 | * `pstsTabTextColor` will handle the tab text color states.
18 | * `pstsTabTextSize` will handle the tab text size.
19 | * Callbacks for selection/deselection of tabs passing the tab view as parameter when custom tabs are use.
20 |
21 | Version 1.0.9 *(22-02-2015)*
22 | ---------------------------------
23 | * Bug fixes
24 | * Add parsing of independent padding attributes (#69)
25 | * pstsTextAlpha value range change from 0..1 to 0..255.
26 | * New attr pstsTextColorSelected
27 | * R.id.tab_title changed to R.id.psts_tab_title
28 | * R.layout.tab changed to R.layout.psts_tab
29 | * R.drawable.background_tab changed to R.drawable.psts_background_tab
30 |
31 |
32 | Version 1.0.8 *(14-01-2015)*
33 | ----------------------------
34 | * Bug fixes
35 | * Ability to build the library using maven
36 | * Update support-v4 library to v21.0.3
37 |
38 | Version 1.0.7 *(08-01-2015)*
39 | ----------------------------
40 | * Bug fixes
41 | * OnTabReselectedListener
42 |
43 | Version 1.0.6 *(21-11-2014)*
44 | ----------------------------
45 | * Update support-v4 library to v21.0.2
46 | * Bug fixes
47 |
48 | Version 1.0.5 *(19-11-2014)*
49 | ----------------------------
50 | * android:textColorPrimary value (from your theme) will be applied automatically to tab's text color , underlineColor, dividerColor and indicatorColor, if any of these values are define in the xml layout.
51 | * Bug fixes
52 |
53 | Version 1.0.4 *(18-11-2014)*
54 | ----------------------------
55 | * Bug fixes
56 |
57 | Version 1.0.3 *(11-11-2014)*
58 | ----------------------------
59 |
60 | * Fix issues #7
61 | * Add support for colour state lists.
62 | * Add support for custom text style.
63 | * Add support for custom alpha values.
64 |
65 | Version 1.0.2 *(05-11-2014)*
66 | ----------------------------
67 | * MinSDK 10
68 |
69 | * Change the default parameters of the tabs layout to make
70 | it look like more material.
71 |
72 | * The indicator is center by default while swiping tabs and paddingMiddle attr
73 | has the possibility to start the tabs in the middle like newsstand google app.
74 |
75 | * The alpha value of the titles change depending the selected position.
76 |
77 | * Ability to change the divider width (No material change).
78 |
79 | * Ability to pass customTabs implementing the interface
80 | 'CustomTabProvider' in your adapter.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android PagerSlidingTabStrip (default Material Design)
2 |
3 | **This library is not maintained anymore and there will be no further releases. For most of the cases you can use [TabLayout](https://developer.android.com/reference/com/google/android/material/tabs/TabLayout) instead of this library.**
4 |
5 | Interactive paging indicator widget, compatible with the `ViewPager` from the
6 | Android Support Library.
7 |
8 |  ------
9 | 
10 |
11 | # Usage
12 |
13 | For a working implementation of this project see the `sample/` folder.
14 |
15 | 1. Include the following dependency in your `build.gradle` file.
16 |
17 | ```groovy
18 | compile 'com.jpardogo.materialtabstrip:library:1.1.1'
19 | ```
20 |
21 | Or add the library as a project. I tried to send a pull request, but looks like the original developer doesn't maintain it anymore.
22 |
23 | 2. Include the `PagerSlidingTabStrip` widget in your layout. This should usually be placed above the `ViewPager` it represents.
24 |
25 | ```xml
26 |
31 | ```
32 |
33 | 3. In your `onCreate` method (or `onCreateView` for a fragment), bind the widget to the `ViewPager`:
34 |
35 | ```java
36 | // Initialize the ViewPager and set an adapter
37 | ViewPager pager = (ViewPager) findViewById(R.id.pager);
38 | pager.setAdapter(new TestAdapter(getSupportFragmentManager()));
39 |
40 | // Bind the tabs to the ViewPager
41 | PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
42 | tabs.setViewPager(pager);
43 | ```
44 |
45 | ### That's all you need to do, but if you want to use your own tabs, then...
46 |
47 | 1. If your adapter implements the interface `CustomTabProvider` you can paste your custom tab view/s.
48 |
49 | - In case the the view returned contains the id `R.id.psts_tab_title`, this view should be a `TextView` and
50 | will be used to placed the title and set the view state (pressed/selected/default).
51 |
52 | - If you don't want the library manage your TextView title for the tab, use a different id than `R.id.psts_tab_title` in your tab layout.
53 |
54 | - The interface provide callbacks for selection and unselection of tabs as well.
55 |
56 | - If your adapter doesn't implement the interface `CustomTabProvider` the default tab will be used, which is a `TextView` with id `R.id.psts_tab_title`).
57 |
58 | 2. *(Optional)* If you use an `OnPageChangeListener` with your view pager
59 | you should set it in the widget rather than on the pager directly.
60 |
61 | ```java
62 | // continued from above
63 | tabs.setOnPageChangeListener(mPageChangeListener);
64 | ```
65 |
66 | # Customization
67 |
68 | From theme:
69 |
70 | * `android:textColorPrimary` value (from your theme) will be applied automatically to the tab's text color (Selected tab with 255 alpha and non selected tabs with 150 alpha), underlineColor, dividerColor and indicatorColor, if the values are not defined on the xml layout.
71 |
72 | Notes about some of the native attributes:
73 |
74 | * `android:paddingLeft` or `android:paddingRight` layout padding. If you apply both, they should be balanced. Check issue [#69](https://github.com/jpardogo/PagerSlidingTabStrip/pull/69) for more information.
75 |
76 | Custom attributes:
77 |
78 | * `pstsIndicatorColor` Color of the sliding indicator. `textColorPrimary` will be it's default color value.
79 | * `pstsIndicatorHeight`Height of the sliding indicator.
80 | * `pstsUnderlineColor` Color of the full-width line on the bottom of the view. `textColorPrimary` will be it's default color value.
81 | * `pstsUnderlineHeight` Height of the full-width line on the bottom of the view.
82 | * `pstsDividerColor` Color of the dividers between tabs. `textColorPrimary` will be it's default color value.
83 | * `pstsDividerWidth` Stroke width of divider line, defaults to 0.
84 | * `pstsDividerPadding` Top and bottom padding of the dividers.
85 | * `pstsShouldExpand` If set to true, each tab is given the same weight, default false.
86 | * `pstsScrollOffset` Scroll offset of the selected tab.
87 | * `pstsPaddingMiddle` If true, the tabs start at the middle of the view (Like Newsstand google app).
88 | * `pstsTabPaddingLeftRight` Left and right padding of each tab.
89 | * `pstsTabBackground` Background drawable of each tab, should be a StateListDrawable.
90 | * `pstsTabTextSize` Tab text size (sp).
91 | * `pstsTabTextColor` Tab text color that can either be a color (text color won't changed) or a selector with a color per state: pressed (tab pressed), selected (tab active), default (active non active). The order of states in the selector is important. Check issue [#68](https://github.com/jpardogo/PagerSlidingTabStrip/pull/70) for more information.
92 | * `pstsTabTextStyle` Set the text style, default normal on API 21, bold on older APIs.
93 | * `pstsTabTextAllCaps` If true, all tab titles will be upper case, default true.
94 | * `pstsTabTextAlpha` Set the text alpha transparency for non selected tabs. Range 0..255. 150 is it's default value. It **WON'T** be used if `pstsTabTextColor` is defined in the layout. If `pstsTabTextColor` is **NOT** defined, It will be applied to the non selected tabs.
95 | * `pstsTabTextFontFamily` Set the font family name. Default `sans-serif-medium` on API 21, `sans-serif` on older APIs.
96 |
97 | Almost all attributes have their respective getters and setters to change them at runtime. To change dynamically `pstsTabTextFontFamily` and `pstsTabTextStyle` you can call:
98 |
99 | * `public void setTypeface(Typeface typeface, int style)`. It can be used to define custom fonts in default tabs. Otherwise you can use custom tabs with `CustomTabProvider`.
100 |
101 | Please open an issue if you find any are missing.
102 |
103 | # Developed By
104 |
105 | * Javier Pardo de Santayana Gomez - [jpardogo.com](http://www.jpardogo.com) -
106 | * Andreas Stuetz -
107 | * And contributors.
108 |
109 | # Contributions
110 |
111 | * Please, read the README file before opening an issue, thanks.
112 | * Please, all the Pull Request must be sent to the dev branch, thanks..
113 |
114 | # Credits
115 |
116 | * [Kirill Grouchnikov](https://plus.google.com/108761828584265913206/posts) - Author of [an explanation post on Google+](https://plus.google.com/108761828584265913206/posts/Cwk7joBV3AC)
117 |
118 | # License
119 |
120 | Copyright 2013 Andreas Stuetz
121 |
122 | Licensed under the Apache License, Version 2.0 (the "License");
123 | you may not use this file except in compliance with the License.
124 | You may obtain a copy of the License at
125 |
126 | http://www.apache.org/licenses/LICENSE-2.0
127 |
128 | Unless required by applicable law or agreed to in writing, software
129 | distributed under the License is distributed on an "AS IS" BASIS,
130 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131 | See the License for the specific language governing permissions and
132 | limitations under the License.
133 |
--------------------------------------------------------------------------------
/art/material_tabs.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/art/material_tabs.gif
--------------------------------------------------------------------------------
/art/material_tabs_middle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/art/material_tabs_middle.gif
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 |
3 | repositories {
4 | mavenCentral()
5 | }
6 |
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.3'
9 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
10 | }
11 |
12 | }
13 |
14 | allprojects {
15 | version = VERSION_NAME
16 | group = GROUP
17 |
18 | repositories {
19 | mavenCentral()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_NAME=1.1.1
2 | GROUP=com.jpardogo.materialtabstrip
3 |
4 | SAMPLE_VERSION_NAME=1.0.2
5 | SAMPLE_VERSION_CODE=3
6 |
7 | POM_DESCRIPTION= ViewPager Material Tabs
8 | POM_URL=https://github.com/jpardogo/PagerSlidingTabStrip
9 | POM_SCM_URL=https://github.com/jpardogo/PagerSlidingTabStrip
10 | POM_SCM_CONNECTION=scm:git@github.com:jpardogo/PagerSlidingTabStrip.git
11 | POM_SCM_DEV_CONNECTION=scm:git@github.com:jpardogo/PagerSlidingTabStrip.git
12 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
13 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
14 | POM_LICENCE_DIST=repo
15 | POM_DEVELOPER_ID=astuetz
16 | POM_DEVELOPER_NAME=Andreas Stuetz
17 | ANDROID_BUILD_TARGET_SDK_VERSION=24
18 | ANDROID_BUILD_TOOLS_VERSION=24.0.2
19 | ANDROID_BUILD_MIN_SDK_VERSION=10
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Aug 26 16:50:50 BST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | dependencies {
4 | compile "com.android.support:support-core-ui:24.2.0"
5 | }
6 |
7 | android {
8 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
9 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
10 |
11 | defaultConfig {
12 | minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
13 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
14 | }
15 |
16 | android {
17 | lintOptions {
18 | abortOnError false
19 | }
20 | }
21 |
22 | sourceSets {
23 | main {
24 | manifest.srcFile 'AndroidManifest.xml'
25 | java.srcDirs = ['src']
26 | res.srcDirs = ['res']
27 | }
28 | }
29 | }
30 |
31 | apply from: 'https://raw.githubusercontent.com/jpardogo/gradle-mvn-push/master/gradle-mvn-push.gradle'
--------------------------------------------------------------------------------
/library/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=PagerSlidingTabStrip_Material Library
2 | POM_ARTIFACT_ID=library
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/library/res/drawable-v21/psts_background_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/library/res/drawable/psts_background_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/res/layout/psts_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/library/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/library/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1AFFFFFF
4 | #AAFFFFFF
5 |
6 |
--------------------------------------------------------------------------------
/library/src/com/astuetz/PagerSlidingTabStrip.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Andreas Stuetz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.astuetz;
18 |
19 | import android.content.Context;
20 | import android.content.res.ColorStateList;
21 | import android.content.res.TypedArray;
22 | import android.database.DataSetObserver;
23 | import android.graphics.Canvas;
24 | import android.graphics.Color;
25 | import android.graphics.Paint;
26 | import android.graphics.Paint.Style;
27 | import android.graphics.Typeface;
28 | import android.os.Build;
29 | import android.os.Parcel;
30 | import android.os.Parcelable;
31 | import android.support.v4.content.ContextCompat;
32 | import android.support.v4.util.Pair;
33 | import android.support.v4.view.ViewPager;
34 | import android.support.v4.view.ViewPager.OnPageChangeListener;
35 | import android.util.AttributeSet;
36 | import android.util.DisplayMetrics;
37 | import android.util.TypedValue;
38 | import android.view.LayoutInflater;
39 | import android.view.View;
40 | import android.view.ViewGroup;
41 | import android.widget.HorizontalScrollView;
42 | import android.widget.LinearLayout;
43 | import android.widget.TextView;
44 |
45 | import com.astuetz.pagerslidingtabstrip.R;
46 |
47 | public class PagerSlidingTabStrip extends HorizontalScrollView {
48 |
49 | public static final int DEF_VALUE_TAB_TEXT_ALPHA = 150;
50 | private static final int[] ANDROID_ATTRS = new int[]{
51 | android.R.attr.textColorPrimary,
52 | android.R.attr.padding,
53 | android.R.attr.paddingLeft,
54 | android.R.attr.paddingRight,
55 | };
56 |
57 | //These indexes must be related with the ATTR array above
58 | private static final int TEXT_COLOR_PRIMARY = 0;
59 | private static final int PADDING_INDEX = 1;
60 | private static final int PADDING_LEFT_INDEX = 2;
61 | private static final int PADDING_RIGHT_INDEX = 3;
62 |
63 | private LinearLayout mTabsContainer;
64 | private LinearLayout.LayoutParams mTabLayoutParams;
65 |
66 | private final PagerAdapterObserver mAdapterObserver = new PagerAdapterObserver();
67 | private final PageListener mPageListener = new PageListener();
68 | private OnTabReselectedListener mTabReselectedListener = null;
69 | public OnPageChangeListener mDelegatePageListener;
70 | private ViewPager mPager;
71 |
72 | private int mTabCount;
73 |
74 | private int mCurrentPosition = 0;
75 | private float mCurrentPositionOffset = 0f;
76 |
77 | private Paint mRectPaint;
78 | private Paint mDividerPaint;
79 |
80 | private int mIndicatorColor;
81 | private int mIndicatorHeight = 2;
82 |
83 | private int mUnderlineHeight = 0;
84 | private int mUnderlineColor;
85 |
86 | private int mDividerWidth = 0;
87 | private int mDividerPadding = 0;
88 | private int mDividerColor;
89 |
90 | private int mTabPadding = 12;
91 | private int mTabTextSize = 14;
92 | private ColorStateList mTabTextColor = null;
93 |
94 | private int mPaddingLeft = 0;
95 | private int mPaddingRight = 0;
96 |
97 | private boolean isExpandTabs = false;
98 | private boolean isCustomTabs;
99 | private boolean isPaddingMiddle = false;
100 | private boolean isTabTextAllCaps = true;
101 |
102 | private Typeface mTabTextTypeface = null;
103 | private int mTabTextTypefaceStyle = Typeface.BOLD;
104 |
105 | private int mScrollOffset;
106 | private int mLastScrollX = 0;
107 |
108 | private int mTabBackgroundResId = R.drawable.psts_background_tab;
109 |
110 | public PagerSlidingTabStrip(Context context) {
111 | this(context, null);
112 | }
113 |
114 | public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
115 | this(context, attrs, 0);
116 | }
117 |
118 | public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
119 | super(context, attrs, defStyle);
120 | setFillViewport(true);
121 | setWillNotDraw(false);
122 | mTabsContainer = new LinearLayout(context);
123 | mTabsContainer.setOrientation(LinearLayout.HORIZONTAL);
124 | addView(mTabsContainer);
125 |
126 | mRectPaint = new Paint();
127 | mRectPaint.setAntiAlias(true);
128 | mRectPaint.setStyle(Style.FILL);
129 |
130 | DisplayMetrics dm = getResources().getDisplayMetrics();
131 | mScrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mScrollOffset, dm);
132 | mIndicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mIndicatorHeight, dm);
133 | mUnderlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mUnderlineHeight, dm);
134 | mDividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mDividerPadding, dm);
135 | mTabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mTabPadding, dm);
136 | mDividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mDividerWidth, dm);
137 | mTabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mTabTextSize, dm);
138 |
139 | mDividerPaint = new Paint();
140 | mDividerPaint.setAntiAlias(true);
141 | mDividerPaint.setStrokeWidth(mDividerWidth);
142 |
143 | // get system attrs for container
144 | TypedArray a = context.obtainStyledAttributes(attrs, ANDROID_ATTRS);
145 | int textPrimaryColor = a.getColor(TEXT_COLOR_PRIMARY, ContextCompat.getColor(context, android.R.color.black));
146 | mUnderlineColor = textPrimaryColor;
147 | mDividerColor = textPrimaryColor;
148 | mIndicatorColor = textPrimaryColor;
149 | int padding = a.getDimensionPixelSize(PADDING_INDEX, 0);
150 | mPaddingLeft = padding > 0 ? padding : a.getDimensionPixelSize(PADDING_LEFT_INDEX, 0);
151 | mPaddingRight = padding > 0 ? padding : a.getDimensionPixelSize(PADDING_RIGHT_INDEX, 0);
152 | a.recycle();
153 |
154 | String tabTextTypefaceName = "sans-serif";
155 | // Use Roboto Medium as the default typeface from API 21 onwards
156 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
157 | tabTextTypefaceName = "sans-serif-medium";
158 | mTabTextTypefaceStyle = Typeface.NORMAL;
159 | }
160 |
161 | // get custom attrs for tabs and container
162 | a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
163 | mIndicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, mIndicatorColor);
164 | mIndicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, mIndicatorHeight);
165 | mUnderlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, mUnderlineColor);
166 | mUnderlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, mUnderlineHeight);
167 | mDividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, mDividerColor);
168 | mDividerWidth = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerWidth, mDividerWidth);
169 | mDividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, mDividerPadding);
170 | isExpandTabs = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, isExpandTabs);
171 | mScrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, mScrollOffset);
172 | isPaddingMiddle = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsPaddingMiddle, isPaddingMiddle);
173 | mTabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, mTabPadding);
174 | mTabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_pstsTabBackground, mTabBackgroundResId);
175 | mTabTextSize = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabTextSize, mTabTextSize);
176 | mTabTextColor = a.hasValue(R.styleable.PagerSlidingTabStrip_pstsTabTextColor) ? a.getColorStateList(R.styleable.PagerSlidingTabStrip_pstsTabTextColor) : null;
177 | mTabTextTypefaceStyle = a.getInt(R.styleable.PagerSlidingTabStrip_pstsTabTextStyle, mTabTextTypefaceStyle);
178 | isTabTextAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTabTextAllCaps, isTabTextAllCaps);
179 | int tabTextAlpha = a.getInt(R.styleable.PagerSlidingTabStrip_pstsTabTextAlpha, DEF_VALUE_TAB_TEXT_ALPHA);
180 | String fontFamily = a.getString(R.styleable.PagerSlidingTabStrip_pstsTabTextFontFamily);
181 | a.recycle();
182 |
183 | //Tab text color selector
184 | if (mTabTextColor == null) {
185 | mTabTextColor = createColorStateList(
186 | textPrimaryColor,
187 | textPrimaryColor,
188 | Color.argb(tabTextAlpha,
189 | Color.red(textPrimaryColor),
190 | Color.green(textPrimaryColor),
191 | Color.blue(textPrimaryColor)));
192 | }
193 |
194 | //Tab text typeface and style
195 | if (fontFamily != null) {
196 | tabTextTypefaceName = fontFamily;
197 | }
198 | mTabTextTypeface = Typeface.create(tabTextTypefaceName, mTabTextTypefaceStyle);
199 |
200 | //Bottom padding for the tabs container parent view to show indicator and underline
201 | setTabsContainerParentViewPaddings();
202 |
203 | //Configure tab's container LayoutParams for either equal divided space or just wrap tabs
204 | mTabLayoutParams = isExpandTabs ?
205 | new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f) :
206 | new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
207 | }
208 |
209 | private void setTabsContainerParentViewPaddings() {
210 | int bottomMargin = mIndicatorHeight >= mUnderlineHeight ? mIndicatorHeight : mUnderlineHeight;
211 | setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottomMargin);
212 | }
213 |
214 | public void setViewPager(ViewPager pager) {
215 | this.mPager = pager;
216 | if (pager.getAdapter() == null) {
217 | throw new IllegalStateException("ViewPager does not have adapter instance.");
218 | }
219 |
220 | isCustomTabs = pager.getAdapter() instanceof CustomTabProvider;
221 | pager.addOnPageChangeListener(mPageListener);
222 | pager.getAdapter().registerDataSetObserver(mAdapterObserver);
223 | mAdapterObserver.setAttached(true);
224 | notifyDataSetChanged();
225 | }
226 |
227 | public void notifyDataSetChanged() {
228 | mTabsContainer.removeAllViews();
229 | mTabCount = mPager.getAdapter().getCount();
230 | View tabView;
231 | for (int i = 0; i < mTabCount; i++) {
232 | if (isCustomTabs) {
233 | tabView = ((CustomTabProvider) mPager.getAdapter()).getCustomTabView(this, i);
234 | } else {
235 | tabView = LayoutInflater.from(getContext()).inflate(R.layout.psts_tab, this, false);
236 | }
237 |
238 | CharSequence title = mPager.getAdapter().getPageTitle(i);
239 | addTab(i, title, tabView);
240 | }
241 |
242 | updateTabStyles();
243 | }
244 |
245 | private void addTab(final int position, CharSequence title, View tabView) {
246 | TextView textView = (TextView) tabView.findViewById(R.id.psts_tab_title);
247 | if (textView != null) {
248 | if (title != null) textView.setText(title);
249 | }
250 |
251 | tabView.setFocusable(true);
252 | tabView.setOnClickListener(new OnClickListener() {
253 | @Override
254 | public void onClick(View v) {
255 | if (mPager.getCurrentItem() != position) {
256 | View tab = mTabsContainer.getChildAt(mPager.getCurrentItem());
257 | unSelect(tab);
258 | mPager.setCurrentItem(position);
259 | } else if (mTabReselectedListener != null) {
260 | mTabReselectedListener.onTabReselected(position);
261 | }
262 | }
263 | });
264 |
265 | mTabsContainer.addView(tabView, position, mTabLayoutParams);
266 | }
267 |
268 | private void updateTabStyles() {
269 | for (int i = 0; i < mTabCount; i++) {
270 | View v = mTabsContainer.getChildAt(i);
271 | v.setBackgroundResource(mTabBackgroundResId);
272 | v.setPadding(mTabPadding, v.getPaddingTop(), mTabPadding, v.getPaddingBottom());
273 | TextView tab_title = (TextView) v.findViewById(R.id.psts_tab_title);
274 | if (tab_title != null) {
275 | tab_title.setTextColor(mTabTextColor);
276 | tab_title.setTypeface(mTabTextTypeface, mTabTextTypefaceStyle);
277 | tab_title.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTabTextSize);
278 | // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
279 | // pre-ICS-build
280 | if (isTabTextAllCaps) {
281 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
282 | tab_title.setAllCaps(true);
283 | } else {
284 | tab_title.setText(tab_title.getText().toString().toUpperCase());
285 | }
286 | }
287 | }
288 | }
289 | }
290 |
291 | private void scrollToChild(int position, int offset) {
292 | if (mTabCount == 0) {
293 | return;
294 | }
295 |
296 | int newScrollX = mTabsContainer.getChildAt(position).getLeft() + offset;
297 | if (position > 0 || offset > 0) {
298 | //Half screen offset.
299 | //- Either tabs start at the middle of the view scrolling straight away
300 | //- Or tabs start at the begging (no padding) scrolling when indicator gets
301 | // to the middle of the view width
302 | newScrollX -= mScrollOffset;
303 | Pair lines = getIndicatorCoordinates();
304 | newScrollX += ((lines.second - lines.first) / 2);
305 | }
306 |
307 | if (newScrollX != mLastScrollX) {
308 | mLastScrollX = newScrollX;
309 | scrollTo(newScrollX, 0);
310 | }
311 | }
312 |
313 | public Pair getIndicatorCoordinates() {
314 | // default: line below current tab
315 | View currentTab = mTabsContainer.getChildAt(mCurrentPosition);
316 | float lineLeft = currentTab.getLeft();
317 | float lineRight = currentTab.getRight();
318 | // if there is an offset, start interpolating left and right coordinates between current and next tab
319 | if (mCurrentPositionOffset > 0f && mCurrentPosition < mTabCount - 1) {
320 | View nextTab = mTabsContainer.getChildAt(mCurrentPosition + 1);
321 | final float nextTabLeft = nextTab.getLeft();
322 | final float nextTabRight = nextTab.getRight();
323 | lineLeft = (mCurrentPositionOffset * nextTabLeft + (1f - mCurrentPositionOffset) * lineLeft);
324 | lineRight = (mCurrentPositionOffset * nextTabRight + (1f - mCurrentPositionOffset) * lineRight);
325 | }
326 |
327 | return new Pair<>(lineLeft, lineRight);
328 | }
329 |
330 | @Override
331 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
332 | if (isPaddingMiddle && mTabsContainer.getChildCount() > 0) {
333 | View view = mTabsContainer.getChildAt(0);
334 | int halfWidthFirstTab = view.getMeasuredWidth() / 2;
335 | mPaddingLeft = mPaddingRight = getWidth() / 2 - halfWidthFirstTab;
336 | }
337 |
338 | if (isPaddingMiddle || mPaddingLeft > 0 || mPaddingRight > 0) {
339 | int width;
340 | if (isPaddingMiddle) {
341 | width = getWidth();
342 | } else {
343 | // Account for manually set padding for offsetting tab start and end positions.
344 | width = getWidth() - mPaddingLeft - mPaddingRight;
345 | }
346 |
347 | //Make sure tabContainer is bigger than the HorizontalScrollView to be able to scroll
348 | mTabsContainer.setMinimumWidth(width);
349 | //Clipping padding to false to see the tabs while we pass them swiping
350 | setClipToPadding(false);
351 | }
352 |
353 | setPadding(mPaddingLeft, getPaddingTop(), mPaddingRight, getPaddingBottom());
354 | if (mScrollOffset == 0) {
355 | mScrollOffset = getWidth() / 2 - mPaddingLeft;
356 | }
357 |
358 | if (mPager != null) {
359 | mCurrentPosition = mPager.getCurrentItem();
360 | }
361 |
362 | mCurrentPositionOffset = 0f;
363 | scrollToChild(mCurrentPosition, 0);
364 | updateSelection(mCurrentPosition);
365 | super.onLayout(changed, l, t, r, b);
366 | }
367 |
368 | @Override
369 | protected void onDraw(Canvas canvas) {
370 | super.onDraw(canvas);
371 | if (isInEditMode() || mTabCount == 0) {
372 | return;
373 | }
374 |
375 | final int height = getHeight();
376 | // draw divider
377 | if (mDividerWidth > 0) {
378 | mDividerPaint.setStrokeWidth(mDividerWidth);
379 | mDividerPaint.setColor(mDividerColor);
380 | for (int i = 0; i < mTabCount - 1; i++) {
381 | View tab = mTabsContainer.getChildAt(i);
382 | canvas.drawLine(tab.getRight(), mDividerPadding, tab.getRight(), height - mDividerPadding, mDividerPaint);
383 | }
384 | }
385 |
386 | // draw underline
387 | if (mUnderlineHeight > 0) {
388 | mRectPaint.setColor(mUnderlineColor);
389 | canvas.drawRect(mPaddingLeft, height - mUnderlineHeight, mTabsContainer.getWidth() + mPaddingRight, height, mRectPaint);
390 | }
391 |
392 | // draw indicator line
393 | if (mIndicatorHeight > 0) {
394 | mRectPaint.setColor(mIndicatorColor);
395 | Pair lines = getIndicatorCoordinates();
396 | canvas.drawRect(lines.first + mPaddingLeft, height - mIndicatorHeight, lines.second + mPaddingLeft, height, mRectPaint);
397 | }
398 | }
399 |
400 | public void setOnTabReselectedListener(OnTabReselectedListener tabReselectedListener) {
401 | this.mTabReselectedListener = tabReselectedListener;
402 | }
403 |
404 | public void setOnPageChangeListener(OnPageChangeListener listener) {
405 | this.mDelegatePageListener = listener;
406 | }
407 |
408 | private class PageListener implements OnPageChangeListener {
409 |
410 | @Override
411 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
412 | mCurrentPosition = position;
413 | mCurrentPositionOffset = positionOffset;
414 | int offset = mTabCount > 0 ? (int) (positionOffset * mTabsContainer.getChildAt(position).getWidth()) : 0;
415 | scrollToChild(position, offset);
416 | invalidate();
417 | if (mDelegatePageListener != null) {
418 | mDelegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
419 | }
420 | }
421 |
422 | @Override
423 | public void onPageScrollStateChanged(int state) {
424 | if (state == ViewPager.SCROLL_STATE_IDLE) {
425 | scrollToChild(mPager.getCurrentItem(), 0);
426 | }
427 | if (mDelegatePageListener != null) {
428 | mDelegatePageListener.onPageScrollStateChanged(state);
429 | }
430 | }
431 |
432 | @Override
433 | public void onPageSelected(int position) {
434 | updateSelection(position);
435 |
436 | //Select current item
437 | View currentTab = mTabsContainer.getChildAt(position);
438 | select(currentTab);
439 | //Unselect prev item
440 | if (position > 0) {
441 | View prevTab = mTabsContainer.getChildAt(position - 1);
442 | unSelect(prevTab);
443 | }
444 | //Unselect next item
445 | if (position < mPager.getAdapter().getCount() - 1) {
446 | View nextTab = mTabsContainer.getChildAt(position + 1);
447 | unSelect(nextTab);
448 | }
449 |
450 | if (mDelegatePageListener != null) {
451 | mDelegatePageListener.onPageSelected(position);
452 | }
453 | }
454 |
455 | }
456 |
457 | private void updateSelection(int position) {
458 | for (int i = 0; i < mTabCount; ++i) {
459 | View tv = mTabsContainer.getChildAt(i);
460 | final boolean selected = i == position;
461 | if (selected) {
462 | select(tv);
463 | } else {
464 | unSelect(tv);
465 | }
466 | }
467 | }
468 |
469 | private void unSelect(View tab) {
470 | if (tab != null) {
471 | TextView tab_title = (TextView) tab.findViewById(R.id.psts_tab_title);
472 | if (tab_title != null) {
473 | tab_title.setSelected(false);
474 | }
475 | if (isCustomTabs) ((CustomTabProvider) mPager.getAdapter()).tabUnselected(tab);
476 | }
477 | }
478 |
479 | private void select(View tab) {
480 | if (tab != null) {
481 | TextView tab_title = (TextView) tab.findViewById(R.id.psts_tab_title);
482 | if (tab_title != null) {
483 | tab_title.setSelected(true);
484 | }
485 | if (isCustomTabs) ((CustomTabProvider) mPager.getAdapter()).tabSelected(tab);
486 | }
487 | }
488 |
489 | private class PagerAdapterObserver extends DataSetObserver {
490 |
491 | private boolean attached = false;
492 |
493 | @Override
494 | public void onChanged() {
495 | notifyDataSetChanged();
496 | }
497 |
498 | void setAttached(boolean attached) {
499 | this.attached = attached;
500 | }
501 |
502 | boolean isAttached() {
503 | return attached;
504 | }
505 | }
506 |
507 | @Override
508 | protected void onAttachedToWindow() {
509 | super.onAttachedToWindow();
510 | if (mPager != null) {
511 | if (!mAdapterObserver.isAttached()) {
512 | mPager.getAdapter().registerDataSetObserver(mAdapterObserver);
513 | mAdapterObserver.setAttached(true);
514 | }
515 | }
516 | }
517 |
518 | @Override
519 | protected void onDetachedFromWindow() {
520 | super.onDetachedFromWindow();
521 | if (mPager != null) {
522 | if (mAdapterObserver.isAttached()) {
523 | mPager.getAdapter().unregisterDataSetObserver(mAdapterObserver);
524 | mAdapterObserver.setAttached(false);
525 | }
526 | }
527 | }
528 |
529 | @Override
530 | public void onRestoreInstanceState(Parcelable state) {
531 | SavedState savedState = (SavedState) state;
532 | super.onRestoreInstanceState(savedState.getSuperState());
533 | mCurrentPosition = savedState.currentPosition;
534 | if (mCurrentPosition != 0 && mTabsContainer.getChildCount() > 0) {
535 | unSelect(mTabsContainer.getChildAt(0));
536 | select(mTabsContainer.getChildAt(mCurrentPosition));
537 | }
538 | requestLayout();
539 | }
540 |
541 | @Override
542 | public Parcelable onSaveInstanceState() {
543 | Parcelable superState = super.onSaveInstanceState();
544 | SavedState savedState = new SavedState(superState);
545 | savedState.currentPosition = mCurrentPosition;
546 | return savedState;
547 | }
548 |
549 | static class SavedState extends BaseSavedState {
550 | int currentPosition;
551 |
552 | SavedState(Parcelable superState) {
553 | super(superState);
554 | }
555 |
556 | private SavedState(Parcel in) {
557 | super(in);
558 | currentPosition = in.readInt();
559 | }
560 |
561 | @Override
562 | public void writeToParcel(Parcel dest, int flags) {
563 | super.writeToParcel(dest, flags);
564 | dest.writeInt(currentPosition);
565 | }
566 |
567 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
568 | @Override
569 | public SavedState createFromParcel(Parcel in) {
570 | return new SavedState(in);
571 | }
572 |
573 | @Override
574 | public SavedState[] newArray(int size) {
575 | return new SavedState[size];
576 | }
577 | };
578 | }
579 |
580 | public int getIndicatorColor() {
581 | return this.mIndicatorColor;
582 | }
583 |
584 | public int getIndicatorHeight() {
585 | return mIndicatorHeight;
586 | }
587 |
588 | public int getUnderlineColor() {
589 | return mUnderlineColor;
590 | }
591 |
592 | public int getDividerColor() {
593 | return mDividerColor;
594 | }
595 |
596 | public int getDividerWidth() {
597 | return mDividerWidth;
598 | }
599 |
600 | public int getUnderlineHeight() {
601 | return mUnderlineHeight;
602 | }
603 |
604 | public int getDividerPadding() {
605 | return mDividerPadding;
606 | }
607 |
608 | public int getScrollOffset() {
609 | return mScrollOffset;
610 | }
611 |
612 | public boolean getShouldExpand() {
613 | return isExpandTabs;
614 | }
615 |
616 | public int getTextSize() {
617 | return mTabTextSize;
618 | }
619 |
620 | public boolean isTextAllCaps() {
621 | return isTabTextAllCaps;
622 | }
623 |
624 | public ColorStateList getTextColor() {
625 | return mTabTextColor;
626 | }
627 |
628 | public int getTabBackground() {
629 | return mTabBackgroundResId;
630 | }
631 |
632 | public int getTabPaddingLeftRight() {
633 | return mTabPadding;
634 | }
635 |
636 | public LinearLayout getTabsContainer() {
637 | return mTabsContainer;
638 | }
639 |
640 | public int getTabCount() {
641 | return mTabCount;
642 | }
643 |
644 | public int getCurrentPosition() {
645 | return mCurrentPosition;
646 | }
647 |
648 | public float getCurrentPositionOffset() {
649 | return mCurrentPositionOffset;
650 | }
651 |
652 | public void setIndicatorColor(int indicatorColor) {
653 | this.mIndicatorColor = indicatorColor;
654 | invalidate();
655 | }
656 |
657 | public void setIndicatorColorResource(int resId) {
658 | this.mIndicatorColor = ContextCompat.getColor(getContext(), resId);
659 | invalidate();
660 | }
661 |
662 | public void setIndicatorHeight(int indicatorLineHeightPx) {
663 | this.mIndicatorHeight = indicatorLineHeightPx;
664 | invalidate();
665 | }
666 |
667 | public void setUnderlineColor(int underlineColor) {
668 | this.mUnderlineColor = underlineColor;
669 | invalidate();
670 | }
671 |
672 | public void setUnderlineColorResource(int resId) {
673 | this.mUnderlineColor = ContextCompat.getColor(getContext(), resId);
674 | invalidate();
675 | }
676 |
677 | public void setDividerColor(int dividerColor) {
678 | this.mDividerColor = dividerColor;
679 | invalidate();
680 | }
681 |
682 | public void setDividerColorResource(int resId) {
683 | this.mDividerColor = ContextCompat.getColor(getContext(), resId);
684 | invalidate();
685 | }
686 |
687 | public void setDividerWidth(int dividerWidthPx) {
688 | this.mDividerWidth = dividerWidthPx;
689 | invalidate();
690 | }
691 |
692 | public void setUnderlineHeight(int underlineHeightPx) {
693 | this.mUnderlineHeight = underlineHeightPx;
694 | invalidate();
695 | }
696 |
697 | public void setDividerPadding(int dividerPaddingPx) {
698 | this.mDividerPadding = dividerPaddingPx;
699 | invalidate();
700 | }
701 |
702 | public void setScrollOffset(int scrollOffsetPx) {
703 | this.mScrollOffset = scrollOffsetPx;
704 | invalidate();
705 | }
706 |
707 | public void setShouldExpand(boolean shouldExpand) {
708 | this.isExpandTabs = shouldExpand;
709 | if (mPager != null) {
710 | requestLayout();
711 | }
712 | }
713 |
714 | public void setAllCaps(boolean textAllCaps) {
715 | this.isTabTextAllCaps = textAllCaps;
716 | }
717 |
718 | public void setTextSize(int textSizePx) {
719 | this.mTabTextSize = textSizePx;
720 | updateTabStyles();
721 | }
722 |
723 | public void setTextColorResource(int resId) {
724 | setTextColor(ContextCompat.getColor(getContext(), resId));
725 | }
726 |
727 | public void setTextColor(int textColor) {
728 | setTextColor(createColorStateList(textColor));
729 | }
730 |
731 | public void setTextColorStateListResource(int resId) {
732 | setTextColor(ContextCompat.getColorStateList(getContext(), resId));
733 | }
734 |
735 | public void setTextColor(ColorStateList colorStateList) {
736 | this.mTabTextColor = colorStateList;
737 | updateTabStyles();
738 | }
739 |
740 | private ColorStateList createColorStateList(int color_state_default) {
741 | return new ColorStateList(
742 | new int[][]{
743 | new int[]{} //default
744 | },
745 | new int[]{
746 | color_state_default //default
747 | }
748 | );
749 | }
750 |
751 | private ColorStateList createColorStateList(int color_state_pressed, int color_state_selected, int color_state_default) {
752 | return new ColorStateList(
753 | new int[][]{
754 | new int[]{android.R.attr.state_pressed}, //pressed
755 | new int[]{android.R.attr.state_selected}, // enabled
756 | new int[]{} //default
757 | },
758 | new int[]{
759 | color_state_pressed,
760 | color_state_selected,
761 | color_state_default
762 | }
763 | );
764 | }
765 |
766 | public void setTypeface(Typeface typeface, int style) {
767 | this.mTabTextTypeface = typeface;
768 | this.mTabTextTypefaceStyle = style;
769 | updateTabStyles();
770 | }
771 |
772 | public void setTabBackground(int resId) {
773 | this.mTabBackgroundResId = resId;
774 | }
775 |
776 | public void setTabPaddingLeftRight(int paddingPx) {
777 | this.mTabPadding = paddingPx;
778 | updateTabStyles();
779 | }
780 |
781 | public interface CustomTabProvider {
782 | View getCustomTabView(ViewGroup parent, int position);
783 |
784 | void tabSelected(View tab);
785 |
786 | void tabUnselected(View tab);
787 | }
788 |
789 | public interface OnTabReselectedListener {
790 | void onTabReselected(int position);
791 | }
792 | }
793 |
--------------------------------------------------------------------------------
/sample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'android-apt'
3 |
4 | repositories {
5 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
6 | mavenCentral()
7 | }
8 |
9 |
10 | dependencies {
11 | compile project(':library')
12 | compile "com.android.support:appcompat-v7:24.2.0"
13 | compile 'com.android.support:cardview-v7:24.2.0'
14 | compile 'com.jakewharton:butterknife:8.4.0'
15 | apt 'com.jakewharton:butterknife-compiler:8.4.0'
16 | compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
17 | compile 'com.nineoldandroids:library:2.4.0'
18 | }
19 |
20 | android {
21 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
22 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
23 |
24 | defaultConfig {
25 | minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
26 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
27 |
28 | versionName project.SAMPLE_VERSION_NAME
29 | versionCode Integer.parseInt(project.SAMPLE_VERSION_CODE)
30 | }
31 |
32 | signingConfigs { release }
33 |
34 | buildTypes {
35 | release {
36 | signingConfig signingConfigs.release
37 | }
38 | }
39 |
40 | sourceSets {
41 | main {
42 | manifest.srcFile 'AndroidManifest.xml'
43 | java.srcDirs = ['src']
44 | res.srcDirs = ['res']
45 | }
46 | }
47 |
48 | android {
49 | lintOptions {
50 | abortOnError false
51 | }
52 | }
53 | }
54 |
55 | File propFile = file('signing.properties');
56 | if (propFile.exists()) {
57 | def Properties props = new Properties()
58 | props.load(new FileInputStream(propFile))
59 |
60 | if (props.containsKey('STORE_FILE') && props.containsKey('STORE_PASSWORD') &&
61 | props.containsKey('KEY_ALIAS') && props.containsKey('KEY_PASSWORD')) {
62 | android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
63 | android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
64 | android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
65 | android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
66 | } else {
67 | android.buildTypes.release.signingConfig = null
68 | }
69 | } else {
70 | android.buildTypes.release.signingConfig = null
71 | }
72 |
--------------------------------------------------------------------------------
/sample/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/ic_launcher-web.png
--------------------------------------------------------------------------------
/sample/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library.reference.1=../library
16 |
--------------------------------------------------------------------------------
/sample/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-hdpi/ic_launcher_actionbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-hdpi/ic_launcher_actionbar.png
--------------------------------------------------------------------------------
/sample/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-mdpi/ic_launcher_actionbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-mdpi/ic_launcher_actionbar.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/actionbar_bottom.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/actionbar_bottom.9.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/background_card.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/background_card.9.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/contact.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/contact.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_action_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_action_user.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher_actionbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher_actionbar.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher_chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher_chrome.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher_gmail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher_gmail.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher_gmaps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher_gmaps.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/ic_launcher_gplus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/ic_launcher_gplus.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/tabs_pattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/tabs_pattern.png
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/tabs_pattern_diagonal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xhdpi/tabs_pattern_diagonal.png
--------------------------------------------------------------------------------
/sample/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/res/drawable-xxhdpi/ic_launcher_actionbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jpardogo/PagerSlidingTabStrip/ab32788bda2742764871aea764c5aa3f038d1ace/sample/res/drawable-xxhdpi/ic_launcher_actionbar.png
--------------------------------------------------------------------------------
/sample/res/drawable/background_tabs.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/res/drawable/background_tabs_diagonal.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/res/layout-land/fragment_quick_contact.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
30 |
31 |
36 |
37 |
48 |
49 |
56 |
57 |
--------------------------------------------------------------------------------
/sample/res/layout-v11/custom_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/sample/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
14 |
15 |
21 |
22 |
30 |
31 |
39 |
40 |
48 |
49 |
57 |
58 |
66 |
67 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/sample/res/layout/custom_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
--------------------------------------------------------------------------------
/sample/res/layout/fragment_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
23 |
24 |
--------------------------------------------------------------------------------
/sample/res/layout/fragment_quick_contact.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
24 |
25 |
31 |
32 |
37 |
38 |
--------------------------------------------------------------------------------
/sample/res/layout/fragment_quickcontact.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sample/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
--------------------------------------------------------------------------------
/sample/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/sample/res/values-v11/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/sample/res/values-v19/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFE5E5E5
4 | #689F38
5 | #3E5F22
6 | #FFCC00
7 |
--------------------------------------------------------------------------------
/sample/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | PagerSlidingTabStrip
5 | Contact
6 |
7 |
--------------------------------------------------------------------------------
/sample/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/sample/src/com/astuetz/viewpager/extensions/sample/LinearLayoutFeedback.java:
--------------------------------------------------------------------------------
1 | package com.astuetz.viewpager.extensions.sample;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.drawable.Drawable;
8 | import android.os.Build;
9 | import android.support.annotation.NonNull;
10 | import android.util.AttributeSet;
11 | import android.widget.LinearLayout;
12 |
13 | /**
14 | * Created by Javier on 23/03/15.
15 | */
16 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
17 | public class LinearLayoutFeedback extends LinearLayout {
18 | private final Drawable mForegroundDrawable;
19 |
20 | public LinearLayoutFeedback(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public LinearLayoutFeedback(Context context, AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public LinearLayoutFeedback(Context context, AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | TypedArray a = getContext().obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});
31 | mForegroundDrawable = a.getDrawable(0);
32 | if (mForegroundDrawable != null) {
33 | mForegroundDrawable.setCallback(this);
34 | }
35 | a.recycle();
36 | }
37 |
38 | @Override
39 | protected void drawableStateChanged() {
40 | super.drawableStateChanged();
41 | mForegroundDrawable.setState(getDrawableState());
42 | invalidate();
43 | }
44 |
45 | @Override
46 | protected void dispatchDraw(Canvas canvas) {
47 | super.dispatchDraw(canvas);
48 | mForegroundDrawable.draw(canvas);
49 | }
50 |
51 | @Override
52 | protected void onSizeChanged(int width, int height, int oldwidth, int oldheight) {
53 | super.onSizeChanged(width, height, oldwidth, oldheight);
54 | mForegroundDrawable.setBounds(0, 0, width, height);
55 | }
56 |
57 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
58 | @Override
59 | public void drawableHotspotChanged(float x, float y) {
60 | super.drawableHotspotChanged(x, y);
61 | if (mForegroundDrawable != null) {
62 | mForegroundDrawable.setHotspot(x, y);
63 | }
64 | }
65 |
66 | @Override
67 | protected boolean verifyDrawable(@NonNull Drawable who) {
68 | return super.verifyDrawable(who) || (who == mForegroundDrawable);
69 | }
70 |
71 | @Override
72 | public void jumpDrawablesToCurrentState() {
73 | super.jumpDrawablesToCurrentState();
74 | mForegroundDrawable.jumpToCurrentState();
75 | }
76 | }
--------------------------------------------------------------------------------
/sample/src/com/astuetz/viewpager/extensions/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Andreas Stuetz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.astuetz.viewpager.extensions.sample;
18 |
19 | import android.graphics.Color;
20 | import android.graphics.drawable.ColorDrawable;
21 | import android.graphics.drawable.Drawable;
22 | import android.graphics.drawable.LayerDrawable;
23 | import android.graphics.drawable.TransitionDrawable;
24 | import android.os.Bundle;
25 | import android.support.v4.app.Fragment;
26 | import android.support.v4.app.FragmentManager;
27 | import android.support.v4.app.FragmentPagerAdapter;
28 | import android.support.v4.content.ContextCompat;
29 | import android.support.v4.view.ViewPager;
30 | import android.support.v7.app.ActionBarActivity;
31 | import android.support.v7.widget.Toolbar;
32 | import android.util.TypedValue;
33 | import android.view.Menu;
34 | import android.view.MenuItem;
35 | import android.view.View;
36 | import android.widget.Toast;
37 |
38 | import com.astuetz.PagerSlidingTabStrip;
39 | import com.readystatesoftware.systembartint.SystemBarTintManager;
40 |
41 | import butterknife.BindView;
42 | import butterknife.ButterKnife;
43 |
44 | public class MainActivity extends ActionBarActivity {
45 |
46 | @BindView(R.id.toolbar)
47 | Toolbar toolbar;
48 | @BindView(R.id.tabs)
49 | PagerSlidingTabStrip tabs;
50 | @BindView(R.id.pager)
51 | ViewPager pager;
52 |
53 | private MyPagerAdapter adapter;
54 | private Drawable oldBackground = null;
55 | private int currentColor;
56 | private SystemBarTintManager mTintManager;
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.activity_main);
62 | ButterKnife.bind(this);
63 | setSupportActionBar(toolbar);
64 | // create our manager instance after the content view is set
65 | mTintManager = new SystemBarTintManager(this);
66 | // enable status bar tint
67 | mTintManager.setStatusBarTintEnabled(true);
68 | adapter = new MyPagerAdapter(getSupportFragmentManager());
69 | pager.setAdapter(adapter);
70 | tabs.setViewPager(pager);
71 | final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources()
72 | .getDisplayMetrics());
73 | pager.setPageMargin(pageMargin);
74 | pager.setCurrentItem(1);
75 | changeColor(ContextCompat.getColor(getBaseContext(), R.color.green));
76 |
77 | tabs.setOnTabReselectedListener(new PagerSlidingTabStrip.OnTabReselectedListener() {
78 | @Override
79 | public void onTabReselected(int position) {
80 | Toast.makeText(MainActivity.this, "Tab reselected: " + position, Toast.LENGTH_SHORT).show();
81 | }
82 | });
83 | }
84 |
85 | @Override
86 | public boolean onCreateOptionsMenu(Menu menu) {
87 | getMenuInflater().inflate(R.menu.main, menu);
88 | return true;
89 | }
90 |
91 | @Override
92 | public boolean onOptionsItemSelected(MenuItem item) {
93 | switch (item.getItemId()) {
94 | case R.id.action_contact:
95 | QuickContactFragment.newInstance().show(getSupportFragmentManager(), "QuickContactFragment");
96 | return true;
97 | }
98 | return super.onOptionsItemSelected(item);
99 | }
100 |
101 | private void changeColor(int newColor) {
102 | tabs.setBackgroundColor(newColor);
103 | mTintManager.setTintColor(newColor);
104 | // change ActionBar color just if an ActionBar is available
105 | Drawable colorDrawable = new ColorDrawable(newColor);
106 | Drawable bottomDrawable = new ColorDrawable(ContextCompat.getColor(getBaseContext(), android.R.color.transparent));
107 | LayerDrawable ld = new LayerDrawable(new Drawable[]{colorDrawable, bottomDrawable});
108 | if (oldBackground == null) {
109 | getSupportActionBar().setBackgroundDrawable(ld);
110 | } else {
111 | TransitionDrawable td = new TransitionDrawable(new Drawable[]{oldBackground, ld});
112 | getSupportActionBar().setBackgroundDrawable(td);
113 | td.startTransition(200);
114 | }
115 |
116 | oldBackground = ld;
117 | currentColor = newColor;
118 | }
119 |
120 | public void onColorClicked(View v) {
121 | int color = Color.parseColor(v.getTag().toString());
122 | changeColor(color);
123 | }
124 |
125 | @Override
126 | protected void onSaveInstanceState(Bundle outState) {
127 | super.onSaveInstanceState(outState);
128 | outState.putInt("currentColor", currentColor);
129 | }
130 |
131 | @Override
132 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
133 | super.onRestoreInstanceState(savedInstanceState);
134 | currentColor = savedInstanceState.getInt("currentColor");
135 | changeColor(currentColor);
136 | }
137 |
138 | public class MyPagerAdapter extends FragmentPagerAdapter {
139 |
140 | private final String[] TITLES = {"Categories", "Home", "Top Paid", "Top Free", "Top Grossing", "Top New Paid",
141 | "Top New Free", "Trending"};
142 |
143 | MyPagerAdapter(FragmentManager fm) {
144 | super(fm);
145 | }
146 |
147 | @Override
148 | public CharSequence getPageTitle(int position) {
149 | return TITLES[position];
150 | }
151 |
152 | @Override
153 | public int getCount() {
154 | return TITLES.length;
155 | }
156 |
157 | @Override
158 | public Fragment getItem(int position) {
159 | return SuperAwesomeCardFragment.newInstance(position);
160 | }
161 | }
162 | }
--------------------------------------------------------------------------------
/sample/src/com/astuetz/viewpager/extensions/sample/QuickContactFragment.java:
--------------------------------------------------------------------------------
1 | package com.astuetz.viewpager.extensions.sample;
2 |
3 | import android.content.Context;
4 | import android.graphics.Point;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.support.v4.app.DialogFragment;
8 | import android.support.v4.view.PagerAdapter;
9 | import android.support.v4.view.ViewPager;
10 | import android.util.TypedValue;
11 | import android.view.Display;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.Window;
16 | import android.widget.ImageView;
17 | import android.widget.TextView;
18 |
19 | import com.astuetz.PagerSlidingTabStrip;
20 |
21 | import static com.astuetz.PagerSlidingTabStrip.CustomTabProvider;
22 |
23 | public class QuickContactFragment extends DialogFragment {
24 |
25 | public static QuickContactFragment newInstance() {
26 | return new QuickContactFragment();
27 | }
28 |
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
31 |
32 | if (getDialog() != null) {
33 | getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
34 | getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
35 | }
36 |
37 | View root = inflater.inflate(R.layout.fragment_quick_contact, container, false);
38 | PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) root.findViewById(R.id.tabs);
39 | ViewPager pager = (ViewPager) root.findViewById(R.id.pager);
40 | ContactPagerAdapter adapter = new ContactPagerAdapter(getActivity());
41 | pager.setAdapter(adapter);
42 | tabs.setViewPager(pager);
43 | return root;
44 | }
45 |
46 | @SuppressWarnings("deprecation")
47 | @Override
48 | public void onStart() {
49 | super.onStart();
50 |
51 | // change dialog width
52 | if (getDialog() != null) {
53 | int fullWidth;
54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
55 | Display display = getActivity().getWindowManager().getDefaultDisplay();
56 | Point size = new Point();
57 | display.getSize(size);
58 | fullWidth = size.x;
59 | } else {
60 | Display display = getActivity().getWindowManager().getDefaultDisplay();
61 | fullWidth = display.getWidth();
62 | }
63 |
64 | final int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources()
65 | .getDisplayMetrics());
66 | int w = fullWidth - padding;
67 | int h = getDialog().getWindow().getAttributes().height;
68 | getDialog().getWindow().setLayout(w, h);
69 | }
70 | }
71 |
72 | public static class ContactPagerAdapter extends PagerAdapter implements CustomTabProvider {
73 |
74 | private final int[] ICONS = {
75 | R.drawable.ic_launcher_gplus,
76 | R.drawable.ic_launcher_gmail,
77 | R.drawable.ic_launcher_gmaps,
78 | R.drawable.ic_launcher_chrome
79 | };
80 | private final String[] TITLES = {
81 | "GPlus",
82 | "GMail",
83 | "GMaps",
84 | "GChrome"
85 | };
86 |
87 | private final Context mContext;
88 |
89 | public ContactPagerAdapter(Context context) {
90 | super();
91 | mContext = context;
92 | }
93 |
94 | @Override
95 | public int getCount() {
96 | return ICONS.length;
97 | }
98 |
99 | @Override
100 | public CharSequence getPageTitle(int position) {
101 | return TITLES[position];
102 | }
103 |
104 | @Override
105 | public Object instantiateItem(ViewGroup container, int position) {
106 | TextView textview = (TextView) LayoutInflater.from(mContext).inflate(R.layout.fragment_quickcontact, container, false);
107 | textview.setText("PAGE " + position);
108 | container.addView(textview);
109 | return textview;
110 | }
111 |
112 | @Override
113 | public void destroyItem(ViewGroup container, int position, Object view) {
114 | container.removeView((View) view);
115 | }
116 |
117 | @Override
118 | public boolean isViewFromObject(View v, Object o) {
119 | return v == o;
120 | }
121 |
122 | @Override
123 | public View getCustomTabView(ViewGroup parent, int position) {
124 | View tab = LayoutInflater.from(mContext).inflate(R.layout.custom_tab, parent, false);
125 | ((ImageView) tab.findViewById(R.id.image)).setImageResource(ICONS[position]);
126 | return tab;
127 | }
128 |
129 | @Override
130 | public void tabSelected(View tab) {
131 | //Callback with the tab on his selected state. It is up to the developer to change anything on it.
132 | }
133 |
134 | @Override
135 | public void tabUnselected(View tab) {
136 | //Callback with the tab on his unselected state. It is up to the developer to change anything on it.
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/sample/src/com/astuetz/viewpager/extensions/sample/SuperAwesomeCardFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Andreas Stuetz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.astuetz.viewpager.extensions.sample;
18 |
19 | import android.os.Bundle;
20 | import android.support.v4.app.Fragment;
21 | import android.support.v4.view.ViewCompat;
22 | import android.view.LayoutInflater;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.widget.TextView;
26 |
27 | import butterknife.BindView;
28 | import butterknife.ButterKnife;
29 |
30 | public class SuperAwesomeCardFragment extends Fragment {
31 |
32 | private static final String ARG_POSITION = "position";
33 |
34 | @BindView(R.id.textView)
35 | TextView textView;
36 |
37 | private int position;
38 |
39 | public static SuperAwesomeCardFragment newInstance(int position) {
40 | SuperAwesomeCardFragment f = new SuperAwesomeCardFragment();
41 | Bundle b = new Bundle();
42 | b.putInt(ARG_POSITION, position);
43 | f.setArguments(b);
44 | return f;
45 | }
46 |
47 | @Override
48 | public void onCreate(Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | position = getArguments().getInt(ARG_POSITION);
51 | }
52 |
53 | @Override
54 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
55 | View rootView = inflater.inflate(R.layout.fragment_card,container,false);
56 | ButterKnife.bind(this, rootView);
57 | ViewCompat.setElevation(rootView, 50);
58 | textView.setText("CARD " + position);
59 | return rootView;
60 | }
61 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include 'library'
2 | include 'sample'
--------------------------------------------------------------------------------