├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── drawable
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ │ ├── styles.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── strings.xml
│ │ │ ├── menu
│ │ │ │ └── menu_main.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ └── layout
│ │ │ │ ├── list_item.xml
│ │ │ │ ├── fragment_list.xml
│ │ │ │ ├── fragment_recyclerview.xml
│ │ │ │ ├── fragment_webview.xml
│ │ │ │ ├── fragment_imageheader.xml
│ │ │ │ ├── fragment_simple.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── fragment_scrollview.xml
│ │ │ │ └── fragment_pagerheader.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── test
│ │ │ │ └── cp
│ │ │ │ └── myscrolllayout
│ │ │ │ ├── constant
│ │ │ │ └── ColorsConstant.java
│ │ │ │ ├── fragment
│ │ │ │ ├── base
│ │ │ │ │ ├── ScrollAbleFragment.java
│ │ │ │ │ └── BasePagerFragment.java
│ │ │ │ ├── ScrollViewFragment.java
│ │ │ │ ├── RecyclerViewFragment.java
│ │ │ │ ├── ListFragment.java
│ │ │ │ ├── ParallaxImageHeaderFragment.java
│ │ │ │ ├── WebViewFragment.java
│ │ │ │ ├── PagerHeaderFragment.java
│ │ │ │ └── SimpleDemoFragment.java
│ │ │ │ ├── adapter
│ │ │ │ ├── MyFragmentPagerAdapter.java
│ │ │ │ ├── MyAdapter.java
│ │ │ │ ├── MyHeadPicAdapter.java
│ │ │ │ └── RecyclerAdapter.java
│ │ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── test
│ │ └── cp
│ │ └── myscrolllayout
│ │ └── ApplicationTest.java
├── proguard-rules.pro
├── build.gradle
└── app.iml
├── scrollablelayoutlib
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── cpoopc
│ │ │ └── scrollablelayoutlib
│ │ │ ├── ScrollableHelper.java
│ │ │ └── ScrollableLayout.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── cpoopc
│ │ └── scrollablelayoutlib
│ │ └── ApplicationTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── image
└── preview.gif
├── demo-apk
└── app-debug.apk
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── PagerSlidingTabStrip
├── gradle.properties
├── res
│ ├── values
│ │ ├── colors.xml
│ │ └── attrs.xml
│ └── drawable
│ │ └── background_tab.xml
├── AndroidManifest.xml
├── project.properties
├── build.gradle
├── PagerSlidingTabStrip.iml
└── src
│ └── com
│ └── astuetz
│ └── PagerSlidingTabStrip.java
├── .gitignore
├── MyScrollLayout.iml
├── gradle.properties
├── LICENSE
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':PagerSlidingTabStrip', ':scrollablelayoutlib'
2 |
--------------------------------------------------------------------------------
/image/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/image/preview.gif
--------------------------------------------------------------------------------
/demo-apk/app-debug.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/demo-apk/app-debug.apk
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_NAME=PagerSlidingTabStrip Library
2 | POM_ARTIFACT_ID=pagerslidingtabstrip
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 | /.idea
8 | build
9 | *.iml
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/scrollablelayoutlib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ScrollableLayoutLib
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpoopc/ScrollableLayout/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6633B5E5
4 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #7B68EE
5 | #FF69B4
6 | #6495ED
7 | #FFBF00
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 30dp
6 | 150dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ScrollableLayout
3 |
4 | Hello world!
5 | Settings
6 |
7 |
8 | Hello blank fragment
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/constant/ColorsConstant.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.constant;/**
2 | * Created by cpoopc on 2015/7/31.
3 | */
4 |
5 | import com.test.cp.myscrolllayout.R;
6 |
7 | /**
8 | * User: cpoopc
9 | * Date: 2015-07-31
10 | * Time: 16:23
11 | * Ver.: 0.1
12 | */
13 | public class ColorsConstant {
14 | public final static int[] colors = new int[]{R.color.c_0,R.color.c_1,R.color.c_2,R.color.c_3};
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/test/cp/myscrolllayout/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/res/drawable/background_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/src/androidTest/java/com/cpoopc/scrollablelayoutlib/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.cpoopc.scrollablelayoutlib;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/base/ScrollAbleFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment.base;/**
2 | * Created by cpoopc on 2015/8/28.
3 | */
4 |
5 | import android.support.v4.app.Fragment;
6 |
7 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
8 |
9 | /**
10 | * User: cpoopc
11 | * Date: 2015-08-28
12 | * Time: 11:45
13 | * Ver.: 0.1
14 | */
15 | public abstract class ScrollAbleFragment extends Fragment implements ScrollableHelper.ScrollableContainer {
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_list.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_recyclerview.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-17
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android-library'
2 |
3 | dependencies {
4 | compile 'com.android.support:support-v4:19.0.0'
5 | }
6 |
7 | android {
8 | compileSdkVersion 21
9 | buildToolsVersion '21.1.1'
10 |
11 | defaultConfig {
12 | minSdkVersion 8
13 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
14 | }
15 |
16 | sourceSets {
17 | main {
18 | manifest.srcFile 'AndroidManifest.xml'
19 | java.srcDirs = ['src']
20 | res.srcDirs = ['res']
21 | }
22 | }
23 | }
24 |
25 | //apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'
--------------------------------------------------------------------------------
/app/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 E:\android\sdk\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 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/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 E:\Android\adt-bundle-windows-x86-20131030\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 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.test.cp.myscrolllayout"
9 | minSdkVersion 8
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile project(':PagerSlidingTabStrip')
25 | compile project(':scrollablelayoutlib')
26 | compile 'com.nineoldandroids:library:2.4.0'
27 | compile 'in.srain.cube:ultra-ptr:1.0.11'
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/MyScrollLayout.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | ANDROID_BUILD_TARGET_SDK_VERSION=21
20 | ANDROID_BUILD_TOOLS_VERSION=21.1.1
21 | ANDROID_BUILD_SDK_VERSION=21
22 | SAMPLE_VERSION_NAME="test_cp"
23 | SAMPLE_VERSION_CODE=1
24 | PROJ_ARTIFACTID=ScrollableLayout
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 cpoopc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_webview.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
16 |
21 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/adapter/MyFragmentPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.adapter;
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.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Created by cpoopc on 2015-02-10.
13 | */
14 | public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
15 |
16 | private List fragmentList;
17 | private List titleList;
18 |
19 | public MyFragmentPagerAdapter(FragmentManager fm, List fragmentList, List titleList) {
20 | super(fm);
21 | this.fragmentList = fragmentList;
22 | this.titleList = titleList;
23 | }
24 |
25 | @Override
26 | public Fragment getItem(int position) {
27 | return fragmentList.get(position);
28 | }
29 |
30 | @Override
31 | public int getCount() {
32 | return fragmentList.size();
33 | }
34 |
35 | @Override
36 | public CharSequence getPageTitle(int position) {
37 | return titleList.get(position);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/ScrollViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ScrollView;
9 |
10 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
11 | import com.test.cp.myscrolllayout.R;
12 | import com.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
13 |
14 |
15 | public class ScrollViewFragment extends ScrollAbleFragment implements ScrollableHelper.ScrollableContainer{
16 |
17 | private ScrollView scrollView;
18 |
19 | public static ScrollViewFragment newInstance() {
20 | ScrollViewFragment scrollViewFragment = new ScrollViewFragment();
21 | return scrollViewFragment;
22 | }
23 |
24 | @Override
25 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
26 | View view = inflater.inflate(R.layout.fragment_scrollview, container, false);
27 | scrollView = (ScrollView) view.findViewById(R.id.scrollview);
28 | return view;
29 | }
30 |
31 | @Override
32 | public View getScrollableView() {
33 | return scrollView;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_imageheader.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
20 |
21 |
22 |
23 |
28 |
29 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_simple.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
18 |
19 |
23 |
24 |
25 |
26 |
31 |
32 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
19 |
24 |
29 |
30 |
31 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/adapter/MyAdapter.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.BaseAdapter;
8 | import android.widget.TextView;
9 |
10 | import com.test.cp.myscrolllayout.R;
11 | import com.test.cp.myscrolllayout.constant.ColorsConstant;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Created by cpoopc on 2015-02-10.
17 | */
18 | public class MyAdapter extends BaseAdapter {
19 |
20 | private List strList;
21 | private Context mContext;
22 |
23 | public MyAdapter( Context mContext,List strList) {
24 | this.strList = strList;
25 | this.mContext = mContext;
26 | }
27 |
28 | @Override
29 | public int getCount() {
30 | return strList.size();
31 | }
32 |
33 | @Override
34 | public Object getItem(int position) {
35 | return null;
36 | }
37 |
38 | @Override
39 | public long getItemId(int position) {
40 | return 0;
41 | }
42 |
43 | @Override
44 | public View getView(int position, View convertView, ViewGroup parent) {
45 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null, false);
46 | convertView.setBackgroundColor(mContext.getResources().getColor(ColorsConstant.colors[position % ColorsConstant.colors.length]));
47 | TextView tv = (TextView) convertView.findViewById(R.id.tv);
48 | tv.setText(strList.get(position));
49 | return convertView;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_scrollview.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
15 |
20 |
24 |
28 |
32 |
36 |
40 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/RecyclerViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
12 | import com.test.cp.myscrolllayout.R;
13 | import com.test.cp.myscrolllayout.adapter.RecyclerAdapter;
14 | import com.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.Random;
19 |
20 | public class RecyclerViewFragment extends ScrollAbleFragment implements ScrollableHelper.ScrollableContainer{
21 |
22 | private RecyclerView mRecyclerView;
23 |
24 | public static RecyclerViewFragment newInstance() {
25 | RecyclerViewFragment recyclerViewFragment = new RecyclerViewFragment();
26 | return recyclerViewFragment;
27 | }
28 |
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | View view = inflater.inflate(R.layout.fragment_recyclerview, container, false);
32 | List strlist = new ArrayList();
33 | for (int i = 0; i < new Random().nextInt(100) + 31; i++) {
34 | strlist.add(String.valueOf(i));
35 | }
36 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
37 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
38 | mRecyclerView.setLayoutManager(linearLayoutManager);
39 | mRecyclerView.setAdapter(new RecyclerAdapter(getActivity(), strlist));
40 | return view;
41 | }
42 |
43 | @Override
44 | public View getScrollableView() {
45 | return mRecyclerView;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/adapter/MyHeadPicAdapter.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.Toast;
9 |
10 | import com.test.cp.myscrolllayout.constant.ColorsConstant;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | public class MyHeadPicAdapter extends PagerAdapter {
16 |
17 | List imageViews = new ArrayList();
18 |
19 | public MyHeadPicAdapter(Context context) {
20 | for (int i = 0; i < ColorsConstant.colors.length; i++) {
21 | ImageView imageView = new ImageView(context);
22 | imageView.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
23 | imageView.setBackgroundColor(context.getResources().getColor(ColorsConstant.colors[i]));
24 | final int index = i;
25 | imageView.setOnClickListener(new View.OnClickListener() {
26 | @Override
27 | public void onClick(View v) {
28 | Toast.makeText(v.getContext(), "im android " + index, Toast.LENGTH_SHORT).show();
29 | }
30 | });
31 | imageViews.add(imageView);
32 | }
33 | }
34 |
35 | @Override
36 | public int getCount() {
37 | return ColorsConstant.colors.length;
38 | }
39 |
40 | @Override
41 | public boolean isViewFromObject(View view, Object object) {
42 | return view == object;
43 | }
44 |
45 | @Override
46 | public Object instantiateItem(ViewGroup container, int position) {
47 | container.addView(imageViews.get(position), 0);
48 | return imageViews.get(position);
49 | }
50 |
51 | @Override
52 | public void destroyItem(ViewGroup container, int position, Object object) {
53 | container.removeView(imageViews.get(position));
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/ListFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.AdapterView;
9 | import android.widget.ListView;
10 | import android.widget.Toast;
11 |
12 |
13 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
14 | import com.test.cp.myscrolllayout.adapter.MyAdapter;
15 | import com.test.cp.myscrolllayout.R;
16 | import com.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 | import java.util.Random;
21 |
22 | public class ListFragment extends ScrollAbleFragment implements ScrollableHelper.ScrollableContainer{
23 |
24 | private ListView mListview;
25 |
26 | public static ListFragment newInstance() {
27 | ListFragment listFragment = new ListFragment();
28 | return listFragment;
29 | }
30 |
31 | @Override
32 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
33 | View view = inflater.inflate(R.layout.fragment_list, container, false);
34 | mListview = (ListView) view.findViewById(R.id.listview);
35 | List strlist = new ArrayList();
36 | // for (int i = 0; i < 99; i++) {
37 | for (int i = 0; i < new Random().nextInt(100) + 31; i++) {
38 | strlist.add(String.valueOf(i));
39 | }
40 | mListview.setAdapter(new MyAdapter(getActivity(), strlist));
41 | mListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
42 | @Override
43 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
44 | Toast.makeText(getActivity(), "点击item" + position, Toast.LENGTH_SHORT).show();
45 | }
46 | });
47 | return view;
48 | }
49 |
50 | @Override
51 | public View getScrollableView() {
52 | return mListview;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/ParallaxImageHeaderFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.view.ViewPager;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 |
11 | import com.astuetz.PagerSlidingTabStrip;
12 | import com.cpoopc.scrollablelayoutlib.ScrollableLayout;
13 | import com.nineoldandroids.view.ViewHelper;
14 | import com.test.cp.myscrolllayout.R;
15 | import com.test.cp.myscrolllayout.fragment.base.BasePagerFragment;
16 |
17 |
18 | public class ParallaxImageHeaderFragment extends BasePagerFragment {
19 |
20 | private ScrollableLayout mScrollLayout;
21 | private ImageView imageHeader;
22 |
23 | @Override
24 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
25 | View layout = inflater.inflate(R.layout.fragment_imageheader, container, false);
26 | ViewPager viewPager = (ViewPager) layout.findViewById(R.id.viewpager);
27 | imageHeader = (ImageView) layout.findViewById(R.id.imageHeader);
28 | // ScrollableLayout
29 | mScrollLayout = (ScrollableLayout) layout.findViewById(R.id.scrollableLayout);
30 | mScrollLayout.setOnScrollListener(new ScrollableLayout.OnScrollListener() {
31 | @Override
32 | public void onScroll(int currentY, int maxY) {
33 | ViewHelper.setTranslationY(imageHeader, (float) (currentY * 0.5));
34 | }
35 | });
36 | // 扩展点击头部滑动范围
37 | // int headHeight = getResources().getDimensionPixelSize(R.dimen.head_height);
38 | // int tabHeight = getResources().getDimensionPixelSize(R.dimen.tab_height);
39 | // mScrollLayout.setClickHeadExpand(headHeight + tabHeight);
40 | PagerSlidingTabStrip pagerSlidingTabStrip = (PagerSlidingTabStrip) layout.findViewById(R.id.pagerStrip);
41 | initFragmentPager(viewPager, pagerSlidingTabStrip, mScrollLayout);
42 | return layout;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [ScrollableLayout](https://github.com/cpoopc/ScrollableLayout)
2 | 共同头部+ViewPager+ListView(AdapterView)|RecyclerView|ScrollView|WebView
3 | blog:http://blog.csdn.net/w7822938/article/details/47173047
4 | 安装包放在/demo-apk,可以直接安装看效果
5 |
6 | ## UPDATE NOTE:
7 | 2015/12/18:
8 | 添加对WebView的支持.
9 | 2015/12/11:
10 | 添加canPtr()方法,支持下拉刷新(demo以[android-Ultra-Pull-To-Refresh](https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh)为例.
11 | 2015/8/31:
12 | 添加对RecyclerView的支持.
13 |
14 | 效果如下:
15 |
16 |
17 | ## Usage
18 | ```
19 | dependencies {
20 | compile 'com.github.cpoopc:scrollablelayoutlib:1.0.1' // 目前只发布到jcenter
21 | }
22 | ```
23 |
24 | 1.xml
25 | ```
26 |
31 | <-- header -->
32 | <-- header example -->
33 |
38 |
39 | <-- header example -->
40 |
41 | <-- content View -->
42 | <-- content View example -->
43 |
48 |
52 | <-- content View example -->
53 |
54 |
55 | ```
56 | 2.xxFragment|xxView|.. implements ScrollableHelper.ScrollableContainer
57 | ```
58 | @Override
59 | public View getScrollableView() {
60 | return scrollView;
61 | }
62 | ```
63 | 3.设置当前container
64 | ```
65 | mScrollLayout.getHelper().setCurrentScrollableContainer(scrollableContainer)
66 | ```
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_pagerheader.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
19 |
20 |
26 |
27 |
32 |
33 |
37 |
38 |
39 |
40 |
45 |
46 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/WebViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.webkit.WebChromeClient;
9 | import android.webkit.WebView;
10 | import android.webkit.WebViewClient;
11 | import android.widget.EditText;
12 |
13 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
14 | import com.test.cp.myscrolllayout.R;
15 | import com.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
16 |
17 |
18 | public class WebViewFragment extends ScrollAbleFragment implements ScrollableHelper.ScrollableContainer{
19 |
20 | private WebView webView;
21 | private EditText mAddressEdt;
22 |
23 | public static WebViewFragment newInstance() {
24 | WebViewFragment scrollViewFragment = new WebViewFragment();
25 | return scrollViewFragment;
26 | }
27 |
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | View view = inflater.inflate(R.layout.fragment_webview, container, false);
31 | mAddressEdt = (EditText) view.findViewById(R.id.addressEdt);
32 | view.findViewById(R.id.goBtn).setOnClickListener(new View.OnClickListener() {
33 | @Override
34 | public void onClick(View v) {
35 | webView.loadUrl(mAddressEdt.getText().toString());
36 | }
37 | });
38 | webView = (WebView) view.findViewById(R.id.webView);
39 | webView.getSettings().setJavaScriptEnabled(true);
40 | webView.getSettings().setDomStorageEnabled(true);
41 | webView.getSettings().setAllowContentAccess(true);
42 | webView.getSettings().setAppCacheEnabled(true);
43 | webView.getSettings().setDisplayZoomControls(true);
44 | webView.setWebChromeClient(new WebChromeClient());
45 | webView.setWebViewClient(new WebViewClient(){
46 | @Override
47 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
48 | view.loadUrl(url);
49 | return true;
50 | }
51 | });
52 | webView.loadUrl("https://github.com/cpoopc");
53 | return view;
54 | }
55 |
56 | @Override
57 | public View getScrollableView() {
58 | return webView;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/adapter/RecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.adapter;/**
2 | * Created by cpoopc on 2015/8/31.
3 | */
4 |
5 | import android.content.Context;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 | import android.widget.Toast;
12 |
13 | import com.test.cp.myscrolllayout.R;
14 | import com.test.cp.myscrolllayout.constant.ColorsConstant;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * User: cpoopc
20 | * Date: 2015-08-31
21 | * Time: 12:53
22 | * Ver.: 0.1
23 | */
24 | public class RecyclerAdapter extends RecyclerView.Adapter {
25 |
26 | private Context mContext;
27 | private List strList;
28 |
29 | public RecyclerAdapter(Context mContext, List strList) {
30 | this.mContext = mContext;
31 | this.strList = strList;
32 | }
33 |
34 | @Override
35 | public RecyclerAdapter.SimpleViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
36 | return new SimpleViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, viewGroup, false));
37 | }
38 |
39 | @Override
40 | public void onBindViewHolder(SimpleViewHolder simpleViewHolder, int i) {
41 | simpleViewHolder.bindData(strList.get(i),mContext.getResources().getColor(ColorsConstant.colors[i % ColorsConstant.colors.length]),i);
42 | }
43 |
44 | @Override
45 | public int getItemCount() {
46 | return strList.size();
47 | }
48 |
49 | public static class SimpleViewHolder extends RecyclerView.ViewHolder{
50 | View itemView;
51 | TextView tv;
52 | int position;
53 | public SimpleViewHolder(View itemView) {
54 | super(itemView);
55 | this.itemView = itemView;
56 | tv = (TextView) itemView.findViewById(R.id.tv);
57 | itemView.setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View v) {
60 | Toast.makeText(v.getContext(), "点击RecycleView item" + position, Toast.LENGTH_SHORT).show();
61 | }
62 | });
63 | }
64 |
65 | public void bindData(String txt,int bgcolor,int position) {
66 | this.position = position;
67 | tv.setText(txt);
68 | itemView.setBackgroundColor(bgcolor);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/base/BasePagerFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment.base;/**
2 | * Created by cpoopc on 2015/9/15.
3 | */
4 |
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.view.ViewPager;
7 | import android.util.Log;
8 |
9 | import com.astuetz.PagerSlidingTabStrip;
10 | import com.cpoopc.scrollablelayoutlib.ScrollableLayout;
11 | import com.test.cp.myscrolllayout.adapter.MyFragmentPagerAdapter;
12 | import com.test.cp.myscrolllayout.fragment.ListFragment;
13 | import com.test.cp.myscrolllayout.fragment.RecyclerViewFragment;
14 | import com.test.cp.myscrolllayout.fragment.ScrollViewFragment;
15 | import com.test.cp.myscrolllayout.fragment.WebViewFragment;
16 |
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | /**
21 | * User: cpoopc
22 | * Date: 2015-09-15
23 | * Time: 10:31
24 | * Ver.: 0.1
25 | */
26 | public abstract class BasePagerFragment extends Fragment{
27 |
28 | public void initFragmentPager( ViewPager viewPager,PagerSlidingTabStrip pagerSlidingTabStrip, final ScrollableLayout mScrollLayout) {
29 | final ArrayList fragmentList = new ArrayList<>();
30 | fragmentList.add(ListFragment.newInstance());
31 | fragmentList.add(ScrollViewFragment.newInstance());
32 | fragmentList.add(RecyclerViewFragment.newInstance());
33 | fragmentList.add(WebViewFragment.newInstance());
34 |
35 | List titleList = new ArrayList<>();
36 | titleList.add("ListView");
37 | titleList.add("ScrollView");
38 | titleList.add("RecyclerView");
39 | titleList.add("WebView");
40 | viewPager.setAdapter(new MyFragmentPagerAdapter(getChildFragmentManager(), fragmentList, titleList));
41 | mScrollLayout.getHelper().setCurrentScrollableContainer(fragmentList.get(0));
42 | pagerSlidingTabStrip.setViewPager(viewPager);
43 | pagerSlidingTabStrip.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
44 | @Override
45 | public void onPageScrolled(int i, float v, int i2) {
46 |
47 | }
48 |
49 | @Override
50 | public void onPageSelected(int i) {
51 | Log.e("onPageSelected", "page:" + i);
52 | /** 标注当前页面 **/
53 | mScrollLayout.getHelper().setCurrentScrollableContainer(fragmentList.get(i));
54 | }
55 |
56 | @Override
57 | public void onPageScrollStateChanged(int i) {
58 |
59 | }
60 | });
61 | viewPager.setCurrentItem(0);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 |
8 | import com.test.cp.myscrolllayout.fragment.PagerHeaderFragment;
9 | import com.test.cp.myscrolllayout.fragment.ParallaxImageHeaderFragment;
10 | import com.test.cp.myscrolllayout.fragment.SimpleDemoFragment;
11 |
12 |
13 | public class MainActivity extends AppCompatActivity {
14 |
15 | private View scrollView;
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_main);
21 | scrollView = findViewById(R.id.scrollView);
22 | }
23 |
24 | public void showParallaxFragment(View view) {
25 | showFragment(ParallaxImageHeaderFragment.class);
26 | }
27 |
28 | public void showPagerHeaderFragment(View view) {
29 | showFragment(PagerHeaderFragment.class);
30 | }
31 |
32 | public void showSimpleDemoFragment(View view) {
33 | showFragment(SimpleDemoFragment.class);
34 | }
35 |
36 | public void showFragment(Class clzz) {
37 | Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
38 | try {
39 | if (fragment == null) {
40 | getSupportFragmentManager().beginTransaction().add(R.id.fragmentContainer, clzz.newInstance(), clzz.getSimpleName()).commit();
41 | } else {
42 | getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainer, clzz.newInstance(), clzz.getSimpleName()).commit();
43 | }
44 | getSupportActionBar().setTitle(clzz.getSimpleName());
45 | scrollView.setVisibility(View.GONE);
46 | } catch (InstantiationException e) {
47 | e.printStackTrace();
48 | } catch (IllegalAccessException e) {
49 | e.printStackTrace();
50 | }
51 | }
52 |
53 | @Override
54 | public void onBackPressed() {
55 | if (!removeFragment()) {
56 | super.onBackPressed();
57 | } else {
58 | scrollView.setVisibility(View.VISIBLE);
59 | getSupportActionBar().setTitle(R.string.app_name);
60 | }
61 | }
62 |
63 | public boolean removeFragment() {
64 | Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
65 | if (fragment != null) {
66 | getSupportFragmentManager().beginTransaction().remove(fragment).commit();
67 | return true;
68 | } else {
69 | return false;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/PagerHeaderFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.view.ViewPager;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.astuetz.PagerSlidingTabStrip;
11 | import com.cpoopc.scrollablelayoutlib.ScrollableHelper;
12 | import com.cpoopc.scrollablelayoutlib.ScrollableLayout;
13 | import com.test.cp.myscrolllayout.R;
14 | import com.test.cp.myscrolllayout.adapter.MyHeadPicAdapter;
15 | import com.test.cp.myscrolllayout.fragment.base.BasePagerFragment;
16 |
17 | import in.srain.cube.views.ptr.PtrClassicFrameLayout;
18 | import in.srain.cube.views.ptr.PtrDefaultHandler;
19 | import in.srain.cube.views.ptr.PtrFrameLayout;
20 | import in.srain.cube.views.ptr.PtrHandler;
21 |
22 |
23 | public class PagerHeaderFragment extends BasePagerFragment {
24 |
25 | private PtrClassicFrameLayout mPtrFrame;
26 | private ScrollableLayout mScrollLayout;
27 |
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | View layout = inflater.inflate(R.layout.fragment_pagerheader, container, false);
31 | ViewPager viewPager = (ViewPager) layout.findViewById(R.id.viewpager);
32 | // 头部图片集
33 | ViewPager vpImage = (ViewPager) layout.findViewById(R.id.imagepager);
34 | vpImage.setAdapter(new MyHeadPicAdapter(getActivity()));
35 |
36 | // ScrollableLayout
37 | mScrollLayout = (ScrollableLayout) layout.findViewById(R.id.scrollableLayout);
38 | PagerSlidingTabStrip pagerSlidingTabStrip = (PagerSlidingTabStrip) layout.findViewById(R.id.pagerStrip);
39 | initFragmentPager(viewPager, pagerSlidingTabStrip, mScrollLayout);
40 | setupPullToRefresh(layout);
41 |
42 | return layout;
43 | }
44 |
45 | private void setupPullToRefresh(View layout) {
46 | mPtrFrame = (PtrClassicFrameLayout) layout.findViewById(R.id.rotate_header_web_view_frame);
47 | mPtrFrame.setLastUpdateTimeRelateObject(this);
48 | mPtrFrame.setPtrHandler(new PtrHandler() {
49 | @Override
50 | public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
51 | return mScrollLayout.canPtr();
52 | // return PtrDefaultHandler.checkContentCanBePulledDown(frame, mScrollLayout, header);
53 | }
54 |
55 | @Override
56 | public void onRefreshBegin(PtrFrameLayout frame) {
57 | mPtrFrame.postDelayed(new Runnable() {
58 | @Override
59 | public void run() {
60 | mPtrFrame.refreshComplete();
61 | }
62 | }, 100);
63 | }
64 | });
65 |
66 | // the following are default settings
67 | mPtrFrame.setResistance(1.7f);
68 | mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);
69 | mPtrFrame.setDurationToClose(200);
70 | mPtrFrame.setDurationToCloseHeader(1000);
71 | // default is false
72 | mPtrFrame.setPullToRefresh(false);
73 | // default is true
74 | mPtrFrame.setKeepHeaderWhenRefresh(true);
75 | mPtrFrame.postDelayed(new Runnable() {
76 | @Override
77 | public void run() {
78 | mPtrFrame.autoRefresh();
79 | }
80 | }, 100);
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/test/cp/myscrolllayout/fragment/SimpleDemoFragment.java:
--------------------------------------------------------------------------------
1 | package com.test.cp.myscrolllayout.fragment;
2 |
3 |
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.view.ViewPager;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.astuetz.PagerSlidingTabStrip;
14 | import com.cpoopc.scrollablelayoutlib.ScrollableLayout;
15 | import com.test.cp.myscrolllayout.R;
16 | import com.test.cp.myscrolllayout.adapter.MyFragmentPagerAdapter;
17 | import com.test.cp.myscrolllayout.adapter.MyHeadPicAdapter;
18 | import com.test.cp.myscrolllayout.fragment.base.ScrollAbleFragment;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * @author cpoopc
25 | * @date 2016/3/11
26 | * @time 11:31
27 | * @description
28 | */
29 | public class SimpleDemoFragment extends Fragment {
30 |
31 | private ScrollableLayout mScrollLayout;
32 |
33 | @Override
34 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
35 | View layout = inflater.inflate(R.layout.fragment_simple, container, false);
36 | ViewPager viewPager = (ViewPager) layout.findViewById(R.id.viewpager);
37 | // 头部图片集
38 | ViewPager vpImage = (ViewPager) layout.findViewById(R.id.imagepager);
39 | vpImage.setAdapter(new MyHeadPicAdapter(getActivity()));
40 |
41 | // ScrollableLayout
42 | mScrollLayout = (ScrollableLayout) layout.findViewById(R.id.scrollableLayout);
43 | PagerSlidingTabStrip pagerSlidingTabStrip = (PagerSlidingTabStrip) layout.findViewById(R.id.pagerStrip);
44 | initFragmentPager(viewPager, pagerSlidingTabStrip, mScrollLayout);
45 |
46 | return layout;
47 | }
48 |
49 | public void initFragmentPager( ViewPager viewPager,PagerSlidingTabStrip pagerSlidingTabStrip, final ScrollableLayout mScrollLayout) {
50 | final ArrayList fragmentList = new ArrayList<>();
51 | /** ListFragment实现ScrollableHelper.ScrollableContainer,返回嵌套的listview **/
52 | fragmentList.add(ListFragment.newInstance());
53 | fragmentList.add(ListFragment.newInstance());
54 |
55 | List titleList = new ArrayList<>();
56 | titleList.add("ListView1");
57 | titleList.add("ListView2");
58 | viewPager.setAdapter(new MyFragmentPagerAdapter(getChildFragmentManager(), fragmentList, titleList));
59 | /** 标注当前页面,从而ScrollableLayout可以从该ListFragment取到当前嵌套的listview,剩下的就交给ScrollableLayout去处理了 **/
60 | mScrollLayout.getHelper().setCurrentScrollableContainer(fragmentList.get(0));
61 | pagerSlidingTabStrip.setViewPager(viewPager);
62 | pagerSlidingTabStrip.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
63 | @Override
64 | public void onPageScrolled(int i, float v, int i2) {
65 |
66 | }
67 |
68 | @Override
69 | public void onPageSelected(int i) {
70 | Log.e("onPageSelected", "page:" + i);
71 | /** 页面切换时,标注当前页面,从而ScrollableLayout可以从该ListFragment取到当前嵌套的listview,剩下的就交给ScrollableLayout去处理了 **/
72 | mScrollLayout.getHelper().setCurrentScrollableContainer(fragmentList.get(i));
73 | }
74 |
75 | @Override
76 | public void onPageScrollStateChanged(int i) {
77 |
78 | }
79 | });
80 | viewPager.setCurrentItem(0);
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "22.0.1"
6 | resourcePrefix "cplib_"
7 |
8 | defaultConfig {
9 | minSdkVersion 8
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:22.2.0'
25 | compile 'com.android.support:recyclerview-v7:22.2.0'
26 | compile 'com.android.support:support-v4:22.2.0'
27 | }
28 |
29 | //apply plugin: 'com.github.dcendents.android-maven'
30 | //apply plugin: 'com.jfrog.bintray'
31 | //// library版本
32 | //version = "1.0.0"
33 | //
34 | //def siteUrl = 'https://github.com/cpoopc/ScrollableLayout' // 项目的主页
35 | //def gitUrl = 'https://github.com/cpoopc/ScrollableLayout.git' // Git仓库的url
36 | //group = 'com.github.cpoopc' // Maven Group ID for the artifact,一般填你唯一的包名
37 | //
38 | //install {
39 | // repositories.mavenInstaller {
40 | // // This generates POM.xml with proper parameters
41 | // pom {
42 | // project {
43 | // packaging 'aar'
44 | // // Add your description here
45 | // name 'support common header with tabstrip,viewpager layout' //项目描述
46 | // url siteUrl
47 | // // Set your license
48 | // licenses {
49 | // license {
50 | // name 'The MIT License (MIT)'
51 | // url 'http://opensource.org/licenses/MIT'
52 | // }
53 | // }
54 | // developers {
55 | // developer {
56 | // id 'cpoopc' //填写开发者基本信息
57 | // name 'cp'
58 | // email '303727604@qq.com'
59 | // }
60 | // }
61 | // scm {
62 | // connection gitUrl
63 | // developerConnection gitUrl
64 | // url siteUrl
65 | // }
66 | // }
67 | // }
68 | // }
69 | //}
70 | //task sourcesJar(type: Jar) {
71 | // from android.sourceSets.main.java.srcDirs
72 | // classifier = 'sources'
73 | //}
74 | //task javadoc(type: Javadoc) {
75 | // source = android.sourceSets.main.java.srcDirs
76 | // classpath += configurations.compile
77 | // classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
78 | //}
79 | //task javadocJar(type: Jar, dependsOn: javadoc) {
80 | // classifier = 'javadoc'
81 | // from javadoc.destinationDir
82 | //}
83 | //javadoc {
84 | // options{
85 | // encoding "UTF-8"
86 | // charSet 'UTF-8'
87 | // author true
88 | // version true
89 | // links "http://docs.oracle.com/javase/7/docs/api"
90 | // title PROJ_ARTIFACTID
91 | // }
92 | //}
93 | //
94 | //artifacts {
95 | // archives javadocJar
96 | // archives sourcesJar
97 | //}
98 | //Properties properties = new Properties()
99 | //properties.load(project.rootProject.file('local.properties').newDataInputStream())
100 | //bintray {
101 | // user = properties.getProperty("bintray.user")
102 | // key = properties.getProperty("bintray.apikey")
103 | // configurations = ['archives']
104 | // pkg {
105 | // repo = "maven" //发布到Bintray的那个仓库里,默认账户有四个库,我们这里上传到maven库
106 | // name = PROJ_ARTIFACTID //发布到Bintray上的项目名字
107 | // websiteUrl = siteUrl
108 | // vcsUrl = gitUrl
109 | // licenses = ["MIT"]
110 | // publish = true
111 | // }
112 | //}
113 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/src/main/java/com/cpoopc/scrollablelayoutlib/ScrollableHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 cpoopc
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 | package com.cpoopc.scrollablelayoutlib;
25 |
26 | import android.annotation.SuppressLint;
27 | import android.os.Build;
28 | import android.support.v7.widget.LinearLayoutManager;
29 | import android.support.v7.widget.RecyclerView;
30 | import android.view.View;
31 | import android.webkit.WebView;
32 | import android.widget.AbsListView;
33 | import android.widget.AdapterView;
34 | import android.widget.ScrollView;
35 |
36 | /**
37 | * Created by cpoopc(303727604@qq.com) on 2015-02-10.
38 | */
39 | public class ScrollableHelper {
40 |
41 | private ScrollableContainer mCurrentScrollableCainer;
42 |
43 | /**
44 | * a viewgroup whitch contains ScrollView/ListView/RecycelerView..
45 | */
46 | public interface ScrollableContainer{
47 | /**
48 | * @return ScrollView/ListView/RecycelerView..'s instance
49 | */
50 | View getScrollableView();
51 | }
52 |
53 | public void setCurrentScrollableContainer(ScrollableContainer scrollableContainer) {
54 | this.mCurrentScrollableCainer = scrollableContainer;
55 | }
56 |
57 | private View getScrollableView() {
58 | if (mCurrentScrollableCainer == null) {
59 | return null;
60 | }
61 | return mCurrentScrollableCainer.getScrollableView();
62 | }
63 |
64 | /**
65 | *
66 | * 判断是否滑动到顶部方法,ScrollAbleLayout根据此方法来做一些逻辑判断
67 | * 目前只实现了AdapterView,ScrollView,RecyclerView
68 | * 需要支持其他view可以自行补充实现
69 | * @return
70 | */
71 | public boolean isTop() {
72 | View scrollableView = getScrollableView();
73 | if (scrollableView == null) {
74 | // throw new NullPointerException("You should call ScrollableHelper.setCurrentScrollableContainer() to set ScrollableContainer.");
75 | return true;
76 | }
77 | if (scrollableView instanceof AdapterView) {
78 | return isAdapterViewTop((AdapterView) scrollableView);
79 | }
80 | if (scrollableView instanceof ScrollView) {
81 | return isScrollViewTop((ScrollView) scrollableView);
82 | }
83 | if (scrollableView instanceof RecyclerView) {
84 | return isRecyclerViewTop((RecyclerView) scrollableView);
85 | }
86 | if (scrollableView instanceof WebView) {
87 | return isWebViewTop((WebView) scrollableView);
88 | }
89 | throw new IllegalStateException("scrollableView must be a instance of AdapterView|ScrollView|RecyclerView");
90 | }
91 |
92 | private static boolean isRecyclerViewTop(RecyclerView recyclerView) {
93 | if (recyclerView != null) {
94 | RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
95 | if (layoutManager instanceof LinearLayoutManager) {
96 | int firstVisibleItemPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
97 | View childAt = recyclerView.getChildAt(0);
98 | if (childAt == null || (firstVisibleItemPosition == 0 &&
99 | layoutManager.getDecoratedTop(childAt) == 0)) {
100 | return true;
101 | }
102 | }
103 | }
104 | return false;
105 | }
106 |
107 | private static boolean isAdapterViewTop(AdapterView adapterView){
108 | if(adapterView != null){
109 | int firstVisiblePosition = adapterView.getFirstVisiblePosition();
110 | View childAt = adapterView.getChildAt(0);
111 | if(childAt == null || (firstVisiblePosition == 0 && childAt.getTop() == 0)){
112 | return true;
113 | }
114 | }
115 | return false;
116 | }
117 |
118 | private static boolean isScrollViewTop(ScrollView scrollView){
119 | if(scrollView != null) {
120 | int scrollViewY = scrollView.getScrollY();
121 | return scrollViewY <= 0;
122 | }
123 | return false;
124 | }
125 |
126 | private static boolean isWebViewTop(WebView scrollView){
127 | if(scrollView != null) {
128 | int scrollViewY = scrollView.getScrollY();
129 | return scrollViewY <= 0;
130 | }
131 | return false;
132 | }
133 |
134 | @SuppressLint("NewApi")
135 | public void smoothScrollBy(int velocityY, int distance, int duration) {
136 | View scrollableView = getScrollableView();
137 | if (scrollableView instanceof AbsListView) {
138 | AbsListView absListView = (AbsListView) scrollableView;
139 | if (Build.VERSION.SDK_INT >= 21) {
140 | absListView.fling(velocityY);
141 | } else {
142 | absListView.smoothScrollBy(distance, duration);
143 | }
144 | } else if (scrollableView instanceof ScrollView) {
145 | ((ScrollView) scrollableView).fling(velocityY);
146 | } else if (scrollableView instanceof RecyclerView) {
147 | ((RecyclerView) scrollableView).fling(0, velocityY);
148 | } else if (scrollableView instanceof WebView) {
149 | ((WebView) scrollableView).flingScroll(0, velocityY);
150 | }
151 | }
152 |
153 | }
154 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/PagerSlidingTabStrip.iml:
--------------------------------------------------------------------------------
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 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
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 |
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 |
--------------------------------------------------------------------------------
/scrollablelayoutlib/src/main/java/com/cpoopc/scrollablelayoutlib/ScrollableLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2015 cpoopc
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 | package com.cpoopc.scrollablelayoutlib;
25 |
26 | import android.annotation.TargetApi;
27 | import android.content.Context;
28 | import android.os.Build;
29 | import android.support.v4.view.ViewPager;
30 | import android.util.AttributeSet;
31 | import android.view.MotionEvent;
32 | import android.view.VelocityTracker;
33 | import android.view.View;
34 | import android.view.ViewConfiguration;
35 | import android.widget.LinearLayout;
36 | import android.widget.Scroller;
37 |
38 | /**
39 | * Created by cpoopc(303727604@qq.com) on 2015-02-10.
40 | */
41 | public class ScrollableLayout extends LinearLayout {
42 |
43 | private final String tag = "cp:scrollableLayout";
44 | private float mDownX;
45 | private float mDownY;
46 | private float mLastY;
47 |
48 | private int minY = 0;
49 | private int maxY = 0;
50 | private int mHeadHeight;
51 | private int mExpandHeight;
52 | private int mTouchSlop;
53 | private int mMinimumVelocity;
54 | private int mMaximumVelocity;
55 | // 方向
56 | private DIRECTION mDirection;
57 | private int mCurY;
58 | private int mLastScrollerY;
59 | private boolean needCheckUpdown;
60 | private boolean updown;
61 | private boolean mDisallowIntercept;
62 | private boolean isClickHead;
63 | private boolean isClickHeadExpand;
64 |
65 | private View mHeadView;
66 | private ViewPager childViewPager;
67 |
68 | private Scroller mScroller;
69 | private VelocityTracker mVelocityTracker;
70 |
71 | /**
72 | * 滑动方向 *
73 | */
74 | enum DIRECTION {
75 | UP,// 向上划
76 | DOWN// 向下划
77 | }
78 |
79 | public interface OnScrollListener {
80 |
81 | void onScroll(int currentY, int maxY);
82 |
83 | }
84 |
85 | private OnScrollListener onScrollListener;
86 |
87 | public void setOnScrollListener(OnScrollListener onScrollListener) {
88 | this.onScrollListener = onScrollListener;
89 | }
90 |
91 | private ScrollableHelper mHelper;
92 |
93 | public ScrollableHelper getHelper() {
94 | return mHelper;
95 | }
96 |
97 | public ScrollableLayout(Context context) {
98 | super(context);
99 | init(context);
100 | }
101 |
102 | public ScrollableLayout(Context context, AttributeSet attrs) {
103 | super(context, attrs);
104 | init(context);
105 | }
106 |
107 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
108 | public ScrollableLayout(Context context, AttributeSet attrs, int defStyleAttr) {
109 | super(context, attrs, defStyleAttr);
110 | init(context);
111 | }
112 |
113 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
114 | public ScrollableLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
115 | super(context, attrs, defStyleAttr, defStyleRes);
116 | init(context);
117 | }
118 |
119 | private void init(Context context) {
120 | mHelper = new ScrollableHelper();
121 | mScroller = new Scroller(context);
122 | final ViewConfiguration configuration = ViewConfiguration.get(context);
123 | mTouchSlop = configuration.getScaledTouchSlop();
124 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
125 | mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
126 | }
127 |
128 | public boolean isSticked() {
129 | return mCurY == maxY;
130 | }
131 |
132 | /**
133 | * 扩大头部点击滑动范围
134 | *
135 | * @param expandHeight
136 | */
137 | public void setClickHeadExpand(int expandHeight) {
138 | mExpandHeight = expandHeight;
139 | }
140 |
141 | public int getMaxY() {
142 | return maxY;
143 | }
144 |
145 | public boolean isHeadTop() {
146 | return mCurY == minY;
147 | }
148 |
149 | public boolean canPtr() {
150 | return updown && mCurY == minY && mHelper.isTop();
151 | }
152 |
153 | public void requestScrollableLayoutDisallowInterceptTouchEvent(boolean disallowIntercept) {
154 | super.requestDisallowInterceptTouchEvent(disallowIntercept);
155 | mDisallowIntercept = disallowIntercept;
156 | }
157 |
158 | @Override
159 | public boolean dispatchTouchEvent(MotionEvent ev) {
160 | float currentX = ev.getX();
161 | float currentY = ev.getY();
162 | float deltaY;
163 | int shiftX = (int) Math.abs(currentX - mDownX);
164 | int shiftY = (int) Math.abs(currentY - mDownY);
165 | switch (ev.getAction()) {
166 | case MotionEvent.ACTION_DOWN:
167 | mDisallowIntercept = false;
168 | needCheckUpdown = true;
169 | updown = true;
170 | mDownX = currentX;
171 | mDownY = currentY;
172 | mLastY = currentY;
173 | checkIsClickHead((int) currentY, mHeadHeight, getScrollY());
174 | checkIsClickHeadExpand((int) currentY, mHeadHeight, getScrollY());
175 | initOrResetVelocityTracker();
176 | mVelocityTracker.addMovement(ev);
177 | mScroller.forceFinished(true);
178 | break;
179 | case MotionEvent.ACTION_MOVE:
180 | if (mDisallowIntercept) {
181 | break;
182 | }
183 | initVelocityTrackerIfNotExists();
184 | mVelocityTracker.addMovement(ev);
185 | deltaY = mLastY - currentY;
186 | if (needCheckUpdown) {
187 | if (shiftX > mTouchSlop && shiftX > shiftY) {
188 | needCheckUpdown = false;
189 | updown = false;
190 | } else if (shiftY > mTouchSlop && shiftY > shiftX) {
191 | needCheckUpdown = false;
192 | updown = true;
193 | }
194 | }
195 |
196 | if (updown && shiftY > mTouchSlop && shiftY > shiftX &&
197 | (!isSticked() || mHelper.isTop() || isClickHeadExpand)) {
198 |
199 | if (childViewPager != null) {
200 | childViewPager.requestDisallowInterceptTouchEvent(true);
201 | }
202 | scrollBy(0, (int) (deltaY + 0.5));
203 | }
204 | mLastY = currentY;
205 | break;
206 | case MotionEvent.ACTION_UP:
207 | if (updown && shiftY > shiftX && shiftY > mTouchSlop) {
208 | mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
209 | float yVelocity = -mVelocityTracker.getYVelocity();
210 | boolean dislowChild = false;
211 | if (Math.abs(yVelocity) > mMinimumVelocity) {
212 | mDirection = yVelocity > 0 ? DIRECTION.UP : DIRECTION.DOWN;
213 | if ((mDirection == DIRECTION.UP && isSticked()) || (!isSticked() && getScrollY() == 0 && mDirection == DIRECTION.DOWN)) {
214 | dislowChild = true;
215 | } else {
216 | mScroller.fling(0, getScrollY(), 0, (int) yVelocity, 0, 0, -Integer.MAX_VALUE, Integer.MAX_VALUE);
217 | mScroller.computeScrollOffset();
218 | mLastScrollerY = getScrollY();
219 | invalidate();
220 | }
221 | }
222 | if (!dislowChild && (isClickHead || !isSticked())) {
223 | int action = ev.getAction();
224 | ev.setAction(MotionEvent.ACTION_CANCEL);
225 | boolean dispathResult = super.dispatchTouchEvent(ev);
226 | ev.setAction(action);
227 | return dispathResult;
228 | }
229 | }
230 | break;
231 | default:
232 | break;
233 | }
234 | super.dispatchTouchEvent(ev);
235 | return true;
236 | }
237 |
238 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
239 | private int getScrollerVelocity(int distance, int duration) {
240 | if (mScroller == null) {
241 | return 0;
242 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
243 | return (int) mScroller.getCurrVelocity();
244 | } else {
245 | return distance / duration;
246 | }
247 | }
248 |
249 | @Override
250 | public void computeScroll() {
251 | if (mScroller.computeScrollOffset()) {
252 | final int currY = mScroller.getCurrY();
253 | if (mDirection == DIRECTION.UP) {
254 | // 手势向上划
255 | if (isSticked()) {
256 | int distance = mScroller.getFinalY() - currY;
257 | int duration = calcDuration(mScroller.getDuration(), mScroller.timePassed());
258 | mHelper.smoothScrollBy(getScrollerVelocity(distance, duration), distance, duration);
259 | mScroller.forceFinished(true);
260 | return;
261 | } else {
262 | scrollTo(0, currY);
263 | }
264 | } else {
265 | // 手势向下划
266 | if (mHelper.isTop() || isClickHeadExpand) {
267 | int deltaY = (currY - mLastScrollerY);
268 | int toY = getScrollY() + deltaY;
269 | scrollTo(0, toY);
270 | if (mCurY <= minY) {
271 | mScroller.forceFinished(true);
272 | return;
273 | }
274 | }
275 | invalidate();
276 | }
277 | mLastScrollerY = currY;
278 | }
279 | }
280 |
281 | @Override
282 | public void scrollBy(int x, int y) {
283 | int scrollY = getScrollY();
284 | int toY = scrollY + y;
285 | if (toY >= maxY) {
286 | toY = maxY;
287 | } else if (toY <= minY) {
288 | toY = minY;
289 | }
290 | y = toY - scrollY;
291 | super.scrollBy(x, y);
292 | }
293 |
294 | @Override
295 | public void scrollTo(int x, int y) {
296 | if (y >= maxY) {
297 | y = maxY;
298 | } else if (y <= minY) {
299 | y = minY;
300 | }
301 | mCurY = y;
302 | if (onScrollListener != null) {
303 | onScrollListener.onScroll(y, maxY);
304 | }
305 | super.scrollTo(x, y);
306 | }
307 |
308 | private void initOrResetVelocityTracker() {
309 | if (mVelocityTracker == null) {
310 | mVelocityTracker = VelocityTracker.obtain();
311 | } else {
312 | mVelocityTracker.clear();
313 | }
314 | }
315 |
316 | private void initVelocityTrackerIfNotExists() {
317 | if (mVelocityTracker == null) {
318 | mVelocityTracker = VelocityTracker.obtain();
319 | }
320 | }
321 |
322 | private void recycleVelocityTracker() {
323 | if (mVelocityTracker != null) {
324 | mVelocityTracker.recycle();
325 | mVelocityTracker = null;
326 | }
327 | }
328 |
329 | private void checkIsClickHead(int downY, int headHeight, int scrollY) {
330 | isClickHead = downY + scrollY <= headHeight;
331 | }
332 |
333 | private void checkIsClickHeadExpand(int downY, int headHeight, int scrollY) {
334 | if (mExpandHeight <= 0) {
335 | isClickHeadExpand = false;
336 | }
337 | isClickHeadExpand = downY + scrollY <= headHeight + mExpandHeight;
338 | }
339 |
340 | private int calcDuration(int duration, int timepass) {
341 | return duration - timepass;
342 | }
343 |
344 | @Override
345 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
346 | mHeadView = getChildAt(0);
347 | measureChildWithMargins(mHeadView, widthMeasureSpec, 0, MeasureSpec.UNSPECIFIED, 0);
348 | maxY = mHeadView.getMeasuredHeight();
349 | mHeadHeight = mHeadView.getMeasuredHeight();
350 | super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) + maxY, MeasureSpec.EXACTLY));
351 | }
352 |
353 | @Override
354 | protected void onFinishInflate() {
355 | if (mHeadView != null && !mHeadView.isClickable()) {
356 | mHeadView.setClickable(true);
357 | }
358 | int childCount = getChildCount();
359 | for (int i = 0; i < childCount; i++) {
360 | View childAt = getChildAt(i);
361 | if (childAt != null && childAt instanceof ViewPager) {
362 | childViewPager = (ViewPager) childAt;
363 | }
364 | }
365 | super.onFinishInflate();
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/PagerSlidingTabStrip/src/com/astuetz/PagerSlidingTabStrip.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Andreas Stuetz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.astuetz;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.content.Context;
21 | import android.content.res.TypedArray;
22 | import android.graphics.Canvas;
23 | import android.graphics.Paint;
24 | import android.graphics.Paint.Style;
25 | import android.graphics.Typeface;
26 | import android.os.Build;
27 | import android.os.Parcel;
28 | import android.os.Parcelable;
29 | import android.support.v4.view.ViewPager;
30 | import android.support.v4.view.ViewPager.OnPageChangeListener;
31 | import android.util.AttributeSet;
32 | import android.util.DisplayMetrics;
33 | import android.util.TypedValue;
34 | import android.view.Gravity;
35 | import android.view.View;
36 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
37 | import android.widget.HorizontalScrollView;
38 | import android.widget.ImageButton;
39 | import android.widget.LinearLayout;
40 | import android.widget.TextView;
41 |
42 | import java.util.Locale;
43 |
44 | import com.astuetz.pagerslidingtabstrip.R;
45 |
46 | public class PagerSlidingTabStrip extends HorizontalScrollView {
47 |
48 | public interface IconTabProvider {
49 | public int getPageIconResId(int position);
50 | }
51 |
52 | // @formatter:off
53 | private static final int[] ATTRS = new int[] {
54 | android.R.attr.textSize,
55 | android.R.attr.textColor
56 | };
57 | // @formatter:on
58 |
59 | private LinearLayout.LayoutParams defaultTabLayoutParams;
60 | private LinearLayout.LayoutParams expandedTabLayoutParams;
61 |
62 | private final PageListener pageListener = new PageListener();
63 | public OnPageChangeListener delegatePageListener;
64 |
65 | private LinearLayout tabsContainer;
66 | private ViewPager pager;
67 |
68 | private int tabCount;
69 |
70 | private int currentPosition = 0;
71 | private float currentPositionOffset = 0f;
72 |
73 | private Paint rectPaint;
74 | private Paint dividerPaint;
75 |
76 | private int indicatorColor = 0xFF666666;
77 | private int underlineColor = 0x1A000000;
78 | private int dividerColor = 0x1A000000;
79 |
80 | private boolean shouldExpand = false;
81 | private boolean textAllCaps = true;
82 |
83 | private int scrollOffset = 52;
84 | private int indicatorHeight = 8;
85 | private int underlineHeight = 2;
86 | private int dividerPadding = 12;
87 | private int tabPadding = 24;
88 | private int dividerWidth = 1;
89 |
90 | private int tabTextSize = 12;
91 | private int tabTextColor = 0xFF666666;
92 | private Typeface tabTypeface = null;
93 | private int tabTypefaceStyle = Typeface.BOLD;
94 |
95 | private int lastScrollX = 0;
96 |
97 | private int tabBackgroundResId = R.drawable.background_tab;
98 |
99 | private Locale locale;
100 |
101 | public PagerSlidingTabStrip(Context context) {
102 | this(context, null);
103 | }
104 |
105 | public PagerSlidingTabStrip(Context context, AttributeSet attrs) {
106 | this(context, attrs, 0);
107 | }
108 |
109 | public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) {
110 | super(context, attrs, defStyle);
111 |
112 | setFillViewport(true);
113 | setWillNotDraw(false);
114 |
115 | tabsContainer = new LinearLayout(context);
116 | tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
117 | tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
118 | addView(tabsContainer);
119 |
120 | DisplayMetrics dm = getResources().getDisplayMetrics();
121 |
122 | scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm);
123 | indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm);
124 | underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm);
125 | dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm);
126 | tabPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm);
127 | dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm);
128 | tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm);
129 |
130 | // get system attrs (android:textSize and android:textColor)
131 |
132 | TypedArray a = context.obtainStyledAttributes(attrs, ATTRS);
133 |
134 | tabTextSize = a.getDimensionPixelSize(0, tabTextSize);
135 | tabTextColor = a.getColor(1, tabTextColor);
136 |
137 | a.recycle();
138 |
139 | // get custom attrs
140 |
141 | a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip);
142 |
143 | indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor);
144 | underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor);
145 | dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor);
146 | indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight);
147 | underlineHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsUnderlineHeight, underlineHeight);
148 | dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding);
149 | tabPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, tabPadding);
150 | tabBackgroundResId = a.getResourceId(R.styleable.PagerSlidingTabStrip_pstsTabBackground, tabBackgroundResId);
151 | shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand);
152 | scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset);
153 | textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps);
154 |
155 | a.recycle();
156 |
157 | rectPaint = new Paint();
158 | rectPaint.setAntiAlias(true);
159 | rectPaint.setStyle(Style.FILL);
160 |
161 | dividerPaint = new Paint();
162 | dividerPaint.setAntiAlias(true);
163 | dividerPaint.setStrokeWidth(dividerWidth);
164 |
165 | defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
166 | expandedTabLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f);
167 |
168 | if (locale == null) {
169 | locale = getResources().getConfiguration().locale;
170 | }
171 | }
172 |
173 | public void setViewPager(ViewPager pager) {
174 | this.pager = pager;
175 |
176 | if (pager.getAdapter() == null) {
177 | throw new IllegalStateException("ViewPager does not have adapter instance.");
178 | }
179 |
180 | pager.setOnPageChangeListener(pageListener);
181 |
182 | notifyDataSetChanged();
183 | }
184 |
185 | public void setOnPageChangeListener(OnPageChangeListener listener) {
186 | this.delegatePageListener = listener;
187 | }
188 |
189 | public void notifyDataSetChanged() {
190 |
191 | tabsContainer.removeAllViews();
192 |
193 | tabCount = pager.getAdapter().getCount();
194 |
195 | for (int i = 0; i < tabCount; i++) {
196 |
197 | if (pager.getAdapter() instanceof IconTabProvider) {
198 | addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i));
199 | } else {
200 | addTextTab(i, pager.getAdapter().getPageTitle(i).toString());
201 | }
202 |
203 | }
204 |
205 | updateTabStyles();
206 |
207 | getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
208 |
209 | @SuppressWarnings("deprecation")
210 | @SuppressLint("NewApi")
211 | @Override
212 | public void onGlobalLayout() {
213 |
214 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
215 | getViewTreeObserver().removeGlobalOnLayoutListener(this);
216 | } else {
217 | getViewTreeObserver().removeOnGlobalLayoutListener(this);
218 | }
219 |
220 | currentPosition = pager.getCurrentItem();
221 | scrollToChild(currentPosition, 0);
222 | }
223 | });
224 |
225 | }
226 |
227 | private void addTextTab(final int position, String title) {
228 |
229 | TextView tab = new TextView(getContext());
230 | tab.setText(title);
231 | tab.setGravity(Gravity.CENTER);
232 | tab.setSingleLine();
233 |
234 | addTab(position, tab);
235 | }
236 |
237 | private void addIconTab(final int position, int resId) {
238 |
239 | ImageButton tab = new ImageButton(getContext());
240 | tab.setImageResource(resId);
241 |
242 | addTab(position, tab);
243 |
244 | }
245 |
246 | private void addTab(final int position, View tab) {
247 | tab.setFocusable(true);
248 | tab.setOnClickListener(new OnClickListener() {
249 | @Override
250 | public void onClick(View v) {
251 | pager.setCurrentItem(position);
252 | }
253 | });
254 |
255 | tab.setPadding(tabPadding, 0, tabPadding, 0);
256 | tabsContainer.addView(tab, position, shouldExpand ? expandedTabLayoutParams : defaultTabLayoutParams);
257 | }
258 |
259 | private void updateTabStyles() {
260 |
261 | for (int i = 0; i < tabCount; i++) {
262 |
263 | View v = tabsContainer.getChildAt(i);
264 |
265 | v.setBackgroundResource(tabBackgroundResId);
266 |
267 | if (v instanceof TextView) {
268 |
269 | TextView tab = (TextView) v;
270 | tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize);
271 | tab.setTypeface(tabTypeface, tabTypefaceStyle);
272 | tab.setTextColor(tabTextColor);
273 |
274 | // setAllCaps() is only available from API 14, so the upper case is made manually if we are on a
275 | // pre-ICS-build
276 | if (textAllCaps) {
277 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
278 | tab.setAllCaps(true);
279 | } else {
280 | tab.setText(tab.getText().toString().toUpperCase(locale));
281 | }
282 | }
283 | }
284 | }
285 |
286 | }
287 |
288 | private void scrollToChild(int position, int offset) {
289 |
290 | if (tabCount == 0) {
291 | return;
292 | }
293 |
294 | int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;
295 |
296 | if (position > 0 || offset > 0) {
297 | newScrollX -= scrollOffset;
298 | }
299 |
300 | if (newScrollX != lastScrollX) {
301 | lastScrollX = newScrollX;
302 | scrollTo(newScrollX, 0);
303 | }
304 |
305 | }
306 |
307 | @Override
308 | protected void onDraw(Canvas canvas) {
309 | super.onDraw(canvas);
310 |
311 | if (isInEditMode() || tabCount == 0) {
312 | return;
313 | }
314 |
315 | final int height = getHeight();
316 |
317 | // draw indicator line
318 |
319 | rectPaint.setColor(indicatorColor);
320 |
321 | // default: line below current tab
322 | View currentTab = tabsContainer.getChildAt(currentPosition);
323 | float lineLeft = currentTab.getLeft();
324 | float lineRight = currentTab.getRight();
325 |
326 | // if there is an offset, start interpolating left and right coordinates between current and next tab
327 | if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
328 |
329 | View nextTab = tabsContainer.getChildAt(currentPosition + 1);
330 | final float nextTabLeft = nextTab.getLeft();
331 | final float nextTabRight = nextTab.getRight();
332 |
333 | lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
334 | lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
335 | }
336 |
337 | canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);
338 |
339 | // draw underline
340 |
341 | rectPaint.setColor(underlineColor);
342 | canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);
343 |
344 | // draw divider
345 |
346 | dividerPaint.setColor(dividerColor);
347 | for (int i = 0; i < tabCount - 1; i++) {
348 | View tab = tabsContainer.getChildAt(i);
349 | canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
350 | }
351 | }
352 |
353 | private class PageListener implements OnPageChangeListener {
354 |
355 | @Override
356 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
357 |
358 | currentPosition = position;
359 | currentPositionOffset = positionOffset;
360 |
361 | scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
362 |
363 | invalidate();
364 |
365 | if (delegatePageListener != null) {
366 | delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
367 | }
368 | }
369 |
370 | @Override
371 | public void onPageScrollStateChanged(int state) {
372 | if (state == ViewPager.SCROLL_STATE_IDLE) {
373 | scrollToChild(pager.getCurrentItem(), 0);
374 | }
375 |
376 | if (delegatePageListener != null) {
377 | delegatePageListener.onPageScrollStateChanged(state);
378 | }
379 | }
380 |
381 | @Override
382 | public void onPageSelected(int position) {
383 | if (delegatePageListener != null) {
384 | delegatePageListener.onPageSelected(position);
385 | }
386 | }
387 |
388 | }
389 |
390 | public void setIndicatorColor(int indicatorColor) {
391 | this.indicatorColor = indicatorColor;
392 | invalidate();
393 | }
394 |
395 | public void setIndicatorColorResource(int resId) {
396 | this.indicatorColor = getResources().getColor(resId);
397 | invalidate();
398 | }
399 |
400 | public int getIndicatorColor() {
401 | return this.indicatorColor;
402 | }
403 |
404 | public void setIndicatorHeight(int indicatorLineHeightPx) {
405 | this.indicatorHeight = indicatorLineHeightPx;
406 | invalidate();
407 | }
408 |
409 | public int getIndicatorHeight() {
410 | return indicatorHeight;
411 | }
412 |
413 | public void setUnderlineColor(int underlineColor) {
414 | this.underlineColor = underlineColor;
415 | invalidate();
416 | }
417 |
418 | public void setUnderlineColorResource(int resId) {
419 | this.underlineColor = getResources().getColor(resId);
420 | invalidate();
421 | }
422 |
423 | public int getUnderlineColor() {
424 | return underlineColor;
425 | }
426 |
427 | public void setDividerColor(int dividerColor) {
428 | this.dividerColor = dividerColor;
429 | invalidate();
430 | }
431 |
432 | public void setDividerColorResource(int resId) {
433 | this.dividerColor = getResources().getColor(resId);
434 | invalidate();
435 | }
436 |
437 | public int getDividerColor() {
438 | return dividerColor;
439 | }
440 |
441 | public void setUnderlineHeight(int underlineHeightPx) {
442 | this.underlineHeight = underlineHeightPx;
443 | invalidate();
444 | }
445 |
446 | public int getUnderlineHeight() {
447 | return underlineHeight;
448 | }
449 |
450 | public void setDividerPadding(int dividerPaddingPx) {
451 | this.dividerPadding = dividerPaddingPx;
452 | invalidate();
453 | }
454 |
455 | public int getDividerPadding() {
456 | return dividerPadding;
457 | }
458 |
459 | public void setScrollOffset(int scrollOffsetPx) {
460 | this.scrollOffset = scrollOffsetPx;
461 | invalidate();
462 | }
463 |
464 | public int getScrollOffset() {
465 | return scrollOffset;
466 | }
467 |
468 | public void setShouldExpand(boolean shouldExpand) {
469 | this.shouldExpand = shouldExpand;
470 | requestLayout();
471 | }
472 |
473 | public boolean getShouldExpand() {
474 | return shouldExpand;
475 | }
476 |
477 | public boolean isTextAllCaps() {
478 | return textAllCaps;
479 | }
480 |
481 | public void setAllCaps(boolean textAllCaps) {
482 | this.textAllCaps = textAllCaps;
483 | }
484 |
485 | public void setTextSize(int textSizePx) {
486 | this.tabTextSize = textSizePx;
487 | updateTabStyles();
488 | }
489 |
490 | public int getTextSize() {
491 | return tabTextSize;
492 | }
493 |
494 | public void setTextColor(int textColor) {
495 | this.tabTextColor = textColor;
496 | updateTabStyles();
497 | }
498 |
499 | public void setTextColorResource(int resId) {
500 | this.tabTextColor = getResources().getColor(resId);
501 | updateTabStyles();
502 | }
503 |
504 | public int getTextColor() {
505 | return tabTextColor;
506 | }
507 |
508 | public void setTypeface(Typeface typeface, int style) {
509 | this.tabTypeface = typeface;
510 | this.tabTypefaceStyle = style;
511 | updateTabStyles();
512 | }
513 |
514 | public void setTabBackground(int resId) {
515 | this.tabBackgroundResId = resId;
516 | }
517 |
518 | public int getTabBackground() {
519 | return tabBackgroundResId;
520 | }
521 |
522 | public void setTabPaddingLeftRight(int paddingPx) {
523 | this.tabPadding = paddingPx;
524 | updateTabStyles();
525 | }
526 |
527 | public int getTabPaddingLeftRight() {
528 | return tabPadding;
529 | }
530 |
531 | @Override
532 | public void onRestoreInstanceState(Parcelable state) {
533 | SavedState savedState = (SavedState) state;
534 | super.onRestoreInstanceState(savedState.getSuperState());
535 | currentPosition = savedState.currentPosition;
536 | requestLayout();
537 | }
538 |
539 | @Override
540 | public Parcelable onSaveInstanceState() {
541 | Parcelable superState = super.onSaveInstanceState();
542 | SavedState savedState = new SavedState(superState);
543 | savedState.currentPosition = currentPosition;
544 | return savedState;
545 | }
546 |
547 | static class SavedState extends BaseSavedState {
548 | int currentPosition;
549 |
550 | public SavedState(Parcelable superState) {
551 | super(superState);
552 | }
553 |
554 | private SavedState(Parcel in) {
555 | super(in);
556 | currentPosition = in.readInt();
557 | }
558 |
559 | @Override
560 | public void writeToParcel(Parcel dest, int flags) {
561 | super.writeToParcel(dest, flags);
562 | dest.writeInt(currentPosition);
563 | }
564 |
565 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
566 | @Override
567 | public SavedState createFromParcel(Parcel in) {
568 | return new SavedState(in);
569 | }
570 |
571 | @Override
572 | public SavedState[] newArray(int size) {
573 | return new SavedState[size];
574 | }
575 | };
576 | }
577 |
578 | }
579 |
--------------------------------------------------------------------------------