├── sample
├── logo.png
├── logo.psd
├── screens.png
├── icon_web.png
├── res
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-mdpi
│ │ └── icon.png
│ ├── drawable-xhdpi
│ │ └── icon.png
│ └── layout
│ │ └── main.xml
├── libs
│ └── android-support-v4.jar
├── project.properties
├── src
│ └── com
│ │ └── directionalviewpager
│ │ └── sample
│ │ ├── TestFragmentAdapter.java
│ │ ├── SampleActivity.java
│ │ └── TestFragment.java
├── AndroidManifest.xml
└── pom.xml
├── library
├── libs
│ └── android-support-v4.jar
├── AndroidManifest.xml
├── project.properties
├── src
│ ├── android
│ │ └── support
│ │ │ └── v4
│ │ │ └── view
│ │ │ └── VerticalViewPagerCompat.java
│ └── com
│ │ └── directionalviewpager
│ │ └── DirectionalViewPager.java
├── pom.xml
└── checkstyle.xml
├── .gitignore
├── CHANGELOG.md
├── README.md
├── pom.xml
└── LICENSE.txt
/sample/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/logo.png
--------------------------------------------------------------------------------
/sample/logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/logo.psd
--------------------------------------------------------------------------------
/sample/screens.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/screens.png
--------------------------------------------------------------------------------
/sample/icon_web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/icon_web.png
--------------------------------------------------------------------------------
/sample/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/sample/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/library/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/library/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/sample/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/sample/res/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JakeWharton/Android-DirectionalViewPager/HEAD/sample/res/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 |
5 | #Eclipse
6 | .project
7 | .classpath
8 | .settings
9 |
10 | #IntelliJ IDEA
11 | .idea
12 | *.iml
13 |
14 | #Maven
15 | target
16 | release.properties
17 | pom.xml.*
18 |
--------------------------------------------------------------------------------
/library/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/library/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | android.library=true
11 | # Project target.
12 | target=android-4
13 |
--------------------------------------------------------------------------------
/library/src/android/support/v4/view/VerticalViewPagerCompat.java:
--------------------------------------------------------------------------------
1 | package android.support.v4.view;
2 |
3 | public final class VerticalViewPagerCompat {
4 | private VerticalViewPagerCompat() {}
5 |
6 | public interface DataSetObserver extends PagerAdapter.DataSetObserver {}
7 |
8 | public static void setDataSetObserver(PagerAdapter adapter, DataSetObserver observer) {
9 | adapter.setDataSetObserver(observer);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/sample/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-4
12 | android.library.reference.1=../library
13 |
--------------------------------------------------------------------------------
/sample/src/com/directionalviewpager/sample/TestFragmentAdapter.java:
--------------------------------------------------------------------------------
1 | package com.directionalviewpager.sample;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | class TestFragmentAdapter extends FragmentPagerAdapter {
8 | protected static final String[] CONTENT = new String[] { "This", "Is Is", "A A A", "Test", };
9 |
10 | public TestFragmentAdapter(FragmentManager fm) {
11 | super(fm);
12 | }
13 |
14 | @Override
15 | public Fragment getItem(int position) {
16 | return TestFragment.newInstance(CONTENT[position]);
17 | }
18 |
19 | @Override
20 | public int getCount() {
21 | return CONTENT.length;
22 | }
23 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | Version 1.2.1 *(2011-10-20)*
5 | ----------------------------
6 |
7 | Maven 3 is now required when building from the command line.
8 |
9 | * Update to support ADT 14.
10 |
11 |
12 | Version 1.2.0 *(2011-10-04)*
13 | ----------------------------
14 |
15 | * Move to `com.directionalviewpager` package.
16 | * Change maven group and artifact to `com.directionalviewpager:library`.
17 |
18 |
19 | Version 1.1.0 *(2011-09-28)*
20 | ----------------------------
21 |
22 | * Extend from `ViewPager` so it can be used with other APIs which require an
23 | instance of `ViewPager`.
24 | * Move to `com.jakewharton.android.view` package.
25 |
26 |
27 | Version 1.0.0 *(2011-08-24)*
28 | ----------------------------
29 |
30 | Initial release.
31 |
--------------------------------------------------------------------------------
/sample/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/sample/src/com/directionalviewpager/sample/SampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.directionalviewpager.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.FragmentActivity;
5 | import android.view.View;
6 | import android.widget.Button;
7 | import com.directionalviewpager.DirectionalViewPager;
8 |
9 | public class SampleActivity extends FragmentActivity {
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | setContentView(R.layout.main);
14 |
15 | //Set up the pager
16 | final DirectionalViewPager pager = (DirectionalViewPager)findViewById(R.id.pager);
17 | pager.setAdapter(new TestFragmentAdapter(getSupportFragmentManager()));
18 |
19 | //Bind to control buttons
20 | ((Button)findViewById(R.id.horizontal)).setOnClickListener(new View.OnClickListener() {
21 | @Override
22 | public void onClick(View v) {
23 | pager.setOrientation(DirectionalViewPager.HORIZONTAL);
24 | }
25 | });
26 | ((Button)findViewById(R.id.vertical)).setOnClickListener(new View.OnClickListener() {
27 | @Override
28 | public void onClick(View v) {
29 | pager.setOrientation(DirectionalViewPager.VERTICAL);
30 | }
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/library/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | com.directionalviewpager
7 | library
8 | Android-DirectionalViewPager
9 | jar
10 |
11 |
12 | com.directionalviewpager
13 | parent
14 | 1.2.1
15 | ../pom.xml
16 |
17 |
18 |
19 |
20 | android
21 | android
22 | provided
23 |
24 |
25 |
26 | android.support
27 | compatibility-v4
28 | provided
29 |
30 |
31 |
32 |
33 | src
34 |
35 |
36 |
37 | com.jayway.maven.plugins.android.generation2
38 | maven-android-plugin
39 | true
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-javadoc-plugin
45 |
46 | true
47 |
48 |
49 |
50 |
51 | org.apache.maven.plugins
52 | maven-checkstyle-plugin
53 |
54 | ${project.basedir}/checkstyle.xml
55 |
56 |
57 |
58 | verify
59 |
60 | checkstyle
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/sample/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
22 |
23 |
29 |
30 |
35 |
36 |
43 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/sample/src/com/directionalviewpager/sample/TestFragment.java:
--------------------------------------------------------------------------------
1 | package com.directionalviewpager.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.Gravity;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 | import android.widget.LinearLayout.LayoutParams;
11 | import android.widget.TextView;
12 |
13 | public final class TestFragment extends Fragment {
14 | private static final String KEY_CONTENT = "TestFragment:Content";
15 |
16 | public static TestFragment newInstance(String content) {
17 | TestFragment fragment = new TestFragment();
18 |
19 | StringBuilder builder = new StringBuilder();
20 | for (int i = 0; i < 30; i++) {
21 | builder.append(content).append(" ");
22 | }
23 | builder.deleteCharAt(builder.length() - 1);
24 | fragment.mContent = builder.toString();
25 |
26 | return fragment;
27 | }
28 |
29 | private String mContent = "???";
30 |
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
33 | if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
34 | mContent = savedInstanceState.getString(KEY_CONTENT);
35 | }
36 |
37 | TextView text = new TextView(getActivity());
38 | text.setText(mContent);
39 | text.setTextSize(20 * getResources().getDisplayMetrics().density);
40 | text.setPadding(20, 20, 20, 20);
41 | text.setGravity(Gravity.CENTER);
42 |
43 | LinearLayout layout = new LinearLayout(getActivity());
44 | layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
45 | layout.setGravity(Gravity.CENTER);
46 | layout.addView(text);
47 |
48 | return layout;
49 | }
50 |
51 | @Override
52 | public void onSaveInstanceState(Bundle outState) {
53 | super.onSaveInstanceState(outState);
54 | outState.putString(KEY_CONTENT, mContent);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/sample/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | com.directionalviewpager
7 | sample
8 | Android-DirectionalViewPager Sample
9 | apk
10 |
11 |
12 | com.directionalviewpager
13 | parent
14 | 1.2.1
15 | ../pom.xml
16 |
17 |
18 |
19 |
20 | android
21 | android
22 | provided
23 |
24 |
25 |
26 | android.support
27 | compatibility-v4
28 |
29 |
30 |
31 | com.directionalviewpager
32 | library
33 | ${project.version}
34 |
35 |
36 |
37 |
38 | src
39 | ${project.artifactId}-${project.version}-unaligned
40 |
41 |
42 |
43 | com.jayway.maven.plugins.android.generation2
44 | maven-android-plugin
45 | true
46 |
47 |
48 |
49 | org.apache.maven.plugins
50 | maven-javadoc-plugin
51 |
52 | true
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | release
61 |
62 |
63 | performRelease
64 | true
65 |
66 |
67 |
68 |
69 |
70 | com.jayway.maven.plugins.android.generation2
71 | maven-android-plugin
72 | true
73 |
74 |
75 | ${project.build.directory}/${project.build.finalName}.apk
76 | ${project.build.directory}/${project.artifactId}-${project.version}.apk
77 |
78 |
79 |
80 |
81 | alignApk
82 | package
83 |
84 | zipalign
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android DirectionalViewPager
2 | ============================
3 |
4 | Implementation of the [compatibility library][1] `ViewPager` class that supports
5 | paging both vertically and horizontally as well as changing between the two
6 | at runtime.
7 |
8 | Try out the sample application [on the Android Market][4].
9 |
10 | ![Example Image][3]
11 |
12 |
13 |
14 | Usage
15 | =====
16 |
17 | *For a working implementation of this project see the `sample/` folder.*
18 |
19 | 1. Include the widget in your view.
20 |
21 |
25 |
26 | By default the widget will page horizontally. You can alter this behavior by
27 | including `android:orientation="vertical"` in the layout or by calling
28 | `setOrientation(DirectionalViewPager.VERTICAL)` in your code.
29 |
30 | 2. In your `onCreate` method (or `onCreateView` for a fragment), bind to a
31 | `PagerAdapter` implementation.
32 |
33 | DirectionalViewPager pager = (DirectionalViewPager)findViewById(R.id.pager);
34 | pager.setAdapter(new TestAdapter(getSupportFragmentManager()));
35 |
36 |
37 | Including In Your Project
38 | -------------------------
39 |
40 | Android-DirectionalViewPager is presented as a standalone `.jar` file. It should
41 | included in addition to the compatibility library `.jar`.
42 |
43 | You can download the file from the GitHub [downloads page][2] or compile your
44 | own by running `mvn clean package` (it will be in the `library/target/` folder).
45 |
46 | If you are using maven you can easily include the library by specifying it
47 | as a dependency:
48 |
49 |
50 | com.directionalviewpager
51 | library
52 | 1.2.0
53 |
54 |
55 | You must also include the following repository:
56 |
57 |
58 | com.jakewharton
59 | http://r.jakewharton.com/maven/release
60 |
61 |
62 |
63 |
64 | Developed By
65 | ============
66 |
67 | * Jake Wharton -
68 |
69 |
70 |
71 | License
72 | =======
73 |
74 | Copyright 2011 Jake Wharton
75 | Copyright 2011 Android Open Source Project
76 |
77 | Licensed under the Apache License, Version 2.0 (the "License");
78 | you may not use this file except in compliance with the License.
79 | You may obtain a copy of the License at
80 |
81 | http://www.apache.org/licenses/LICENSE-2.0
82 |
83 | Unless required by applicable law or agreed to in writing, software
84 | distributed under the License is distributed on an "AS IS" BASIS,
85 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
86 | See the License for the specific language governing permissions and
87 | limitations under the License.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | [1]: http://developer.android.com/sdk/compatibility-library.html
96 | [2]: https://github.com/JakeWharton/Android-DirectionalViewPager/downloads
97 | [3]: https://raw.github.com/JakeWharton/Android-DirectionalViewPager/master/sample/screens.png
98 | [4]: https://market.android.com/details?id=com.directionalviewpager.sample
99 |
--------------------------------------------------------------------------------
/library/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4.0.0
5 |
6 | com.directionalviewpager
7 | parent
8 | pom
9 | 1.2.1
10 |
11 | Android-DirectionalViewPager (Parent)
12 | Implementation of the compatibility library ViewPager class that supports both vertical and horizontal paging.
13 | https://github.com/JakeWharton/Android-DirectionalViewPager
14 | 2011
15 |
16 |
17 | library
18 | sample
19 |
20 |
21 |
22 | http://github.com/JakeWharton/Android-DirectionalViewPager/
23 | scm:git:git://github.com/JakeWharton/Android-DirectionalViewPager.git
24 | scm:git:git@github.com:JakeWharton/Android-DirectionalViewPager.git
25 |
26 |
27 |
28 |
29 | Jake Wharton
30 | jakewharton@gmail.com
31 | jakewharton
32 | http://jakewharton.com
33 | -5
34 |
35 | developer
36 |
37 |
38 |
39 |
40 |
41 |
42 | Apache License Version 2.0
43 | http://www.apache.org/licenses/LICENSE-2.0.txt
44 | repo
45 |
46 |
47 |
48 |
49 |
50 | personal-repository
51 | JakeWharton.com Maven Repository
52 | scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/release/
53 |
54 |
55 | personal-repository
56 | JakeWharton.com Maven Repository
57 | scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/snapshot/
58 |
59 |
60 |
61 |
62 | Jake Wharton
63 | http://jakewharton.com
64 |
65 |
66 |
67 | GitHub Issues
68 | https://github.com/JakeWharton/Android-DirectionalViewPager/issues
69 |
70 |
71 |
72 | UTF-8
73 | UTF-8
74 |
75 | 1.6
76 | 1.6_r3
77 | 4
78 | r3
79 |
80 |
81 |
82 |
83 |
84 | android
85 | android
86 | ${android.version}
87 |
88 |
89 |
90 | android.support
91 | compatibility-v4
92 | ${android.support.version}
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | org.apache.maven.plugins
102 | maven-compiler-plugin
103 | 2.3.2
104 |
105 | ${java.version}
106 | ${java.version}
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-javadoc-plugin
113 | 2.8
114 |
115 |
116 |
117 | com.jayway.maven.plugins.android.generation2
118 | android-maven-plugin
119 | 3.0.0-alpha-13
120 |
121 |
122 | ${android.platform}
123 |
124 | true
125 |
126 | true
127 |
128 |
129 |
130 | org.apache.maven.plugins
131 | maven-checkstyle-plugin
132 | 2.6
133 |
134 | true
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | org.apache.maven.plugins
143 | maven-release-plugin
144 | 2.1
145 |
146 | true
147 |
148 |
149 |
150 |
151 | org.apache.maven.plugins
152 | maven-deploy-plugin
153 | 2.6
154 |
155 |
156 | org.apache.maven.wagon
157 | wagon-ssh
158 | 1.0-beta-7
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/library/src/com/directionalviewpager/DirectionalViewPager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 The Android Open Source Project
3 | * Copyright (C) 2011 Jake Wharton
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package com.directionalviewpager;
19 |
20 | import java.util.ArrayList;
21 | import android.content.Context;
22 | import android.os.Build;
23 | import android.os.Parcel;
24 | import android.os.Parcelable;
25 | import android.support.v4.os.ParcelableCompat;
26 | import android.support.v4.os.ParcelableCompatCreatorCallbacks;
27 | import android.support.v4.view.MotionEventCompat;
28 | import android.support.v4.view.PagerAdapter;
29 | import android.support.v4.view.VelocityTrackerCompat;
30 | import android.support.v4.view.VerticalViewPagerCompat;
31 | import android.support.v4.view.ViewConfigurationCompat;
32 | import android.support.v4.view.ViewPager;
33 | import android.util.AttributeSet;
34 | import android.util.Log;
35 | import android.view.MotionEvent;
36 | import android.view.VelocityTracker;
37 | import android.view.View;
38 | import android.view.ViewConfiguration;
39 | import android.view.ViewGroup;
40 | import android.widget.Scroller;
41 |
42 | /**
43 | * Layout manager that allows the user to flip horizontally or vertically
44 | * through pages of data. You supply an implementation of a
45 | * {@link PagerAdapter} to generate the pages that the view shows.
46 | *
47 | *
Note this class is currently under early design and
48 | * development. The API will likely change in later updates of
49 | * the compatibility library, requiring changes to the source code
50 | * of apps when they are compiled against the newer version.
51 | */
52 | public class DirectionalViewPager extends ViewPager {
53 | private static final String TAG = "DirectionalViewPager";
54 | private static final String XML_NS = "http://schemas.android.com/apk/res/android";
55 | private static final boolean DEBUG = false;
56 |
57 | private static final boolean USE_CACHE = false;
58 |
59 | public static final int HORIZONTAL = 0;
60 | public static final int VERTICAL = 1;
61 |
62 | static class ItemInfo {
63 | Object object;
64 | int position;
65 | boolean scrolling;
66 | }
67 |
68 | private final ArrayList mItems = new ArrayList();
69 |
70 | private PagerAdapter mAdapter;
71 | private int mCurItem; // Index of currently displayed page.
72 | private int mRestoredCurItem = -1;
73 | private Parcelable mRestoredAdapterState = null;
74 | private ClassLoader mRestoredClassLoader = null;
75 | private Scroller mScroller;
76 | private VerticalViewPagerCompat.DataSetObserver mObserver;
77 |
78 | private int mChildWidthMeasureSpec;
79 | private int mChildHeightMeasureSpec;
80 | private boolean mInLayout;
81 |
82 | private boolean mScrollingCacheEnabled;
83 |
84 | private boolean mPopulatePending;
85 | private boolean mScrolling;
86 |
87 | private boolean mIsBeingDragged;
88 | private boolean mIsUnableToDrag;
89 | private int mTouchSlop;
90 | private float mInitialMotion;
91 | /**
92 | * Position of the last motion event.
93 | */
94 | private float mLastMotionX;
95 | private float mLastMotionY;
96 | private int mOrientation = HORIZONTAL;
97 | /**
98 | * ID of the active pointer. This is used to retain consistency during
99 | * drags/flings if multiple pointers are used.
100 | */
101 | private int mActivePointerId = INVALID_POINTER;
102 | /**
103 | * Sentinel value for no current active pointer.
104 | * Used by {@link #mActivePointerId}.
105 | */
106 | private static final int INVALID_POINTER = -1;
107 |
108 | /**
109 | * Determines speed during touch scrolling
110 | */
111 | private VelocityTracker mVelocityTracker;
112 | private int mMinimumVelocity;
113 | private int mMaximumVelocity;
114 |
115 | private OnPageChangeListener mOnPageChangeListener;
116 |
117 | private int mScrollState = SCROLL_STATE_IDLE;
118 |
119 | public DirectionalViewPager(Context context) {
120 | super(context);
121 | initViewPager();
122 | }
123 |
124 | public DirectionalViewPager(Context context, AttributeSet attrs) {
125 | super(context, attrs);
126 | initViewPager();
127 |
128 | //We default to horizontal, only change if a value is explicitly specified
129 | int orientation = attrs.getAttributeIntValue(XML_NS, "orientation", -1);
130 | if (orientation != -1) {
131 | setOrientation(orientation);
132 | }
133 | }
134 |
135 | void initViewPager() {
136 | setWillNotDraw(false);
137 | mScroller = new Scroller(getContext());
138 | final ViewConfiguration configuration = ViewConfiguration.get(getContext());
139 | mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
140 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
141 | mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
142 | }
143 |
144 | private void setScrollState(int newState) {
145 | if (mScrollState == newState) {
146 | return;
147 | }
148 |
149 | mScrollState = newState;
150 | if (mOnPageChangeListener != null) {
151 | mOnPageChangeListener.onPageScrollStateChanged(newState);
152 | }
153 | }
154 |
155 | public void setAdapter(PagerAdapter adapter) {
156 | if (mAdapter != null) {
157 | VerticalViewPagerCompat.setDataSetObserver(mAdapter, null);
158 | }
159 |
160 | mAdapter = adapter;
161 |
162 | if (mAdapter != null) {
163 | if (mObserver == null) {
164 | mObserver = new DataSetObserver();
165 | }
166 | VerticalViewPagerCompat.setDataSetObserver(mAdapter, mObserver);
167 | mPopulatePending = false;
168 | if (mRestoredCurItem >= 0) {
169 | mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
170 | setCurrentItemInternal(mRestoredCurItem, false, true);
171 | mRestoredCurItem = -1;
172 | mRestoredAdapterState = null;
173 | mRestoredClassLoader = null;
174 | } else {
175 | populate();
176 | }
177 | }
178 | }
179 |
180 | public PagerAdapter getAdapter() {
181 | return mAdapter;
182 | }
183 |
184 | public void setCurrentItem(int item) {
185 | mPopulatePending = false;
186 | setCurrentItemInternal(item, true, false);
187 | }
188 |
189 | void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
190 | if (mAdapter == null || mAdapter.getCount() <= 0) {
191 | setScrollingCacheEnabled(false);
192 | return;
193 | }
194 | if (!always && mCurItem == item && mItems.size() != 0) {
195 | setScrollingCacheEnabled(false);
196 | return;
197 | }
198 | if (item < 0) {
199 | item = 0;
200 | } else if (item >= mAdapter.getCount()) {
201 | item = mAdapter.getCount() - 1;
202 | }
203 | if (item > (mCurItem+1) || item < (mCurItem-1)) {
204 | // We are doing a jump by more than one page. To avoid
205 | // glitches, we want to keep all current pages in the view
206 | // until the scroll ends.
207 | for (int i=0; i 0;
283 | int newCurrItem = -1;
284 |
285 | for (int i = 0; i < mItems.size(); i++) {
286 | final ItemInfo ii = mItems.get(i);
287 | final int newPos = mAdapter.getItemPosition(ii.object);
288 |
289 | if (newPos == PagerAdapter.POSITION_UNCHANGED) {
290 | continue;
291 | }
292 |
293 | if (newPos == PagerAdapter.POSITION_NONE) {
294 | mItems.remove(i);
295 | i--;
296 | mAdapter.destroyItem(this, ii.position, ii.object);
297 | needPopulate = true;
298 |
299 | if (mCurItem == ii.position) {
300 | // Keep the current item in the valid range
301 | newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));
302 | }
303 | continue;
304 | }
305 |
306 | if (ii.position != newPos) {
307 | if (ii.position == mCurItem) {
308 | // Our current item changed position. Follow it.
309 | newCurrItem = newPos;
310 | }
311 |
312 | ii.position = newPos;
313 | needPopulate = true;
314 | }
315 | }
316 |
317 | if (newCurrItem >= 0) {
318 | // TODO This currently causes a jump.
319 | setCurrentItemInternal(newCurrItem, false, true);
320 | needPopulate = true;
321 | }
322 | if (needPopulate) {
323 | populate();
324 | requestLayout();
325 | }
326 | }
327 |
328 | void populate() {
329 | if (mAdapter == null) {
330 | return;
331 | }
332 |
333 | // Bail now if we are waiting to populate. This is to hold off
334 | // on creating views from the time the user releases their finger to
335 | // fling to a new position until we have finished the scroll to
336 | // that position, avoiding glitches from happening at that point.
337 | if (mPopulatePending) {
338 | if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");
339 | return;
340 | }
341 |
342 | // Also, don't populate until we are attached to a window. This is to
343 | // avoid trying to populate before we have restored our view hierarchy
344 | // state and conflicting with what is restored.
345 | if (getWindowToken() == null) {
346 | return;
347 | }
348 |
349 | mAdapter.startUpdate(this);
350 |
351 | final int startPos = mCurItem > 0 ? mCurItem - 1 : mCurItem;
352 | final int count = mAdapter.getCount();
353 | final int endPos = mCurItem < (count-1) ? mCurItem+1 : count-1;
354 |
355 | if (DEBUG) Log.v(TAG, "populating: startPos=" + startPos + " endPos=" + endPos);
356 |
357 | // Add and remove pages in the existing list.
358 | int lastPos = -1;
359 | for (int i=0; i endPos) && !ii.scrolling) {
362 | if (DEBUG) Log.i(TAG, "removing: " + ii.position + " @ " + i);
363 | mItems.remove(i);
364 | i--;
365 | mAdapter.destroyItem(this, ii.position, ii.object);
366 | } else if (lastPos < endPos && ii.position > startPos) {
367 | // The next item is outside of our range, but we have a gap
368 | // between it and the last item where we want to have a page
369 | // shown. Fill in the gap.
370 | lastPos++;
371 | if (lastPos < startPos) {
372 | lastPos = startPos;
373 | }
374 | while (lastPos <= endPos && lastPos < ii.position) {
375 | if (DEBUG) Log.i(TAG, "inserting: " + lastPos + " @ " + i);
376 | addNewItem(lastPos, i);
377 | lastPos++;
378 | i++;
379 | }
380 | }
381 | lastPos = ii.position;
382 | }
383 |
384 | // Add any new pages we need at the end.
385 | lastPos = mItems.size() > 0 ? mItems.get(mItems.size()-1).position : -1;
386 | if (lastPos < endPos) {
387 | lastPos++;
388 | lastPos = lastPos > startPos ? lastPos : startPos;
389 | while (lastPos <= endPos) {
390 | if (DEBUG) Log.i(TAG, "appending: " + lastPos);
391 | addNewItem(lastPos, -1);
392 | lastPos++;
393 | }
394 | }
395 |
396 | if (DEBUG) {
397 | Log.i(TAG, "Current page list:");
398 | for (int i=0; i CREATOR
430 | = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() {
431 | @Override
432 | public SavedState createFromParcel(Parcel in, ClassLoader loader) {
433 | return new SavedState(in, loader);
434 | }
435 | @Override
436 | public SavedState[] newArray(int size) {
437 | return new SavedState[size];
438 | }
439 | });
440 |
441 | SavedState(Parcel in, ClassLoader loader) {
442 | super(in);
443 | if (loader == null) {
444 | loader = getClass().getClassLoader();
445 | }
446 | position = in.readInt();
447 | adapterState = in.readParcelable(loader);
448 | this.loader = loader;
449 | }
450 | }
451 |
452 | @Override
453 | public Parcelable onSaveInstanceState() {
454 | Parcelable superState = super.onSaveInstanceState();
455 | SavedState ss = new SavedState(superState);
456 | ss.position = mCurItem;
457 | ss.adapterState = mAdapter.saveState();
458 | return ss;
459 | }
460 |
461 | @Override
462 | public void onRestoreInstanceState(Parcelable state) {
463 | if (!(state instanceof SavedState)) {
464 | super.onRestoreInstanceState(state);
465 | return;
466 | }
467 |
468 | SavedState ss = (SavedState)state;
469 | super.onRestoreInstanceState(ss.getSuperState());
470 |
471 | if (mAdapter != null) {
472 | mAdapter.restoreState(ss.adapterState, ss.loader);
473 | setCurrentItemInternal(ss.position, false, true);
474 | } else {
475 | mRestoredCurItem = ss.position;
476 | mRestoredAdapterState = ss.adapterState;
477 | mRestoredClassLoader = ss.loader;
478 | }
479 | }
480 |
481 | public int getOrientation() {
482 | return mOrientation;
483 | }
484 |
485 | public void setOrientation(int orientation) {
486 | switch (orientation) {
487 | case HORIZONTAL:
488 | case VERTICAL:
489 | break;
490 |
491 | default:
492 | throw new IllegalArgumentException("Only HORIZONTAL and VERTICAL are valid orientations.");
493 | }
494 |
495 | if (orientation == mOrientation) {
496 | return;
497 | }
498 |
499 | //Complete any scroll we are currently in the middle of
500 | completeScroll();
501 |
502 | //Reset values
503 | mInitialMotion = 0;
504 | mLastMotionX = 0;
505 | mLastMotionY = 0;
506 | if (mVelocityTracker != null) {
507 | mVelocityTracker.clear();
508 | }
509 |
510 | //Adjust scroll for new orientation
511 | mOrientation = orientation;
512 | if (mOrientation == HORIZONTAL) {
513 | scrollTo(mCurItem * getWidth(), 0);
514 | } else {
515 | scrollTo(0, mCurItem * getHeight());
516 | }
517 | requestLayout();
518 | }
519 |
520 | @Override
521 | public void addView(View child, int index, ViewGroup.LayoutParams params) {
522 | if (mInLayout) {
523 | addViewInLayout(child, index, params);
524 | child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec);
525 | } else {
526 | super.addView(child, index, params);
527 | }
528 |
529 | if (USE_CACHE) {
530 | if (child.getVisibility() != GONE) {
531 | child.setDrawingCacheEnabled(mScrollingCacheEnabled);
532 | } else {
533 | child.setDrawingCacheEnabled(false);
534 | }
535 | }
536 | }
537 |
538 | ItemInfo infoForChild(View child) {
539 | for (int i=0; i Build.VERSION_CODES.DONUT) {
757 | // If we don't have a valid id, the touch down wasn't on content.
758 | break;
759 | }
760 |
761 | final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);
762 | final float x = MotionEventCompat.getX(ev, pointerIndex);
763 | final float y = MotionEventCompat.getY(ev, pointerIndex);
764 | final float xDiff = Math.abs(x - mLastMotionX);
765 | final float yDiff = Math.abs(y - mLastMotionY);
766 | float primaryDiff;
767 | float secondaryDiff;
768 |
769 | if (mOrientation == HORIZONTAL) {
770 | primaryDiff = xDiff;
771 | secondaryDiff = yDiff;
772 | } else {
773 | primaryDiff = yDiff;
774 | secondaryDiff = xDiff;
775 | }
776 |
777 |
778 | if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
779 |
780 | if (primaryDiff > mTouchSlop && primaryDiff > secondaryDiff) {
781 | if (DEBUG) Log.v(TAG, "Starting drag!");
782 | mIsBeingDragged = true;
783 | setScrollState(SCROLL_STATE_DRAGGING);
784 | if (mOrientation == HORIZONTAL) {
785 | mLastMotionX = x;
786 | } else {
787 | mLastMotionY = y;
788 | }
789 | setScrollingCacheEnabled(true);
790 | } else {
791 | if (secondaryDiff > mTouchSlop) {
792 | // The finger has moved enough in the vertical
793 | // direction to be counted as a drag... abort
794 | // any attempt to drag horizontally, to work correctly
795 | // with children that have scrolling containers.
796 | if (DEBUG) Log.v(TAG, "Starting unable to drag!");
797 | mIsUnableToDrag = true;
798 | }
799 | }
800 | break;
801 | }
802 |
803 | case MotionEvent.ACTION_DOWN: {
804 | /*
805 | * Remember location of down touch.
806 | * ACTION_DOWN always refers to pointer index 0.
807 | */
808 | if (mOrientation == HORIZONTAL) {
809 | mLastMotionX = mInitialMotion = ev.getX();
810 | mLastMotionY = ev.getY();
811 | } else {
812 | mLastMotionX = ev.getX();
813 | mLastMotionY = mInitialMotion = ev.getY();
814 | }
815 | mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
816 |
817 | if (mScrollState == SCROLL_STATE_SETTLING) {
818 | // Let the user 'catch' the pager as it animates.
819 | mIsBeingDragged = true;
820 | mIsUnableToDrag = false;
821 | setScrollState(SCROLL_STATE_DRAGGING);
822 | } else {
823 | completeScroll();
824 | mIsBeingDragged = false;
825 | mIsUnableToDrag = false;
826 | }
827 |
828 | if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY
829 | + " mIsBeingDragged=" + mIsBeingDragged
830 | + "mIsUnableToDrag=" + mIsUnableToDrag);
831 | break;
832 | }
833 |
834 | case MotionEventCompat.ACTION_POINTER_UP:
835 | onSecondaryPointerUp(ev);
836 | break;
837 | }
838 |
839 | /*
840 | * The only time we want to intercept motion events is if we are in the
841 | * drag mode.
842 | */
843 | return mIsBeingDragged;
844 | }
845 |
846 | @Override
847 | public boolean onTouchEvent(MotionEvent ev) {
848 |
849 | if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
850 | // Don't handle edge touches immediately -- they may actually belong to one of our
851 | // descendants.
852 | return false;
853 | }
854 |
855 | if (mAdapter == null || mAdapter.getCount() == 0) {
856 | // Nothing to present or scroll; nothing to touch.
857 | return false;
858 | }
859 |
860 | if (mVelocityTracker == null) {
861 | mVelocityTracker = VelocityTracker.obtain();
862 | }
863 | mVelocityTracker.addMovement(ev);
864 |
865 | final int action = ev.getAction();
866 |
867 | switch (action & MotionEventCompat.ACTION_MASK) {
868 | case MotionEvent.ACTION_DOWN: {
869 | /*
870 | * If being flinged and user touches, stop the fling. isFinished
871 | * will be false if being flinged.
872 | */
873 | completeScroll();
874 |
875 | // Remember where the motion event started
876 | if (mOrientation == HORIZONTAL) {
877 | mLastMotionX = mInitialMotion = ev.getX();
878 | } else {
879 | mLastMotionY = mInitialMotion = ev.getY();
880 | }
881 | mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
882 | break;
883 | }
884 | case MotionEvent.ACTION_MOVE:
885 | if (!mIsBeingDragged) {
886 | final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
887 | final float x = MotionEventCompat.getX(ev, pointerIndex);
888 | final float y = MotionEventCompat.getY(ev, pointerIndex);
889 | final float xDiff = Math.abs(x - mLastMotionX);
890 | final float yDiff = Math.abs(y - mLastMotionY);
891 | float primaryDiff;
892 | float secondaryDiff;
893 |
894 | if (mOrientation == HORIZONTAL) {
895 | primaryDiff = xDiff;
896 | secondaryDiff = yDiff;
897 | } else {
898 | primaryDiff = yDiff;
899 | secondaryDiff = xDiff;
900 | }
901 |
902 |
903 | if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
904 | if (primaryDiff > mTouchSlop && primaryDiff > secondaryDiff) {
905 | if (DEBUG) Log.v(TAG, "Starting drag!");
906 | mIsBeingDragged = true;
907 | if (mOrientation == HORIZONTAL) {
908 | mLastMotionX = x;
909 | } else {
910 | mLastMotionY = y;
911 | }
912 | setScrollState(SCROLL_STATE_DRAGGING);
913 | setScrollingCacheEnabled(true);
914 | }
915 | }
916 | if (mIsBeingDragged) {
917 | // Scroll to follow the motion event
918 | final int activePointerIndex = MotionEventCompat.findPointerIndex(
919 | ev, mActivePointerId);
920 | final float x = MotionEventCompat.getX(ev, activePointerIndex);
921 | final float y = MotionEventCompat.getY(ev, activePointerIndex);
922 |
923 | int size;
924 | float scroll;
925 |
926 | if (mOrientation == HORIZONTAL) {
927 | size = getWidth();
928 | scroll = getScrollX() + (mLastMotionX - x);
929 | mLastMotionX = x;
930 | } else {
931 | size = getHeight();
932 | scroll = getScrollY() + (mLastMotionY - y);
933 | mLastMotionY = y;
934 | }
935 |
936 | final float lowerBound = Math.max(0, (mCurItem - 1) * size);
937 | final float upperBound =
938 | Math.min(mCurItem + 1, mAdapter.getCount() - 1) * size;
939 | if (scroll < lowerBound) {
940 | scroll = lowerBound;
941 | } else if (scroll > upperBound) {
942 | scroll = upperBound;
943 | }
944 | if (mOrientation == HORIZONTAL) {
945 | // Don't lose the rounded component
946 | mLastMotionX += scroll - (int) scroll;
947 | scrollTo((int) scroll, getScrollY());
948 | } else {
949 | // Don't lose the rounded component
950 | mLastMotionY += scroll - (int) scroll;
951 | scrollTo(getScrollX(), (int) scroll);
952 | }
953 | if (mOnPageChangeListener != null) {
954 | final int position = (int) scroll / size;
955 | final int positionOffsetPixels = (int) scroll % size;
956 | final float positionOffset = (float) positionOffsetPixels / size;
957 | mOnPageChangeListener.onPageScrolled(position, positionOffset,
958 | positionOffsetPixels);
959 | }
960 | }
961 | break;
962 | case MotionEvent.ACTION_UP:
963 | if (mIsBeingDragged) {
964 | final VelocityTracker velocityTracker = mVelocityTracker;
965 | velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
966 | int initialVelocity;
967 | float lastMotion;
968 | int sizeOverThree;
969 |
970 | if (mOrientation == HORIZONTAL) {
971 | initialVelocity = (int)VelocityTrackerCompat.getXVelocity(
972 | velocityTracker, mActivePointerId);
973 | lastMotion = mLastMotionX;
974 | sizeOverThree = getWidth() / 3;
975 | } else {
976 | initialVelocity = (int)VelocityTrackerCompat.getYVelocity(
977 | velocityTracker, mActivePointerId);
978 | lastMotion = mLastMotionY;
979 | sizeOverThree = getHeight() / 3;
980 | }
981 |
982 | mPopulatePending = true;
983 | if ((Math.abs(initialVelocity) > mMinimumVelocity)
984 | || Math.abs(mInitialMotion-lastMotion) >= sizeOverThree) {
985 | if (lastMotion > mInitialMotion) {
986 | setCurrentItemInternal(mCurItem-1, true, true);
987 | } else {
988 | setCurrentItemInternal(mCurItem+1, true, true);
989 | }
990 | } else {
991 | setCurrentItemInternal(mCurItem, true, true);
992 | }
993 |
994 | mActivePointerId = INVALID_POINTER;
995 | endDrag();
996 | }
997 | break;
998 | case MotionEvent.ACTION_CANCEL:
999 | if (mIsBeingDragged) {
1000 | setCurrentItemInternal(mCurItem, true, true);
1001 | mActivePointerId = INVALID_POINTER;
1002 | endDrag();
1003 | }
1004 | break;
1005 | case MotionEventCompat.ACTION_POINTER_DOWN: {
1006 | final int index = MotionEventCompat.getActionIndex(ev);
1007 | if (mOrientation == HORIZONTAL) {
1008 | mLastMotionX = MotionEventCompat.getX(ev, index);
1009 | } else {
1010 | mLastMotionY = MotionEventCompat.getY(ev, index);
1011 | }
1012 | mActivePointerId = MotionEventCompat.getPointerId(ev, index);
1013 | break;
1014 | }
1015 | case MotionEventCompat.ACTION_POINTER_UP:
1016 | onSecondaryPointerUp(ev);
1017 | final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
1018 | if (mOrientation == HORIZONTAL) {
1019 | mLastMotionX = MotionEventCompat.getX(ev, index);
1020 | } else {
1021 | mLastMotionY = MotionEventCompat.getY(ev, index);
1022 | }
1023 | break;
1024 | }
1025 | return true;
1026 | }
1027 |
1028 | private void onSecondaryPointerUp(MotionEvent ev) {
1029 | final int pointerIndex = MotionEventCompat.getActionIndex(ev);
1030 | final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
1031 | if (pointerId == mActivePointerId) {
1032 | // This was our active pointer going up. Choose a new
1033 | // active pointer and adjust accordingly.
1034 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
1035 | if (mOrientation == HORIZONTAL) {
1036 | mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);
1037 | } else {
1038 | mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex);
1039 | }
1040 | mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
1041 | if (mVelocityTracker != null) {
1042 | mVelocityTracker.clear();
1043 | }
1044 | }
1045 | }
1046 |
1047 | private void endDrag() {
1048 | mIsBeingDragged = false;
1049 | mIsUnableToDrag = false;
1050 |
1051 | if (mVelocityTracker != null) {
1052 | mVelocityTracker.recycle();
1053 | mVelocityTracker = null;
1054 | }
1055 | }
1056 |
1057 | private void setScrollingCacheEnabled(boolean enabled) {
1058 | if (mScrollingCacheEnabled != enabled) {
1059 | mScrollingCacheEnabled = enabled;
1060 | if (USE_CACHE) {
1061 | final int size = getChildCount();
1062 | for (int i = 0; i < size; ++i) {
1063 | final View child = getChildAt(i);
1064 | if (child.getVisibility() != GONE) {
1065 | child.setDrawingCacheEnabled(enabled);
1066 | }
1067 | }
1068 | }
1069 | }
1070 | }
1071 |
1072 | private class DataSetObserver implements VerticalViewPagerCompat.DataSetObserver {
1073 | @Override
1074 | public void onDataSetChanged() {
1075 | dataSetChanged();
1076 | }
1077 | }
1078 | }
1079 |
--------------------------------------------------------------------------------