├── README.md
├── TabController
├── .gitignore
├── .idea
│ ├── compiler.xml
│ ├── copyright
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── inspectionProfiles
│ │ ├── Project_Default.xml
│ │ └── profiles_settings.xml
│ ├── markdown-navigator.xml
│ ├── markdown-navigator
│ │ └── profiles_settings.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── sample
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── appolica
│ │ │ └── sample
│ │ │ └── ExampleInstrumentedTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── appolica
│ │ │ │ └── sample
│ │ │ │ ├── TabClickListener.java
│ │ │ │ ├── Tabs.java
│ │ │ │ ├── activity
│ │ │ │ ├── ActivitiesAdapter.java
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── TabControllerActivity.java
│ │ │ │ └── TabControllerFragmentActivity.java
│ │ │ │ └── tabs
│ │ │ │ ├── BottomBarListener.java
│ │ │ │ ├── FlatFragment.java
│ │ │ │ ├── NestedFragment.java
│ │ │ │ ├── pager
│ │ │ │ ├── PagerAdapter.java
│ │ │ │ └── ViewPagerFragment.java
│ │ │ │ └── stack
│ │ │ │ ├── StackFragment.java
│ │ │ │ └── StackFragmentClickListener.java
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── ic_tab_flat.png
│ │ │ ├── ic_tab_pager.png
│ │ │ └── ic_tab_stack.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── ic_tab_flat.png
│ │ │ ├── ic_tab_pager.png
│ │ │ └── ic_tab_stack.png
│ │ │ ├── drawable-xhdpi
│ │ │ ├── ic_tab_flat.png
│ │ │ ├── ic_tab_pager.png
│ │ │ └── ic_tab_stack.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── ic_tab_flat.png
│ │ │ ├── ic_tab_pager.png
│ │ │ └── ic_tab_stack.png
│ │ │ ├── layout
│ │ │ ├── activity_fragment_tab_controller.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── activity_tab_controller.xml
│ │ │ ├── fragment_stack_nested.xml
│ │ │ ├── fragment_tab.xml
│ │ │ ├── fragment_tab_flat.xml
│ │ │ ├── fragment_tab_stack.xml
│ │ │ ├── fragment_tab_view_pager.xml
│ │ │ └── list_item.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-w820dp
│ │ │ └── dimens.xml
│ │ │ ├── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── controller_tabs.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── appolica
│ │ └── sample
│ │ └── ExampleUnitTest.java
├── settings.gradle
└── tab-controller
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── appolica
│ │ └── tabcontroller
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── appolica
│ │ │ └── tabcontroller
│ │ │ ├── AttachDetachHandler.java
│ │ │ ├── FragmentProvider.java
│ │ │ ├── ShowHideFrHandler.java
│ │ │ ├── ShowHideHandler.java
│ │ │ ├── TabController.java
│ │ │ ├── fragment
│ │ │ └── TabControllerFragment.java
│ │ │ └── listener
│ │ │ ├── OnFragmentChangeListener.java
│ │ │ └── SimpleFragmentChangeListener.java
│ └── res
│ │ ├── layout
│ │ └── fragment_tab_controller.xml
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── appolica
│ └── tabcontroller
│ └── ExampleUnitTest.java
└── doc_resources
└── gif
└── sample.gif
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated. Please see https://developer.android.com/guide/navigation
2 | # TabControllerAndroid *by Appolica*
3 | This library provides an easy to use API for switching between fragments that share the same container. Implementing tabs, such as the ones Instagram has at the bottom of the layout, is a much simpler goal to achieve when using **TabController**.
4 | Tabs can be switched by using either show/hide or attach/detach. You can even provide your own implementation of the way tabs are being shown.
5 |
6 | The library is developed and maintained by [Appolica](http://www.appolica.com).
7 |
8 |
9 |
10 | *Note: The sample uses [BottomBar](https://github.com/roughike/BottomBar) in order to give a nice example of using this library. TabController is for managing fragments and does not provide any UI views.*
11 |
12 | ## Download
13 | [  ](https://bintray.com/appolica-ltd/maven/TabControllerAndroid/_latestVersion)
14 |
15 | ## Gradle
16 | ```gradle
17 | dependencies {
18 | ...
19 | compile 'com.appolica:tab-controller:1.0.3'
20 | }
21 | ```
22 |
23 | ## Example
24 |
25 | There are two ways of using this library. One is to use `TabControllerFragment`. It encapsulates all the fragments and their container into a single fragment.
26 |
27 | You can use it like any other fragment by adding it to the xml layout:
28 | ```xml
29 |
34 | ```
35 |
36 | or instantiating it and adding it by yourself:
37 |
38 | ```java
39 | final TabControllerFragment controllerFragment = new TabControllerFragment();
40 | getSupportFragmentManager()
41 | .beginTransaction()
42 | .add(conainerId, controllerFragment)
43 | .commitNow();
44 | ```
45 |
46 | Obtain the TabController instance simply like this:
47 | ```java
48 | final TabController tabController = controllerFragment.getTabController();
49 | ```
50 |
51 | ---
52 | The other way is to provide your own fragment container. If you choose to use this, you have to create the TabController instance by yourself:
53 |
54 | ```java
55 | final TabController tabController = new TabController(getSupportFragmentManager(), R.id.container);
56 | ```
57 | ---
58 |
59 | It doesn't matter whether you use your own container or TabControllerFragment. Once you obtain a TabController instance, everything is the same.
60 |
61 | In order to show your fragment you have to use `TabController::switchTo` method. This method accepts an implementation of `FragmentProvider`.
62 | Suppose you have multiple fragments and the first one is called `HomeFragment`. Then you would need something like `HomeFragmentProvider`, that implements `FragmentProvider`.
63 |
64 | ```java
65 | public class HomeFragment extends Fragment {
66 | public static final String TAG = "HomeFragment";
67 |
68 | public static HomeFragment getInstance(int tabNum) {
69 | final HomeFragment fragment = new HomeFragment();
70 |
71 | return tab;
72 | }
73 |
74 | ...
75 | }
76 | ```
77 | ```java
78 | class HomeFragmentProvider implements FragmentProvider{
79 | @Override
80 | public String getTag() {
81 | return HomeFragment.TAG;
82 | }
83 |
84 | @Override
85 | public Fragment getInstance() {
86 | return HomeFragment.getInstance();
87 | }
88 | }
89 | ```
90 | Create an instance of `HomeFragmentProvider` and pass it to `TabController::switchTo` in order to show your `HomeFragment`.
91 | ```java
92 | final HomeFragmentProvider homeProvider = new HomeFragmentProvider();
93 | tabController.switchTo(homeProvider);
94 | ```
95 | The `TabController` will create a new instance (by calling `FragmentProvider::getInstance`) of your fragment if it hasn't been already created. This depends on whether `FragmentManager::findFragmentByTag` returns `null` for the tag, given by `FragmentProvider::getTag`.
96 |
97 | ## API
98 |
99 | #### TabController
100 |
101 | ##### Constructors:
102 | * `TabController(FragmentManager fragmentManager, int containerId)` - Create a new instance of TabController with the default ShowHideHandler.
103 | * `TabController(FragmentManager fragmentManager, int containerId, ShowHideHandler showHideHandler)` - Create a new instance of TabController.
104 |
105 | ##### Public methods:
106 | * `void switchTo(FragmentProvider provider)` - Show the given fragment in the container, provided to the constructor. If `FragmentManager::findFragmentByTag` returns null for the tag, given by the provider, your fragment's instance will be obtained by calling `FragmentProvider::getInstance`. Otherwise it will be reused. If there is already a visible fragment, it will be hidden. How fragments are shown/hidden depends on ShowHideHandler.
107 | * `Fragment getVisibleFragment()` - Iterates through the fragments, returned by FragmentManager::getFragments. Returns the first visible fragment found in the list or null.
108 | * `Fragment getFragment(@NonNull FragmentProvider fragmentProvider)` - Find a fragment by it's `FragmentProvider`. Same as calling fragmentManager.findFragmentByTag(fragmentProvider.getTag());
109 | * `void save(Bundle savedInstanceState)` - Save the state of the `TabController` in order to be able to restore your last visible fragment when your app restores.
110 | * `void restore(@Nullable Bundle savedInstanceState)` - Restore the state of the `TabController`. This will show the last visible fragment before saving the state.
111 | * `void setChangeListener(OnFragmentChangeListener changeListener)` - Set listener to be notified on one of the `TabController`'s events.
112 |
113 | #### ShowHideHandler
114 | Implementations of this interface determine how your fragments are going to be shown/hidden. It could be by using `FragmentTransaction.show(Fragment)`/`FragmentTransaction.hide(Fragment)` or `FragmentTransaction.attach(Fragment)`/`FragmentTransaction.detach(Fragment)`.
115 |
116 | ##### Public methods:
117 | * `FragmentTransaction show(FragmentTransaction transaction, Fragment fragment)` - Show the given fragment within the given transaction the way you want.
118 | * `FragmentTransaction hide(FragmentTransaction transaction, Fragment fragment)` - Hide the given fragment within the given transaction the way you want.
119 | * `void save(Bundle saveControllerState, Fragment fragment)` - Called when TabController is saving its state. In some cases (like when you show/hide your fragment by using `FragmentTransaction.show/hide`) you may want to save the visibility of your fragment. This is where you should do that. This method is called for each fragment, returned from `FragmentManager.getFragments()`.
120 | * `void restore(@Nullable Bundle savedControllerState, FragmentTransaction transaction, Fragment fragment)` - Called when `TabController` is restoring its state. In some cases (like when you show/hide your fragment by using `FragmentTransaction.show/hide`) in order to restore the visibility of your fragments you should implement this method. Your fragment will become visible or hidden depending on what action you add to the given `FragmentTransaction`. This method is called for each fragment returned from `FragmentManagegetFragments()`.
121 | * `boolean isVisible(Fragment fragment)` - Since Fragment.isVisible() and Fragment.isHidden() work different, `TabController` is using this abstract method, relying that the implementation will work properly.
122 |
123 | #### FragmentProvider
124 | Used by `TabController`. Implementation of this interface should provide a tag and an instance of the fragment that will be shown/hidden by the controller.
125 |
126 | ##### Public methods:
127 | * `String getTag()` - Provide the fragment's tag.
128 | * `Fragment getInstance()` - Provide fragment's instance.
129 |
130 | #### OnFragmentChangeListener
131 | Pass this listener to `TabController.setChangeListener(OnFragmentChangeListener)` to be notified for one of it's events.
132 |
133 | ##### Public methods:
134 | * `void onFragmentShown(FragmentProvider provider, Fragment shownFragment)` - Called when one of your fragments has been shown.
135 | * `void onFragmentAlreadyVisible(FragmentProvider provider, Fragment visibleFragment)` - Called on attempt to show an already visible fragment.
136 | * `void onFragmentCreated(FragmentProvider provider, Fragment createdFragment)` - Called when the fragment you want to show has been created by the TabController.
137 |
138 | #### TabControllerFragment
139 | An encapsulation for the fragments that are managed through the `TabController`. All of these fragments are switched between within this fragment using child fragment manager.
140 | We encourage you to use this fragment in order to restrict the access of the `TabController` to any other fragments, that aren't related to it and vice versa.
141 |
142 | ##### Public methods:
143 | * `TabController getTabController()` - Obtain the `TabController`. Its instance is created in `Fragment.onViewCreated(View, Bundle)`.
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | # License
152 |
153 | Copyright 2017 Appolica Ltd.
154 |
155 | Licensed under the Apache License, Version 2.0 (the "License");
156 | you may not use this file except in compliance with the License.
157 | You may obtain a copy of the License at
158 |
159 | http://www.apache.org/licenses/LICENSE-2.0
160 |
161 | Unless required by applicable law or agreed to in writing, software
162 | distributed under the License is distributed on an "AS IS" BASIS,
163 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
164 | See the License for the specific language governing permissions and
165 | limitations under the License.
166 |
--------------------------------------------------------------------------------
/TabController/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/TabController/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/TabController/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/TabController/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TabController/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/TabController/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/TabController/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TabController/.idea/markdown-navigator.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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/TabController/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/TabController/.idea/misc.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 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | 1.8
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/TabController/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/TabController/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TabController/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TabController/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/TabController/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/TabController/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/TabController/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Mar 23 15:00:18 EET 2017
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-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/TabController/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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/TabController/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 |
--------------------------------------------------------------------------------
/TabController/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/TabController/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.appolica.sample"
9 | minSdkVersion 15
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | dataBinding {
24 | enabled true
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(include: ['*.jar'], dir: 'libs')
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | testCompile 'junit:junit:4.12'
34 |
35 | compile 'com.android.support:support-fragment:25.3.1'
36 |
37 | compile 'com.android.support:recyclerview-v7:25.3.1'
38 | compile 'com.android.support:cardview-v7:25.3.1'
39 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
40 |
41 | compile project(':tab-controller')
42 |
43 | compile 'com.roughike:bottom-bar:2.2.0'
44 | }
45 |
--------------------------------------------------------------------------------
/TabController/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/bogomil/Development/SDK/android-sdk-linux/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/TabController/sample/src/androidTest/java/com/appolica/sample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.appolica.sample", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/TabClickListener.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample;
2 |
3 | public interface TabClickListener {
4 | void onTab1Click();
5 |
6 | void onTab2Click();
7 |
8 | void onTab3Click();
9 |
10 | void onTab4Click();
11 | }
12 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/Tabs.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | import com.appolica.sample.tabs.FlatFragment;
6 | import com.appolica.sample.tabs.pager.ViewPagerFragment;
7 | import com.appolica.sample.tabs.stack.StackFragment;
8 | import com.appolica.tabcontroller.FragmentProvider;
9 |
10 | public enum Tabs implements FragmentProvider {
11 | TAB_1(StackFragment.class),
12 | TAB_2(ViewPagerFragment.class),
13 | TAB_3(FlatFragment.class)
14 | ;
15 |
16 | private Class extends Fragment> fragmentClass;
17 |
18 | Tabs(Class extends Fragment> fragmentClass) {
19 | this.fragmentClass = fragmentClass;
20 | }
21 |
22 | @Override
23 | public String getTag() {
24 | return name();
25 | }
26 |
27 | @Override
28 | public Fragment getInstance() {
29 | try {
30 | return fragmentClass.newInstance();
31 | } catch (InstantiationException e) {
32 | e.printStackTrace();
33 | } catch (IllegalAccessException e) {
34 | e.printStackTrace();
35 | }
36 |
37 | return null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/activity/ActivitiesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.activity;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.databinding.DataBindingUtil;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.appolica.sample.R;
13 | import com.appolica.sample.databinding.ListItemBinding;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class ActivitiesAdapter extends RecyclerView.Adapter {
19 |
20 | private List> data = new ArrayList<>();
21 |
22 | class ItemViewHolder extends RecyclerView.ViewHolder {
23 |
24 | ListItemBinding binding;
25 |
26 | public ItemViewHolder(ListItemBinding binding) {
27 | super(binding.getRoot());
28 | this.binding = binding;
29 | }
30 | }
31 |
32 | @Override
33 | public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
34 | final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
35 |
36 | ListItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.list_item, parent, false);
37 |
38 | return new ItemViewHolder(binding);
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(ItemViewHolder holder, final int position) {
43 | holder.binding.listItemTextView.setText(data.get(position).getSimpleName());
44 |
45 | holder.itemView.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | final Context context = v.getContext();
49 |
50 | context.startActivity(new Intent(context, data.get(position)));
51 | }
52 | });
53 | }
54 |
55 | @Override
56 | public int getItemCount() {
57 | return data.size();
58 | }
59 |
60 | public void addData(List> data) {
61 | this.data.addAll(data);
62 | notifyDataSetChanged();
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.activity;
2 |
3 | import android.app.Activity;
4 | import android.databinding.DataBindingUtil;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.os.Bundle;
7 | import android.support.v7.widget.LinearLayoutManager;
8 |
9 | import com.appolica.sample.R;
10 | import com.appolica.sample.databinding.ActivityMainBinding;
11 |
12 | import java.util.ArrayList;
13 |
14 | public class MainActivity extends AppCompatActivity {
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
20 |
21 | binding.recyclerViewActivities.setLayoutManager(new LinearLayoutManager(this));
22 | binding.recyclerViewActivities.setHasFixedSize(true);
23 |
24 | ActivitiesAdapter adapter = new ActivitiesAdapter();
25 | binding.recyclerViewActivities.setAdapter(adapter);
26 |
27 | final ArrayList> activityClasses = new ArrayList<>();
28 | activityClasses.add(TabControllerActivity.class);
29 | activityClasses.add(TabControllerFragmentActivity.class);
30 |
31 | adapter.addData(activityClasses);
32 |
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/activity/TabControllerActivity.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.os.PersistableBundle;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.util.Log;
9 |
10 | import com.appolica.sample.R;
11 | import com.appolica.sample.TabClickListener;
12 | import com.appolica.sample.Tabs;
13 | import com.appolica.sample.databinding.ActivityTabControllerBinding;
14 | import com.appolica.sample.tabs.BottomBarListener;
15 | import com.appolica.tabcontroller.AttachDetachHandler;
16 | import com.appolica.tabcontroller.FragmentProvider;
17 | import com.appolica.tabcontroller.ShowHideFrHandler;
18 | import com.appolica.tabcontroller.TabController;
19 | import com.appolica.tabcontroller.listener.OnFragmentChangeListener;
20 |
21 | public class TabControllerActivity
22 | extends AppCompatActivity
23 | implements OnFragmentChangeListener, BottomBarListener.BottomBarTabListener {
24 |
25 | private static final String BUNDLE_BOTTOM_BAR = TabControllerFragmentActivity.class.getName() + ":BottomBar";
26 | private static final String TAG = "TabControllerActivity";
27 |
28 | private TabController tabController;
29 | private ActivityTabControllerBinding binding;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | binding = DataBindingUtil.setContentView(this, R.layout.activity_tab_controller);
35 |
36 | tabController = new TabController(getSupportFragmentManager(), R.id.container, new AttachDetachHandler());
37 | tabController.setChangeListener(this);
38 |
39 | if (savedInstanceState != null) {
40 | binding.bottomBar.onRestoreInstanceState(savedInstanceState.getParcelable(BUNDLE_BOTTOM_BAR));
41 | tabController.restore(savedInstanceState);
42 | }
43 |
44 | binding.bottomBar.setOnTabSelectListener(new BottomBarListener(this), true);
45 | }
46 |
47 | @Override
48 | public void onFragmentShown(FragmentProvider provider, Fragment shownFragment) {
49 | Log.d(TAG, "onFragmentShown: " + provider.getTag());
50 | }
51 |
52 | @Override
53 | public void onFragmentAlreadyVisible(FragmentProvider provider, Fragment visibleFragment) {
54 | Log.d(TAG, "onFragmentAlreadyVisible: " + provider.getTag());
55 | }
56 |
57 | @Override
58 | public void onFragmentCreated(FragmentProvider provider, Fragment createdFragment) {
59 | Log.d(TAG, "onFragmentCreated: " + provider.getTag());
60 | }
61 |
62 | @Override
63 | protected void onSaveInstanceState(Bundle outState) {
64 | super.onSaveInstanceState(outState);
65 | tabController.save(outState);
66 | }
67 |
68 | @Override
69 | public void onStackSelected() {
70 | tabController.switchTo(Tabs.TAB_1);
71 | }
72 |
73 | @Override
74 | public void onViewPagerSelected() {
75 | tabController.switchTo(Tabs.TAB_2);
76 | }
77 |
78 | @Override
79 | public void onFlatSelected() {
80 | tabController.switchTo(Tabs.TAB_3);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/activity/TabControllerFragmentActivity.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.activity;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.os.Parcelable;
6 | import android.os.PersistableBundle;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.util.Log;
10 |
11 | import com.appolica.sample.R;
12 | import com.appolica.sample.Tabs;
13 | import com.appolica.sample.databinding.ActivityTabFragmentBinding;
14 | import com.appolica.sample.tabs.BottomBarListener;
15 | import com.appolica.tabcontroller.FragmentProvider;
16 | import com.appolica.tabcontroller.TabController;
17 | import com.appolica.tabcontroller.fragment.TabControllerFragment;
18 | import com.appolica.tabcontroller.listener.OnFragmentChangeListener;
19 |
20 | public class TabControllerFragmentActivity
21 | extends AppCompatActivity
22 | implements OnFragmentChangeListener,
23 | BottomBarListener.BottomBarTabListener {
24 |
25 | private static final String TAG = "TabControllerActivity";
26 | private static final String BUNDLE_BOTTOM_BAR = TabControllerFragmentActivity.class.getName() + ":BottomBar";
27 |
28 | private TabController tabController;
29 | private ActivityTabFragmentBinding binding;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | binding = DataBindingUtil.setContentView(this, R.layout.activity_fragment_tab_controller);
35 |
36 | final TabControllerFragment tabControllerFragment =
37 | (TabControllerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
38 |
39 | tabController = tabControllerFragment.getTabController();
40 | tabController.setChangeListener(this);
41 |
42 | if (savedInstanceState != null) {
43 | binding.bottomBar.onRestoreInstanceState(savedInstanceState.getParcelable(BUNDLE_BOTTOM_BAR));
44 | }
45 |
46 | binding.bottomBar.setOnTabSelectListener(new BottomBarListener(this), true);
47 | }
48 |
49 | @Override
50 | public void onFragmentShown(FragmentProvider fragmentType, Fragment shownFragment) {
51 | Log.d(TAG, "onFragmentShown: " + fragmentType.getTag());
52 | }
53 |
54 | @Override
55 | public void onFragmentAlreadyVisible(FragmentProvider fragmentType, Fragment visibleFragment) {
56 | Log.d(TAG, "onFragmentAlreadyVisible: " + fragmentType.getTag());
57 | }
58 |
59 | @Override
60 | public void onFragmentCreated(FragmentProvider fragmentType, Fragment addedFragment) {
61 | Log.d(TAG, "onFragmentCreated: " + fragmentType.getTag());
62 | }
63 |
64 | @Override
65 | public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
66 | super.onSaveInstanceState(outState, outPersistentState);
67 | final Parcelable bottomBarParcelable = binding.bottomBar.onSaveInstanceState();
68 |
69 | outState.putParcelable(BUNDLE_BOTTOM_BAR, bottomBarParcelable);
70 | }
71 |
72 | @Override
73 | public void onStackSelected() {
74 | tabController.switchTo(Tabs.TAB_1);
75 | }
76 |
77 | @Override
78 | public void onViewPagerSelected() {
79 | tabController.switchTo(Tabs.TAB_2);
80 | }
81 |
82 | @Override
83 | public void onFlatSelected() {
84 | tabController.switchTo(Tabs.TAB_3);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/BottomBarListener.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs;
2 |
3 | import android.support.annotation.IdRes;
4 |
5 | import com.appolica.sample.R;
6 | import com.roughike.bottombar.OnTabSelectListener;
7 |
8 | public class BottomBarListener implements OnTabSelectListener {
9 |
10 | private BottomBarTabListener listener;
11 |
12 | public BottomBarListener(BottomBarTabListener listener) {
13 | this.listener = listener;
14 | }
15 |
16 | @Override
17 | public void onTabSelected(@IdRes int tabId) {
18 | switch (tabId) {
19 | case R.id.tab_stack:
20 | listener.onStackSelected();
21 | break;
22 | case R.id.tab_pager:
23 | listener.onViewPagerSelected();
24 | break;
25 | case R.id.tab_flat:
26 | listener.onFlatSelected();
27 | break;
28 | }
29 | }
30 |
31 | public interface BottomBarTabListener {
32 | void onStackSelected();
33 | void onViewPagerSelected();
34 | void onFlatSelected();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/FlatFragment.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.appolica.sample.R;
12 | import com.appolica.sample.databinding.FragmentTabFlatBinding;
13 |
14 |
15 | public class FlatFragment extends Fragment {
16 |
17 | private FragmentTabFlatBinding binding;
18 |
19 | @Nullable
20 | @Override
21 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_tab_flat, container, false);
23 | return binding.getRoot();
24 | }
25 |
26 | @Override
27 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
28 | super.onViewCreated(view, savedInstanceState);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/NestedFragment.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.appolica.sample.R;
12 | import com.appolica.sample.databinding.FragmentStackNestedBinding;
13 |
14 |
15 | public class NestedFragment extends Fragment {
16 |
17 | public static final String KEY_FRAGMENT_INDEX = NestedFragment.class.getName() + ":KEY_FRAGMENT_INDEX";
18 | public static final String TAG = NestedFragment.class.getSimpleName();
19 | private FragmentStackNestedBinding binding;
20 |
21 | public static NestedFragment getInstance(int index) {
22 | final Bundle args = new Bundle();
23 | final NestedFragment fragment = new NestedFragment();
24 |
25 | args.putInt(KEY_FRAGMENT_INDEX, index);
26 | fragment.setArguments(args);
27 |
28 | return fragment;
29 | }
30 |
31 | @Nullable
32 | @Override
33 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
34 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_stack_nested, container, false);
35 | return binding.getRoot();
36 | }
37 |
38 | @Override
39 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
40 | super.onViewCreated(view, savedInstanceState);
41 |
42 | final int fragmentIndex = getArguments().getInt(KEY_FRAGMENT_INDEX);
43 | binding.setText(getString(R.string.stack_fragment_index, fragmentIndex));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/pager/PagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs.pager;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | import com.appolica.sample.Tabs;
8 | import com.appolica.sample.tabs.NestedFragment;
9 |
10 |
11 | public class PagerAdapter extends FragmentPagerAdapter {
12 | public PagerAdapter(FragmentManager fm) {
13 | super(fm);
14 | }
15 |
16 | @Override
17 | public CharSequence getPageTitle(int position) {
18 | return Tabs.values()[position].name();
19 | }
20 |
21 | @Override
22 | public Fragment getItem(int position) {
23 | final NestedFragment fragment = NestedFragment.getInstance(position);
24 |
25 | return fragment;
26 | }
27 |
28 | @Override
29 | public int getCount() {
30 | return PagerTabs.values().length;
31 | }
32 |
33 | public static enum PagerTabs {
34 | TAB_1(1),
35 | TAB_2(2);
36 |
37 | private int index;
38 |
39 | PagerTabs(int index) {
40 | this.index = index;
41 | }
42 |
43 | public int getIndex() {
44 | return index;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/pager/ViewPagerFragment.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs.pager;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.appolica.sample.R;
12 | import com.appolica.sample.databinding.FragmentTabViewPagerBinding;
13 |
14 |
15 | public class ViewPagerFragment extends Fragment {
16 |
17 | private FragmentTabViewPagerBinding binding;
18 |
19 | @Nullable
20 | @Override
21 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22 |
23 | binding = DataBindingUtil.inflate(inflater, R.layout.fragment_tab_view_pager, container, false);
24 |
25 | return binding.getRoot();
26 | }
27 |
28 | @Override
29 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
30 | super.onViewCreated(view, savedInstanceState);
31 |
32 | final PagerAdapter pagerAdapter = new PagerAdapter(getChildFragmentManager());
33 |
34 | binding.tabLayout.setupWithViewPager(binding.viewPager);
35 |
36 | binding.viewPager.setAdapter(pagerAdapter);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/stack/StackFragment.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs.stack;
2 |
3 | import android.databinding.DataBindingUtil;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.appolica.sample.R;
13 | import com.appolica.sample.databinding.StackFragmentsBinding;
14 | import com.appolica.sample.tabs.NestedFragment;
15 |
16 | public class StackFragment extends Fragment implements StackFragmentClickListener {
17 |
18 | private StackFragmentsBinding binding;
19 |
20 | @Nullable
21 | @Override
22 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
23 |
24 | binding =
25 | DataBindingUtil.inflate(inflater, R.layout.fragment_tab_stack, container, false);
26 |
27 | return binding.getRoot();
28 | }
29 |
30 | @Override
31 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
32 | super.onViewCreated(view, savedInstanceState);
33 |
34 | binding.setClickListener(this);
35 | }
36 |
37 | @Override
38 | public void onPopClick() {
39 | popFragment();
40 | }
41 |
42 | @Override
43 | public void onPushClick() {
44 | final FragmentManager childFragmentManager = getChildFragmentManager();
45 | final int stackCount = childFragmentManager.getBackStackEntryCount();
46 | final NestedFragment fragment = NestedFragment.getInstance(stackCount);
47 |
48 | childFragmentManager.beginTransaction()
49 | .replace(R.id.container, fragment)
50 | .addToBackStack(String.format("%s:%d", NestedFragment.TAG, stackCount))
51 | .commit();
52 |
53 | childFragmentManager.executePendingTransactions();
54 | }
55 |
56 | private void popFragment() {
57 | getChildFragmentManager().popBackStack();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/java/com/appolica/sample/tabs/stack/StackFragmentClickListener.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample.tabs.stack;
2 |
3 | public interface StackFragmentClickListener {
4 | void onPopClick();
5 | void onPushClick();
6 | }
7 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-hdpi/ic_tab_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-hdpi/ic_tab_flat.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-hdpi/ic_tab_pager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-hdpi/ic_tab_pager.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-hdpi/ic_tab_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-hdpi/ic_tab_stack.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-mdpi/ic_tab_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-mdpi/ic_tab_flat.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-mdpi/ic_tab_pager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-mdpi/ic_tab_pager.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-mdpi/ic_tab_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-mdpi/ic_tab_stack.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_flat.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_pager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_pager.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xhdpi/ic_tab_stack.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_flat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_flat.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_pager.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_pager.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/drawable-xxhdpi/ic_tab_stack.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/activity_fragment_tab_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
27 |
28 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/activity_tab_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
25 |
26 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/fragment_stack_nested.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
20 |
21 |
35 |
36 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/fragment_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
17 |
18 |
34 |
35 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/fragment_tab_flat.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
25 |
26 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/fragment_tab_stack.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
20 |
21 |
31 |
32 |
33 |
34 |
44 |
45 |
55 |
56 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/fragment_tab_view_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
24 |
25 |
26 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
17 |
18 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/TabController/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #C5CAE9
6 | #00BCD4
7 | #212121
8 | #757575
9 | #FFFFFF
10 | #BDBDBD
11 | #f5f5f5
12 | #bdbdbd
13 | #1976d2
14 | #3F51B5
15 | #1976d2
16 |
17 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Sample
3 | Tab Controller
4 | Tab Controller Fragment
5 | Push
6 | Pop
7 | Fragment: %d
8 | Flat Fragment
9 |
10 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/TabController/sample/src/main/res/xml/controller_tabs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/TabController/sample/src/test/java/com/appolica/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.appolica.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/TabController/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':tab-controller', ':sample'
2 |
--------------------------------------------------------------------------------
/TabController/tab-controller/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/TabController/tab-controller/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release' // must be applied after your artifact generating plugin (eg. java / com.android.library)
3 |
4 | buildscript {
5 | repositories {
6 | jcenter()
7 | }
8 |
9 | dependencies {
10 | classpath "me.tatarka:gradle-retrolambda:3.4.0"
11 | classpath 'com.novoda:bintray-release:0.4.0'
12 | }
13 |
14 | }
15 |
16 | apply plugin: 'me.tatarka.retrolambda'
17 |
18 |
19 | android {
20 | lintOptions {
21 | abortOnError false
22 | }
23 | compileOptions {
24 | sourceCompatibility JavaVersion.VERSION_1_8
25 | targetCompatibility JavaVersion.VERSION_1_8
26 | }
27 |
28 | compileSdkVersion 25
29 | buildToolsVersion "25.0.2"
30 |
31 | defaultConfig {
32 | minSdkVersion 14
33 | targetSdkVersion 25
34 | versionCode 4
35 | versionName "1.0.3"
36 |
37 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
38 |
39 | }
40 | buildTypes {
41 | release {
42 | minifyEnabled false
43 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
44 | }
45 | }
46 | }
47 |
48 | dependencies {
49 | compile fileTree(dir: 'libs', include: ['*.jar'])
50 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
51 | exclude group: 'com.android.support', module: 'support-annotations'
52 | })
53 |
54 | compile 'com.android.support:support-fragment:25.3.1'
55 | testCompile 'junit:junit:4.12'
56 | }
57 |
58 | publish {
59 | userOrg = 'appolica-ltd'
60 | groupId = 'com.appolica'
61 | artifactId = 'tab-controller'
62 | publishVersion = '1.0.3'
63 | desc = 'A helper library for managing fragments in a certain way.'
64 | website = 'https://github.com/Appolica/TabControllerAndroid'
65 | licences = ['Apache-2.0']
66 | uploadName = 'TabControllerAndroid'
67 | }
--------------------------------------------------------------------------------
/TabController/tab-controller/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/dido/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/androidTest/java/com/appolica/tabcontroller/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.appolica.tabcontroller.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/AttachDetachHandler.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentTransaction;
7 | import android.util.Log;
8 |
9 | /**
10 | * An implementation of {@link ShowHideHandler} that uses {@link FragmentTransaction#attach(Fragment)}
11 | * and {@link FragmentTransaction#detach(Fragment)} to show/hide fragments.
12 | */
13 | public class AttachDetachHandler implements ShowHideHandler {
14 | private static final String TAG = "AttachDetachHandler";
15 |
16 | @Override
17 | public FragmentTransaction show(FragmentTransaction transaction, Fragment fragment) {
18 | Log.d(TAG, "attach: " + fragment);
19 | return transaction.attach(fragment);
20 | }
21 |
22 | @Override
23 | public FragmentTransaction hide(FragmentTransaction transaction, Fragment fragment) {
24 | Log.d(TAG, "detach: " + fragment);
25 | return transaction.detach(fragment);
26 | }
27 |
28 | @Override
29 | public void save(@Nullable Bundle saveControllerState, Fragment fragment) {
30 | // should be empty
31 | }
32 |
33 | @Override
34 | public void restore(@Nullable Bundle savedControllerState, FragmentTransaction transaction, Fragment fragment) {
35 | // should be empty
36 | }
37 |
38 | @Override
39 | public boolean isVisible(Fragment fragment) {
40 | return !fragment.isDetached();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/FragmentProvider.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | /**
6 | * Used by {@link TabController}. Implementation of this interface should provide a tag and
7 | * an instance of the fragment that will be shown/hidden by the controller.
8 | */
9 | public interface FragmentProvider {
10 |
11 | /**
12 | * Provide the fragment's tag.
13 | * @return The fragment's tag.
14 | */
15 | public String getTag();
16 |
17 | /**
18 | * Provide fragment's instance.
19 | * @return The fragment's instance.
20 | */
21 | public Fragment getInstance();
22 | }
23 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/ShowHideFrHandler.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentTransaction;
7 |
8 | /**
9 | * An implementation of {@link ShowHideHandler} that uses {@link FragmentTransaction#show(Fragment)}
10 | * and {@link FragmentTransaction#hide(Fragment)} to show/hide fragments.
11 | */
12 | public class ShowHideFrHandler implements ShowHideHandler {
13 | @Override
14 | public FragmentTransaction show(FragmentTransaction transaction, Fragment fragment) {
15 |
16 | return transaction.show(fragment);
17 | }
18 |
19 | @Override
20 | public FragmentTransaction hide(FragmentTransaction transaction, Fragment fragment) {
21 | return transaction.hide(fragment);
22 | }
23 |
24 | @Override
25 | public void save(Bundle saveControllerState, Fragment fragment) {
26 | boolean visible = isVisible(fragment);
27 | saveControllerState.putBoolean(fragment.getTag(), visible);
28 | }
29 |
30 | @Override
31 | public void restore(@Nullable Bundle savedControllerState, FragmentTransaction transaction, Fragment fragment) {
32 | if (savedControllerState != null) {
33 | boolean visible = savedControllerState.getBoolean(fragment.getTag());
34 | if (visible) {
35 | show(transaction, fragment);
36 | } else {
37 | hide(transaction, fragment);
38 | }
39 | }
40 | }
41 |
42 | @Override
43 | public boolean isVisible(Fragment fragment) {
44 | return !fragment.isHidden();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/ShowHideHandler.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentManager;
7 | import android.support.v4.app.FragmentTransaction;
8 |
9 | /**
10 | * Implementations of this interface determine how your fragments are going to be shown/hidden.
11 | * It could be by using {@link FragmentTransaction#show(Fragment)}/{@link FragmentTransaction#hide(Fragment)}
12 | * or {@link FragmentTransaction#attach(Fragment)}/{@link FragmentTransaction#detach(Fragment)}
13 | */
14 | public interface ShowHideHandler {
15 | /**
16 | * Show the given fragment within the given transaction the way you want.
17 | *
18 | * @param transaction The transaction that will be committed in order to show your fragment.
19 | * @param fragment The fragment you want to show.
20 | * @return The transaction, that when committed should show your fragment.
21 | */
22 | public FragmentTransaction show(FragmentTransaction transaction, Fragment fragment);
23 |
24 | /**
25 | * Hide the given fragment within the given transaction the way you want.
26 | *
27 | * @param transaction The transaction that will be committed in order to hide your fragment.
28 | * @param fragment The fragment you want to hide.
29 | * @return The transaction, that when committed should hide your fragment.
30 | */
31 | public FragmentTransaction hide(FragmentTransaction transaction, Fragment fragment);
32 |
33 | /**
34 | * Called when {@link TabController} is saving its state. In some cases (like when you
35 | * show/hide your fragment by using FragmentTransaction::show/hide) you may want to save
36 | * the visibility of your fragment. This is where you should do that.
37 | *
38 | * This method is called for each fragment, returned from {@link FragmentManager#getFragments()}.
39 | *
40 | * @param saveControllerState The output bundle for saving your visibility.
41 | * @param fragment The fragment which visibility you are saving.
42 | */
43 | public void save(Bundle saveControllerState, Fragment fragment);
44 |
45 | /**
46 | * Called when {@link TabController} is restoring its state. In some cases (like when you
47 | * show/hide your fragment by using FragmentTransaction::show/hide) in order to restore the
48 | * visibility of your fragments you should implement this method. Your fragment will become
49 | * visible or hidden depending on what action you add to the given {@link FragmentTransaction}.
50 | *
51 | * This method is called for each fragment returned from {@link FragmentManager#getFragments()}.
52 | *
53 | * @param savedControllerState The bundle you restore your visibility state from.
54 | * @param transaction The transaction your fragment will be shown/hidden again.
55 | * @param fragment The fragment which's visibility you are restoring.
56 | */
57 | public void restore(@Nullable Bundle savedControllerState, FragmentTransaction transaction, Fragment fragment);
58 |
59 | /**
60 | * Since {@link Fragment#isVisible()} and {@link Fragment#isHidden()} work different,
61 | * {@link TabController} is using this abstract method, relying that the implementation will
62 | * work properly.
63 | *
64 | * @param fragment The fragment which's visibility {@link TabController} is querying.
65 | * @return true if your fragment is visible, false otherwise.
66 | */
67 | public boolean isVisible(Fragment fragment);
68 | }
69 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/TabController.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentTransaction;
9 |
10 | import com.appolica.tabcontroller.listener.OnFragmentChangeListener;
11 |
12 | import java.util.ArrayList;
13 | import java.util.Iterator;
14 | import java.util.List;
15 |
16 | /**
17 | * The core of the library. This class controls the switching between fragments.
18 | */
19 | public class TabController {
20 |
21 | private static final String TAG = "TabController";
22 |
23 | private static final String BUNDLE_KEY = "bundle-key-tab-controller";
24 |
25 | private final FragmentManager fragmentManager;
26 | private final int containerId;
27 |
28 | private ShowHideHandler showHideHandler;
29 |
30 | private OnFragmentChangeListener changeListener;
31 |
32 | /**
33 | * Create a new instance of {@link TabController} with the default {@link ShowHideHandler}.
34 | *
35 | * @param fragmentManager The support fragment manager, used to switch between fragments.
36 | * @param containerId The view id of the container for your fragments.
37 | *
38 | * @see ShowHideHandler
39 | */
40 | public TabController(FragmentManager fragmentManager, int containerId) {
41 | this(fragmentManager, containerId, new ShowHideFrHandler());
42 | }
43 |
44 | /**
45 | * Create a new instance of {@link TabController}.
46 | *
47 | * @param fragmentManager The support fragment manager, used to switch between fragments.
48 | * @param containerId The view id of the container for your fragments.
49 | * @param showHideHandler The {@link ShowHideHandler} which determines how your fragments
50 | * are going to be shown/hidden.
51 | *
52 | * @see ShowHideHandler
53 | */
54 | public TabController(FragmentManager fragmentManager, int containerId, ShowHideHandler showHideHandler) {
55 | this.fragmentManager = fragmentManager;
56 | FragmentManager.enableDebugLogging(false);
57 | this.containerId = containerId;
58 | this.showHideHandler = showHideHandler;
59 | }
60 |
61 | /**
62 | * Show the given fragment in the container, provided to the constructor. If
63 | * FragmentManager::findFragmentByTag returns null for the tag, given by the provider,
64 | * your fragment's instance will be obtained by calling FragmentProvider::getInstance.
65 | * Otherwise it will be reused.
66 | *
67 | * If there is already a visible fragment, it will be hidden. How fragments are shown/hidden
68 | * depends on {@link ShowHideHandler}.
69 | *
70 | * @param provider The {@link FragmentProvider} for the fragment you want to show.
71 | *
72 | * @see FragmentProvider
73 | */
74 | public void switchTo(FragmentProvider provider) {
75 |
76 | List notifiers = new ArrayList<>();
77 |
78 | inTransaction(transaction -> {
79 |
80 | final Fragment fragmentToShow = fragmentManager.findFragmentByTag(provider.getTag());
81 |
82 | if (fragmentToShow != null) {
83 | if (!showHideHandler.isVisible(fragmentToShow)) {
84 | //Fragment is active but not visible
85 | hideVisibleFragment(transaction);
86 | showFragment(fragmentToShow, transaction);
87 |
88 | notifiers.add(listener -> listener.onFragmentShown(provider, fragmentToShow));
89 | } else {
90 | //Fragment is already visible on the screen
91 | notifiers.add(listener -> listener.onFragmentAlreadyVisible(provider, fragmentToShow));
92 | }
93 | } else {
94 | //Fragment does not exist
95 | hideVisibleFragment(transaction);
96 |
97 | Fragment addedFragment = addToFragmentManager(provider, transaction);
98 |
99 | notifiers.add(listener -> listener.onFragmentCreated(provider, addedFragment));
100 | notifiers.add(listener -> listener.onFragmentShown(provider, addedFragment));
101 | }
102 |
103 | return notifiers;
104 | });
105 | }
106 |
107 | private void hide(FragmentProvider currentFragment) {
108 | final Fragment visibleFragment = fragmentManager.findFragmentByTag(currentFragment.getTag());
109 |
110 | if (visibleFragment != null) {
111 |
112 | inTransaction(transaction -> {
113 | showHideHandler.hide(transaction, visibleFragment);
114 | return new ArrayList<>();
115 | });
116 | }
117 | }
118 |
119 | private void showFragment(Fragment fragment, FragmentTransaction transaction) {
120 | showHideHandler.show(transaction, fragment);
121 | }
122 |
123 | private Fragment addToFragmentManager(FragmentProvider fragmentType, FragmentTransaction transaction) {
124 | Fragment fragment = fragmentType.getInstance();
125 | transaction.add(containerId, fragment, fragmentType.getTag());
126 |
127 | return fragment;
128 | }
129 |
130 | private void hideVisibleFragment(FragmentTransaction fragmentTransaction) {
131 | final Fragment visibleFragment = getVisibleFragment();
132 |
133 | if (visibleFragment != null) {
134 | showHideHandler.hide(fragmentTransaction, visibleFragment);
135 | }
136 | }
137 |
138 | /**
139 | * Iterates through the fragments, returned by FragmentManager::getFragments.
140 | *
141 | * @return The first visible fragment found in the list or null.
142 | */
143 | @Nullable
144 | public Fragment getVisibleFragment() {
145 | final List fragments = getFMFragments();
146 | for (Fragment fragment : fragments) {
147 | if (showHideHandler.isVisible(fragment)) {
148 | return fragment;
149 | }
150 | }
151 |
152 | return null;
153 | }
154 |
155 | /**
156 | * Find a fragment by it's {@link FragmentProvider}. Same as calling
157 | * fragmentManager.findFragmentByTag(fragmentProvider.getTag());
158 | *
159 | * @param fragmentProvider The fragment provider of the fragment you want to obtain.
160 | * @return The fragment which the given {@link FragmentProvider} is for.
161 | */
162 | @Nullable
163 | public Fragment getFragment(@NonNull FragmentProvider fragmentProvider) {
164 | return fragmentManager.findFragmentByTag(fragmentProvider.getTag());
165 | }
166 |
167 | /**
168 | * Restore the state of the {@link TabController}. This will show the last visible fragment
169 | * before saving the state.
170 | *
171 | * Make sure you call {@link #save(Bundle)} when saving your instance
172 | * state.
173 | *
174 | * @param savedInstanceState The saved instance state Bundle where the TabController state
175 | * wil be obtained from.
176 | */
177 | public void restore(@Nullable Bundle savedInstanceState) {
178 | if (savedInstanceState != null) {
179 | final Bundle controllerState = savedInstanceState.getBundle(BUNDLE_KEY);
180 |
181 | if (controllerState == null) {
182 | throw new IllegalStateException("TabController's bundle not found in savedInstanceState. Did you call TabController::save in onSaveInstanceState(outState)?");
183 | }
184 |
185 | final List fragments = getFMFragments();
186 |
187 | inTransaction(transaction -> {
188 |
189 | for (Fragment fragment : fragments) {
190 | showHideHandler.restore(controllerState, transaction, fragment);
191 | }
192 |
193 | return new ArrayList<>();
194 | });
195 | }
196 | }
197 |
198 | /**
199 | * Save the state of the {@link TabController} in order to be able to restore your last visible
200 | * fragment when your app restores.
201 | *
202 | * Make sure you call {@link #restore(Bundle)} when restoring your instance state.
203 | * @param savedInstanceState The output Bundle where the state will be saved to.
204 | */
205 | public void save(Bundle savedInstanceState) {
206 |
207 | final Bundle controllerState = new Bundle();
208 |
209 | final List fragments = getFMFragments();
210 |
211 | for (Fragment fragment : fragments) {
212 |
213 | showHideHandler.save(controllerState, fragment);
214 | }
215 |
216 | savedInstanceState.putBundle(BUNDLE_KEY, controllerState);
217 | }
218 |
219 | private void inTransaction(@NonNull TransactionBody body) {
220 | inTransaction(body, FragmentTransaction::commitNow);
221 | }
222 |
223 | private void inAsyncTransaction(@NonNull TransactionBody body) {
224 | inTransaction(body, FragmentTransaction::commit);
225 | }
226 |
227 | private void inTransaction(@NonNull TransactionBody body, @NonNull TransactionCommitter committer) {
228 | FragmentTransaction transaction = fragmentManager.beginTransaction();
229 |
230 | transaction.setAllowOptimization(false);
231 |
232 | List notifiers = body.runInTransaction(transaction);
233 |
234 | committer.commitTransaction(transaction);
235 |
236 | if (changeListener != null)
237 | for (Notifier notifier : notifiers) {
238 | notifier.notifyListener(changeListener);
239 | }
240 | }
241 |
242 | /**
243 | * Set listener to be notified on one of the {@link TabController}'s events.
244 | *
245 | * @param changeListener Your implementation of the listener.
246 | *
247 | * @see OnFragmentChangeListener
248 | */
249 | public void setChangeListener(OnFragmentChangeListener changeListener) {
250 | this.changeListener = changeListener;
251 | }
252 |
253 | @NonNull
254 | private List getFMFragments() {
255 | final List fmList = fragmentManager.getFragments();
256 |
257 | final List resultList = new ArrayList<>();
258 |
259 | if (fmList != null) {
260 |
261 | resultList.addAll(fmList);
262 |
263 | final Iterator iterator = resultList.iterator();
264 | while (iterator.hasNext()) {
265 |
266 | if (iterator.next() == null) {
267 | iterator.remove();
268 | }
269 | }
270 | }
271 |
272 | return resultList;
273 | }
274 |
275 | private static interface TransactionBody {
276 | @NonNull
277 | public List runInTransaction(FragmentTransaction fragmentTransaction);
278 | }
279 |
280 | private static interface TransactionCommitter {
281 |
282 | public void commitTransaction(FragmentTransaction fragmentTransaction);
283 | }
284 |
285 | private static interface Notifier {
286 | public void notifyListener(@NonNull OnFragmentChangeListener onFragmentChangeListener);
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/fragment/TabControllerFragment.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.appolica.tabcontroller.R;
11 | import com.appolica.tabcontroller.TabController;
12 |
13 | /**
14 | * An encapsulation for the fragments that are managed through the {@link TabController}.
15 | * All of these fragments are switched between within this fragment using child fragment manager.
16 | *
17 | * We encourage you to use this fragment in order to restrict the access of the
18 | * {@link TabController} to any other fragments, that aren't related to it and vice versa.
19 | */
20 | public class TabControllerFragment extends Fragment {
21 |
22 | private TabController tabController;
23 |
24 | @Nullable
25 | @Override
26 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
27 |
28 | final View view = inflater.inflate(R.layout.fragment_tab_controller, container, false);
29 |
30 | return view;
31 | }
32 |
33 | @Override
34 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
35 | super.onViewCreated(view, savedInstanceState);
36 |
37 | tabController = new TabController(getChildFragmentManager(), R.id.container);
38 |
39 | if (savedInstanceState != null) {
40 | tabController.restore(savedInstanceState);
41 | }
42 | }
43 |
44 | @Override
45 | public void onSaveInstanceState(Bundle outState) {
46 | super.onSaveInstanceState(outState);
47 | tabController.save(outState);
48 | }
49 |
50 | /**
51 | * Obtain the {@link TabController}. Its instance is created in
52 | * {@link Fragment#onViewCreated(View, Bundle)}.
53 | *
54 | * @return The {@link TabController}'s instance or null if hasn't been instantiated yet.
55 | */
56 | public TabController getTabController() {
57 | return tabController;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/listener/OnFragmentChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller.listener;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | import com.appolica.tabcontroller.FragmentProvider;
6 |
7 | /**
8 | * Pass this listener to
9 | * {@link com.appolica.tabcontroller.TabController#setChangeListener(OnFragmentChangeListener)}
10 | * to be notified for one of it's events.
11 | */
12 | public interface OnFragmentChangeListener {
13 |
14 | /**
15 | * Called when one of your fragments has been shown.
16 | *
17 | * @param provider Your shown fragment's provider.
18 | * @param shownFragment The fragment that has been shown.
19 | */
20 | void onFragmentShown(FragmentProvider provider, Fragment shownFragment);
21 |
22 | /**
23 | * Called on attempt to show an already visible fragment.
24 | *
25 | * @param provider Your visible fragment's provider.
26 | * @param visibleFragment The fragment that is already visible.
27 | */
28 | void onFragmentAlreadyVisible(FragmentProvider provider, Fragment visibleFragment);
29 |
30 | /**
31 | * Called when the fragment you want to show has been created by the
32 | * {@link com.appolica.tabcontroller.TabController}.
33 | *
34 | * @param provider Your created fragment's provider.
35 | * @param createdFragment Your created fragment.
36 | */
37 | void onFragmentCreated(FragmentProvider provider, Fragment createdFragment);
38 | }
39 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/java/com/appolica/tabcontroller/listener/SimpleFragmentChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller.listener;
2 |
3 | import android.support.v4.app.Fragment;
4 |
5 | import com.appolica.tabcontroller.FragmentProvider;
6 |
7 | public class SimpleFragmentChangeListener implements OnFragmentChangeListener {
8 | @Override
9 | public void onFragmentShown(FragmentProvider provider, Fragment shownFragment) {
10 |
11 | }
12 |
13 | @Override
14 | public void onFragmentAlreadyVisible(FragmentProvider provider, Fragment visibleFragment) {
15 |
16 | }
17 |
18 | @Override
19 | public void onFragmentCreated(FragmentProvider provider, Fragment createdFragment) {
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/res/layout/fragment_tab_controller.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TabController
3 |
4 |
--------------------------------------------------------------------------------
/TabController/tab-controller/src/test/java/com/appolica/tabcontroller/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.appolica.tabcontroller;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/doc_resources/gif/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Appolica/TabControllerAndroid/8bea029dd5a6c4e35caabd96a038b7d7bec33572/doc_resources/gif/sample.gif
--------------------------------------------------------------------------------