diff --git a/README.md b/README.md index 3b7ea059b7c1c64656960b41948f4924aa315bf6..92319a67580b75c6036ec72fb4a21d954b59c77c 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,78 @@ -##Description +# VerticalViewPager -Small library allowing you to have a VerticalViewPager. It's just a copy paste from the v19 ViewPager available in the support lib, where I changed all the left/right into top/bottom and X into Y. +**本项目基于开源项目VerticalViewPager进行鸿蒙化的移植和开发,可以通过项目标签以及github地址(https://github.com/castorflex/VerticalViewPager)追踪到原安卓项目版本** -Nothing complicated here, but you can gain some time avoiding rewriting it. +#### 项目介绍 -##Integration +- 项目名称:垂直滑动ViewPager +- 所属系列:鸿蒙的第三方组件适配移植 +- 功能:实现ViewPager垂直方向页面滑动,实现滚动页面缩放效果。 +- 项目移植状态:主功能完成 +- 调用差异:无 +- 开发版本:sdk5,DevEco Studio2.1 beta3 +- 项目作者和维护人:佘涛涛 +- 联系方式:shetaotao050@chinasoftinc.com +- 原项目Doc地址:https://github.com/castorflex/VerticalViewPager -The lib will be available soon on Maven Central. All you have to do is add it on your gradle build: +#### 效果演示 -```xml -dependencies { - compile 'com.github.castorflex.verticalviewpager:library:19.0.1' -} -``` + + +#### 安装教程 + +1.下载library的har包library.har(位于:)。 + +2.启动 DevEco Studio,将下载的har包,导入工程目录“demo->libs”下。 + +3.在moudle级别下的build.gradle文件中添加依赖,在dependencies标签中增加对libs目录下jar包的引用。 + + ``` + dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + ...... + } + ``` + +在sdk5,DevEco Studio2.1 beta3下项目可直接运行 +如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, +并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下 + +#### 使用说明 -##Note +1、将VerticalViewPager添加到指定xml -`PageAdapter#getPageWidth()` is used as a `getPageHeight()` in the lib. +``` + +``` -##License +2、获取VerticalViewPager组件,将PageSliderProvider对象设置给VerticalViewPager,设置页面滑动缩放效果,设置垂直滑动。 ``` -"THE BEER-WARE LICENSE" (Revision 42): -You can do whatever you want with this stuff. -If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. +VerticalViewPager verticalViewPager = (VerticalViewPager) findComponentById(ResourceTable.Id_page_slider); +verticalViewPager.setProvider(PageSliderProvider); +verticalViewPager.setPageTransformer(new TransformerItem(ZoomOutSlideTransformer.class).getPageTransformer()); +verticalViewPager.setOrientation(Component.VERTICAL); ``` -####Badges +#### 测试信息 + +CodeCheck代码测试无异常 + +CloudTest代码测试无异常 + +火绒安全病毒安全检测通过 + +当前版本demo功能与安卓原组件基本无差异 + +测试员:常小俊 + +#### 版本迭代 -[![Analytics](https://ga-beacon.appspot.com/UA-32954204-2/VerticalViewPager/readme)](https://github.com/igrigorik/ga-beacon) +- v0.0.1_alpha -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/castorflex/verticalviewpager/trend.png)](https://bitdeli.com/free "Bitdeli Badge") +#### 版权和许可信息 +​ diff --git a/build.gradle b/build.gradle index afc9df542ebdb1eb228482d6fbc11d817c43bca1..4480028e116977980cfc89c451d2b1822d717a66 100755 --- a/build.gradle +++ b/build.gradle @@ -1,20 +1,36 @@ +apply plugin: 'com.huawei.ohos.app' + +ohos { + compileSdkVersion 5 + defaultConfig { + compatibleSdkVersion 4 + } +} + buildscript { repositories { - mavenCentral() + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:0.7.+' + classpath 'com.huawei.ohos:hap:2.4.2.7' + classpath 'com.huawei.ohos:decctest:1.0.0.6' } } allprojects { - version = VERSION_NAME - group = GROUP - repositories { - mavenCentral() + maven { + url 'https://repo.huaweicloud.com/repository/maven/' + } + maven { + url 'https://developer.huawei.com/repo/' + } + jcenter() } } - - -apply plugin: 'android-reporting' \ No newline at end of file diff --git a/changeLog.md b/changeLog.md new file mode 100644 index 0000000000000000000000000000000000000000..1f03f5669f6cbd1b917942e50ad316cc3acc57a6 --- /dev/null +++ b/changeLog.md @@ -0,0 +1,13 @@ +# 基本功能: + +实现ViewPager垂直方向页面滑动,实现滚动页面缩放效果; + + +# 修改点: +1. 暂无 + +# 遗留问题(暂不支持的功能): +1. 暂无 + + + diff --git a/entry/.gitignore b/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9 --- /dev/null +++ b/entry/.gitignore @@ -0,0 +1 @@ +/build diff --git a/entry/build.gradle b/entry/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..13684fa326833176a7f709a738a2fd56d6fab1ca --- /dev/null +++ b/entry/build.gradle @@ -0,0 +1,23 @@ +apply plugin: 'com.huawei.ohos.hap' +ohos { + compileSdkVersion 5 + defaultConfig { + compatibleSdkVersion 4 + } + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + implementation project(path: ':Library') + testImplementation 'junit:junit:4.13' + ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.100' +} diff --git a/entry/proguard-rules.pro b/entry/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..f7666e47561d514b2a76d5a7dfbb43ede86da92a --- /dev/null +++ b/entry/proguard-rules.pro @@ -0,0 +1 @@ +# config module specific ProGuard rules here. \ No newline at end of file diff --git a/entry/src/main/config.json b/entry/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..52d1004fd8cdce8dce6364dd5632c734f88eb018 --- /dev/null +++ b/entry/src/main/config.json @@ -0,0 +1,58 @@ +{ + "app": { + "bundleName": "fr.castorflex.android.verticalviewpager", + "vendor": "castorflex", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5, + "releaseType": "Beta1" + } + }, + "deviceConfig": {}, + "module": { + "package": "fr.castorflex.android.verticalviewpager.sample", + "name": ".MyApplication", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "entry", + "moduleType": "entry" + }, + "abilities": [ + { + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ], + "orientation": "unspecified", + "name": "fr.castorflex.android.verticalviewpager.sample.MainAbility", + "icon": "$media:icon", + "description": "$string:mainability_description", + "label": "$string:app_name", + "type": "page", + "launchType": "standard", + "metaData": { + "customizeData": [ + { + "extra": "", + "name": "hwc-theme", + "value": "androidhwext:style/Theme.Emui.NoTitleBar" + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainAbility.java b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainAbility.java new file mode 100644 index 0000000000000000000000000000000000000000..37a68c74fe7d29a848e4630f075038bea70e118b --- /dev/null +++ b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainAbility.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.sample; + +import fr.castorflex.android.verticalviewpager.sample.slice.MainAbilitySlice; +import ohos.aafwk.ability.Ability; +import ohos.aafwk.content.Intent; + +/** + * Main ability + * + * @author shetaotao + * @since 2021-04-25 + */ +public class MainAbility extends Ability { + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setMainRoute(MainAbilitySlice.class.getName()); + } +} diff --git a/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MyApplication.java b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MyApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..11b54cfa11603a20f87a81228141c81b7f79a7a4 --- /dev/null +++ b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/MyApplication.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.sample; + +import ohos.aafwk.ability.AbilityPackage; + +/** + * Main ability package + * + * @author shetaotao + * @since 2021-04-25 + */ +public class MyApplication extends AbilityPackage { + @Override + public void onInitialize() { + super.onInitialize(); + } +} diff --git a/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/PagerProvider.java b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/PagerProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..57f1fb836a4a2ed8163acfb713a296a1e1b54ffa --- /dev/null +++ b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/PagerProvider.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.sample; + +import ohos.agp.components.Component; +import ohos.agp.components.ComponentContainer; +import ohos.agp.components.PageSliderProvider; +import ohos.agp.components.Text; + +import java.util.ArrayList; +import java.util.List; + +/** + * 数据源,每个页面对应list中的一项 + * + * @author name + * @since 2021-04-21 + */ +public class PagerProvider extends PageSliderProvider { + private ArrayList mComponents = new ArrayList<>(); + private ArrayList mPageViewList; + + /** + * 创建PageSlide适配器 + * + * @param pageViewList 页面对应list + */ + public PagerProvider(ArrayList pageViewList) { + this.mPageViewList = pageViewList; + } + + @Override + public int getCount() { + return mPageViewList.size(); + } + + /** + * 获取Child 没有 + * + * @param componentContainer componentContainer + * @param index index + * @return Object + */ + @Override + public Object createPageInContainer(ComponentContainer componentContainer, int index) { + Component component = mPageViewList.get(index); + Text label = (Text) component.findComponentById(ResourceTable.Id_textview); + componentContainer.addComponent(component); + mComponents.add(index, label); + return label; + } + + @Override + public void destroyPageFromContainer(ComponentContainer componentContainer, int index, Object object) { + componentContainer.removeComponent((Component) object); + } + + @Override + public boolean isPageMatchToObject(Component component, Object object) { + return component == object; + } + + /** + * Get components + * + * @return Components + */ + public List getComponents() { + return mComponents; + } +} diff --git a/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/slice/MainAbilitySlice.java b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/slice/MainAbilitySlice.java new file mode 100644 index 0000000000000000000000000000000000000000..54e09f09dccb054e6cb933a71f4e64c711778a59 --- /dev/null +++ b/entry/src/main/java/fr/castorflex/android/verticalviewpager/sample/slice/MainAbilitySlice.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.sample.slice; + +import fr.castorflex.android.verticalviewpager.VerticalViewPager; +import fr.castorflex.android.verticalviewpager.sample.PagerProvider; +import fr.castorflex.android.verticalviewpager.sample.ResourceTable; +import fr.castorflex.android.verticalviewpager.transformer.TransformerItem; +import fr.castorflex.android.verticalviewpager.transformer.ZoomOutSlideTransformer; +import ohos.aafwk.ability.AbilitySlice; +import ohos.aafwk.content.Intent; +import ohos.agp.components.Component; +import ohos.agp.components.LayoutScatter; +import ohos.agp.components.StackLayout; +import ohos.agp.utils.Color; + +import java.util.ArrayList; + +/** + * Main ability slice + * + * @author shetaotao + * @since 2021-04-25 + */ +public class MainAbilitySlice extends AbilitySlice { + private VerticalViewPager mPageSlider; + + @Override + public void onStart(Intent intent) { + super.onStart(intent); + super.setUIContent(ResourceTable.Layout_ability_main); + getWindow().setStatusBarColor(Color.BLUE.getValue()); + initPages(); + } + + private void initPages() { + ArrayList pageView = getPageView(); + mPageSlider = (VerticalViewPager) findComponentById(ResourceTable.Id_page_slider); + PagerProvider pageProvider = new PagerProvider(pageView); + mPageSlider.setProvider(pageProvider); + mPageSlider.setPages(pageProvider.getComponents()); + mPageSlider.setPageTransformer(new TransformerItem(ZoomOutSlideTransformer.class).getPageTransformer()); + mPageSlider.setOrientation(Component.VERTICAL); + } + + private ArrayList getPageView() { + LayoutScatter layoutScatter = LayoutScatter.getInstance(getContext()); + StackLayout layoutOne = + (StackLayout) layoutScatter.parse(ResourceTable.Layout_fragment, null, false); + StackLayout layoutTwo = + (StackLayout) layoutScatter.parse(ResourceTable.Layout_fragment2, null, false); + StackLayout layoutThree = + (StackLayout) layoutScatter.parse(ResourceTable.Layout_fragment3, null, false); + + ArrayList pageView = new ArrayList(); + pageView.add(layoutOne); + pageView.add(layoutTwo); + pageView.add(layoutThree); + return pageView; + } +} diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..bc410e6b480b8e9c5318d2efd574f4207492842a --- /dev/null +++ b/entry/src/main/resources/base/element/color.json @@ -0,0 +1,24 @@ +{ + "color": [ + { + "name": "black", + "value": "#000000" + }, + { + "name": "white", + "value": "#FFFFFF" + }, + { + "name": "holo_orange_dark", + "value": "#FF8800" + }, + { + "name": "black_lit", + "value": "#444444" + }, + { + "name": "holo_green_dark", + "value": "#669900" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..1690ad9104c40c7dcebe9c272b7380e33e6ffede --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "app_name", + "value": "VerticalViewPager" + }, + { + "name": "mainability_description", + "value": "Java_Phone_Empty Feature Ability" + }, + { + "name": "HelloWorld", + "value": "Hello World" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/graphic/background_ability_main.xml b/entry/src/main/resources/base/graphic/background_ability_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..c0c0a3df480fa387a452b9c40ca191cc918a3fc0 --- /dev/null +++ b/entry/src/main/resources/base/graphic/background_ability_main.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/layout/ability_main.xml b/entry/src/main/resources/base/layout/ability_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..883dfeb9c61fb2eb7774058a4d4bd54e7b61a56a --- /dev/null +++ b/entry/src/main/resources/base/layout/ability_main.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/layout/fragment.xml b/entry/src/main/resources/base/layout/fragment.xml new file mode 100644 index 0000000000000000000000000000000000000000..b5db6916ab5e6c6c81084762decc119799c38a0c --- /dev/null +++ b/entry/src/main/resources/base/layout/fragment.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/layout/fragment2.xml b/entry/src/main/resources/base/layout/fragment2.xml new file mode 100644 index 0000000000000000000000000000000000000000..8bcef89e8d02ae954b9acb2fcd8b6ec9bdd7dfde --- /dev/null +++ b/entry/src/main/resources/base/layout/fragment2.xml @@ -0,0 +1,30 @@ + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/layout/fragment3.xml b/entry/src/main/resources/base/layout/fragment3.xml new file mode 100644 index 0000000000000000000000000000000000000000..3357302a8ef7aca888cce072424b7e2e6b2e5440 --- /dev/null +++ b/entry/src/main/resources/base/layout/fragment3.xml @@ -0,0 +1,31 @@ + + + + + + + + + \ No newline at end of file diff --git a/entry/src/main/resources/base/media/icon.png b/entry/src/main/resources/base/media/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c Binary files /dev/null and b/entry/src/main/resources/base/media/icon.png differ diff --git a/gif/verticalviewpager_demo.gif b/gif/verticalviewpager_demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..56d36f2dd9c376b5712c4fce999c8a03de069d81 Binary files /dev/null and b/gif/verticalviewpager_demo.gif differ diff --git a/gradle.properties b/gradle.properties index 73e0cd0798c121a71d3dcf57e12e9b7d0819b6ca..0daf1830fbdef07e50a44d74210c8c82f1b66278 100755 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,10 @@ -VERSION_NAME=19.0.1 -VERSION_CODE=2 -GROUP=com.github.castorflex.verticalviewpager - -#storeFile=nice try -#keyAlias=nice try -#storePassword=nice try -#keyPassword=nice try - -POM_DESCRIPTION=Android Library to have a vertical ViewPager -POM_URL=https://github.com/castorflex/VerticalViewPager -POM_SCM_URL=https://github.com/castorflex/VerticalViewPager -POM_SCM_CONNECTION=scm:git@github.com:castorflex/VerticalViewPager.git -POM_SCM_DEV_CONNECTION=scm:git@github.com:castorflex/VerticalViewPager.git -POM_LICENCE_NAME=THE BEER-WARE LICENSE, Revision 42 -POM_LICENCE_URL=https://en.wikipedia.org/wiki/Beerware -POM_LICENCE_DIST=repo -POM_DEVELOPER_ID=castorflex -POM_DEVELOPER_NAME=Antoine Merle - +# Project-wide Gradle settings. +# IDE (e.g. DevEco Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# If the Chinese output is garbled, please configure the following parameter. +# org.gradle.jvmargs=-Dfile.encoding=GBK diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a8698b08ecc4158d828ca593c4928e9dd..490fda8577df6c95960ba7077c43220e5bb2c0d9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9b8ffdd47e5613c706fc9ca40de3d6bfc414905c..f59159e865d4b59feb1b8c44b001f62fc5d58df4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed Apr 10 15:27:10 PDT 2013 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://repo.huaweicloud.com/gradle/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip diff --git a/gradlew b/gradlew index 91a7e269e19dfc62e27137a0b57ef3e430cee4fd..2fe81a7d95e4f9ad2c9b2a046707d36ceb3980b3 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## ## @@ -6,20 +22,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +75,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +105,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -110,10 +125,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -138,27 +154,30 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730b4e8fcd90b57a0e8e01544fea7c31a89..62bd9b9ccefea2b65ae41e5d9a545e2021b90a1d 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,90 +1,103 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windowz variants - -if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9 --- /dev/null +++ b/library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library/build.gradle b/library/build.gradle index 643308e4836e0c921a24c611faa393a5e6a225f4..e1c0b274a6c5cb35b197a177a17684addf760676 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,23 +1,21 @@ -apply plugin: 'android-library' - -repositories { - mavenCentral() -} - -dependencies { - compile 'com.android.support:support-v4:19.0.0' -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.0" - +apply plugin: 'com.huawei.ohos.library' +ohos { + compileSdkVersion 5 defaultConfig { - minSdkVersion 4 - targetSdkVersion 19 - versionName project.VERSION_NAME - versionCode Integer.parseInt(project.VERSION_CODE) + compatibleSdkVersion 4 + } + buildTypes { + release { + proguardOpt { + proguardEnabled false + rulesFiles 'proguard-rules.pro' + } + } } + } -apply from: '../mvn_push.gradle' +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.13' +} diff --git a/library/gradle.properties b/library/gradle.properties deleted file mode 100644 index 2e0862f597a6d6f53d5b8732dff57743c5219024..0000000000000000000000000000000000000000 --- a/library/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -POM_NAME=VerticalViewPager Library -POM_ARTIFACT_ID=library -POM_PACKAGING=aar \ No newline at end of file diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..f7666e47561d514b2a76d5a7dfbb43ede86da92a --- /dev/null +++ b/library/proguard-rules.pro @@ -0,0 +1 @@ +# config module specific ProGuard rules here. \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml deleted file mode 100644 index ce427a82245ac38adf1b0cea697f97b075293817..0000000000000000000000000000000000000000 --- a/library/src/main/AndroidManifest.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/library/src/main/config.json b/library/src/main/config.json new file mode 100644 index 0000000000000000000000000000000000000000..852dd5037dab5d27d9244f3e37c8f267f9cbc9c6 --- /dev/null +++ b/library/src/main/config.json @@ -0,0 +1,27 @@ +{ + "app": { + "bundleName": "fr.castorflex.android.verticalviewpager.sample", + "vendor": "castorflex", + "version": { + "code": 1, + "name": "1.0" + }, + "apiVersion": { + "compatible": 4, + "target": 5, + "releaseType": "Beta1" + } + }, + "deviceConfig": {}, + "module": { + "package": "fr.castorflex.android.verticalviewpager", + "deviceType": [ + "phone" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "Library", + "moduleType": "har" + } + } +} \ No newline at end of file diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/VerticalViewPager.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/VerticalViewPager.java index 8fbc9c3752c2c97caaf0530b47673696baadd72a..6e4aea501e339e4207f304479cdaedf625a28c6d 100644 --- a/library/src/main/java/fr/castorflex/android/verticalviewpager/VerticalViewPager.java +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/VerticalViewPager.java @@ -1,2789 +1,204 @@ package fr.castorflex.android.verticalviewpager; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.database.DataSetObserver; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.SystemClock; -import android.support.v4.os.ParcelableCompat; -import android.support.v4.os.ParcelableCompatCreatorCallbacks; -import android.support.v4.view.AccessibilityDelegateCompat; -import android.support.v4.view.KeyEventCompat; -import android.support.v4.view.MotionEventCompat; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.VelocityTrackerCompat; -import android.support.v4.view.ViewCompat; -import android.support.v4.view.ViewConfigurationCompat; -import android.support.v4.view.ViewPager; -import android.support.v4.view.accessibility.AccessibilityEventCompat; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; -import android.support.v4.view.accessibility.AccessibilityRecordCompat; -import android.support.v4.widget.EdgeEffectCompat; -import android.util.AttributeSet; -import android.util.Log; -import android.view.FocusFinder; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.accessibility.AccessibilityEvent; -import android.view.animation.Interpolator; -import android.widget.Scroller; +import fr.castorflex.android.verticalviewpager.transformer.MathUtils; +import ohos.agp.components.AttrSet; +import ohos.agp.components.Component; +import ohos.agp.components.PageSlider; +import ohos.app.Context; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.List; /** - * Created by castorflex on 12/29/13. - * Just a copy of the original ViewPager modified to support vertical Scrolling + * 扩展了PageSlide的动画接口 + * + * @author shetaotao + * @since 2021-04-26 */ -public class VerticalViewPager extends ViewGroup { - - private static final String TAG = "ViewPager"; - private static final boolean DEBUG = false; - - private static final boolean USE_CACHE = false; - - private static final int DEFAULT_OFFSCREEN_PAGES = 1; - private static final int MAX_SETTLE_DURATION = 600; // ms - private static final int MIN_DISTANCE_FOR_FLING = 25; // dips - - private static final int DEFAULT_GUTTER_SIZE = 16; // dips - - private static final int MIN_FLING_VELOCITY = 400; // dips - - private static final int[] LAYOUT_ATTRS = new int[]{ - android.R.attr.layout_gravity - }; - - /** - * Used to track what the expected number of items in the adapter should be. - * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. - */ - private int mExpectedAdapterCount; - - static class ItemInfo { - Object object; - int position; - boolean scrolling; - float heightFactor; - float offset; - } - - private static final Comparator COMPARATOR = new Comparator() { - @Override - public int compare(ItemInfo lhs, ItemInfo rhs) { - return lhs.position - rhs.position; - } - }; - - private static final Interpolator sInterpolator = new Interpolator() { - public float getInterpolation(float t) { - t -= 1.0f; - return t * t * t * t * t + 1.0f; - } - }; - - private final ArrayList mItems = new ArrayList(); - private final ItemInfo mTempItem = new ItemInfo(); - - private final Rect mTempRect = new Rect(); - - private PagerAdapter mAdapter; - private int mCurItem; // Index of currently displayed page. - private int mRestoredCurItem = -1; - private Parcelable mRestoredAdapterState = null; - private ClassLoader mRestoredClassLoader = null; - private Scroller mScroller; - private PagerObserver mObserver; - - private int mPageMargin; - private Drawable mMarginDrawable; - private int mLeftPageBounds; - private int mRightPageBounds; - - // Offsets of the first and last items, if known. - // Set during population, used to determine if we are at the beginning - // or end of the pager data set during touch scrolling. - private float mFirstOffset = -Float.MAX_VALUE; - private float mLastOffset = Float.MAX_VALUE; - - private int mChildWidthMeasureSpec; - private int mChildHeightMeasureSpec; - private boolean mInLayout; - - private boolean mScrollingCacheEnabled; - - private boolean mPopulatePending; - private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; - - private boolean mIsBeingDragged; - private boolean mIsUnableToDrag; - private boolean mIgnoreGutter; - private int mDefaultGutterSize; - private int mGutterSize; - private int mTouchSlop; - /** - * Position of the last motion event. - */ - private float mLastMotionX; - private float mLastMotionY; - private float mInitialMotionX; - private float mInitialMotionY; - /** - * ID of the active pointer. This is used to retain consistency during - * drags/flings if multiple pointers are used. - */ - private int mActivePointerId = INVALID_POINTER; - /** - * Sentinel value for no current active pointer. - * Used by {@link #mActivePointerId}. - */ - private static final int INVALID_POINTER = -1; - - /** - * Determines speed during touch scrolling - */ - private VelocityTracker mVelocityTracker; - private int mMinimumVelocity; - private int mMaximumVelocity; - private int mFlingDistance; - private int mCloseEnough; - - // If the pager is at least this close to its final position, complete the scroll - // on touch down and let the user interact with the content inside instead of - // "catching" the flinging pager. - private static final int CLOSE_ENOUGH = 2; // dp - - private boolean mFakeDragging; - private long mFakeDragBeginTime; - - private EdgeEffectCompat mTopEdge; - private EdgeEffectCompat mBottomEdge; - - private boolean mFirstLayout = true; - private boolean mNeedCalculatePageOffsets = false; - private boolean mCalledSuper; - private int mDecorChildCount; - - private ViewPager.OnPageChangeListener mOnPageChangeListener; - private ViewPager.OnPageChangeListener mInternalPageChangeListener; - private OnAdapterChangeListener mAdapterChangeListener; - private ViewPager.PageTransformer mPageTransformer; - private Method mSetChildrenDrawingOrderEnabled; - - private static final int DRAW_ORDER_DEFAULT = 0; - private static final int DRAW_ORDER_FORWARD = 1; - private static final int DRAW_ORDER_REVERSE = 2; - private int mDrawingOrder; - private ArrayList mDrawingOrderedChildren; - private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); - - /** - * Indicates that the pager is in an idle, settled state. The current page - * is fully in view and no animation is in progress. - */ - public static final int SCROLL_STATE_IDLE = 0; - - /** - * Indicates that the pager is currently being dragged by the user. - */ - public static final int SCROLL_STATE_DRAGGING = 1; - - /** - * Indicates that the pager is in the process of settling to a final position. - */ - public static final int SCROLL_STATE_SETTLING = 2; - - private final Runnable mEndScrollRunnable = new Runnable() { - public void run() { - setScrollState(SCROLL_STATE_IDLE); - populate(); - } - }; - - private int mScrollState = SCROLL_STATE_IDLE; - - /** - * Used internally to monitor when adapters are switched. - */ - interface OnAdapterChangeListener { - public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); - } - - /** - * Used internally to tag special types of child views that should be added as - * pager decorations by default. - */ - interface Decor { - } - - public VerticalViewPager(Context context) { - super(context); - initViewPager(); - } - - public VerticalViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - initViewPager(); - } - - void initViewPager() { - setWillNotDraw(false); - setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - setFocusable(true); - final Context context = getContext(); - mScroller = new Scroller(context, sInterpolator); - final ViewConfiguration configuration = ViewConfiguration.get(context); - final float density = context.getResources().getDisplayMetrics().density; - - mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); - mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); - mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - mTopEdge = new EdgeEffectCompat(context); - mBottomEdge = new EdgeEffectCompat(context); - - mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); - mCloseEnough = (int) (CLOSE_ENOUGH * density); - mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); - - ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); - - if (ViewCompat.getImportantForAccessibility(this) - == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - ViewCompat.setImportantForAccessibility(this, - ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); - } - } - - @Override - protected void onDetachedFromWindow() { - removeCallbacks(mEndScrollRunnable); - super.onDetachedFromWindow(); - } - - private void setScrollState(int newState) { - if (mScrollState == newState) { - return; - } - - mScrollState = newState; - if (mPageTransformer != null) { - // PageTransformers can do complex things that benefit from hardware layers. - enableLayers(newState != SCROLL_STATE_IDLE); - } - if (mOnPageChangeListener != null) { - mOnPageChangeListener.onPageScrollStateChanged(newState); - } - } - - /** - * Set a PagerAdapter that will supply views for this pager as needed. - * - * @param adapter Adapter to use - */ - public void setAdapter(PagerAdapter adapter) { - if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(mObserver); - mAdapter.startUpdate(this); - for (int i = 0; i < mItems.size(); i++) { - final ItemInfo ii = mItems.get(i); - mAdapter.destroyItem(this, ii.position, ii.object); - } - mAdapter.finishUpdate(this); - mItems.clear(); - removeNonDecorViews(); - mCurItem = 0; - scrollTo(0, 0); - } - - final PagerAdapter oldAdapter = mAdapter; - mAdapter = adapter; - mExpectedAdapterCount = 0; - - if (mAdapter != null) { - if (mObserver == null) { - mObserver = new PagerObserver(); - } - mAdapter.registerDataSetObserver(mObserver); - mPopulatePending = false; - final boolean wasFirstLayout = mFirstLayout; - mFirstLayout = true; - mExpectedAdapterCount = mAdapter.getCount(); - if (mRestoredCurItem >= 0) { - mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); - setCurrentItemInternal(mRestoredCurItem, false, true); - mRestoredCurItem = -1; - mRestoredAdapterState = null; - mRestoredClassLoader = null; - } else if (!wasFirstLayout) { - populate(); - } else { - requestLayout(); - } - } - - if (mAdapterChangeListener != null && oldAdapter != adapter) { - mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); - } - } - - private void removeNonDecorViews() { - for (int i = 0; i < getChildCount(); i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (!lp.isDecor) { - removeViewAt(i); - i--; - } - } - } - - /** - * Retrieve the current adapter supplying pages. - * - * @return The currently registered PagerAdapter - */ - public PagerAdapter getAdapter() { - return mAdapter; - } - - void setOnAdapterChangeListener(OnAdapterChangeListener listener) { - mAdapterChangeListener = listener; - } - -// private int getClientWidth() { -// return getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); -// } - - private int getClientHeight() { - return getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); - } - - - /** - * Set the currently selected page. If the ViewPager has already been through its first - * layout with its current adapter there will be a smooth animated transition between - * the current item and the specified item. - * - * @param item Item index to select - */ - public void setCurrentItem(int item) { - mPopulatePending = false; - setCurrentItemInternal(item, !mFirstLayout, false); - } - - /** - * Set the currently selected page. - * - * @param item Item index to select - * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately - */ - public void setCurrentItem(int item, boolean smoothScroll) { - mPopulatePending = false; - setCurrentItemInternal(item, smoothScroll, false); - } - - public int getCurrentItem() { - return mCurItem; - } - - void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { - setCurrentItemInternal(item, smoothScroll, always, 0); - } - - void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { - if (mAdapter == null || mAdapter.getCount() <= 0) { - setScrollingCacheEnabled(false); - return; - } - if (!always && mCurItem == item && mItems.size() != 0) { - setScrollingCacheEnabled(false); - return; - } - - if (item < 0) { - item = 0; - } else if (item >= mAdapter.getCount()) { - item = mAdapter.getCount() - 1; - } - final int pageLimit = mOffscreenPageLimit; - if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { - // We are doing a jump by more than one page. To avoid - // glitches, we want to keep all current pages in the view - // until the scroll ends. - for (int i = 0; i < mItems.size(); i++) { - mItems.get(i).scrolling = true; - } - } - final boolean dispatchSelected = mCurItem != item; - - if (mFirstLayout) { - // We don't have any idea how big we are yet and shouldn't have any pages either. - // Just set things up and let the pending layout handle things. - mCurItem = item; - if (dispatchSelected && mOnPageChangeListener != null) { - mOnPageChangeListener.onPageSelected(item); - } - if (dispatchSelected && mInternalPageChangeListener != null) { - mInternalPageChangeListener.onPageSelected(item); - } - requestLayout(); - } else { - populate(item); - scrollToItem(item, smoothScroll, velocity, dispatchSelected); - } - } - - private void scrollToItem(int item, boolean smoothScroll, int velocity, - boolean dispatchSelected) { - final ItemInfo curInfo = infoForPosition(item); - int destY = 0; - if (curInfo != null) { - final int height = getClientHeight(); - destY = (int) (height * Math.max(mFirstOffset, - Math.min(curInfo.offset, mLastOffset))); - } - if (smoothScroll) { - smoothScrollTo(0, destY, velocity); - if (dispatchSelected && mOnPageChangeListener != null) { - mOnPageChangeListener.onPageSelected(item); - } - if (dispatchSelected && mInternalPageChangeListener != null) { - mInternalPageChangeListener.onPageSelected(item); - } - } else { - if (dispatchSelected && mOnPageChangeListener != null) { - mOnPageChangeListener.onPageSelected(item); - } - if (dispatchSelected && mInternalPageChangeListener != null) { - mInternalPageChangeListener.onPageSelected(item); - } - completeScroll(false); - scrollTo(0, destY); - pageScrolled(destY); - } - } - - /** - * Set a listener that will be invoked whenever the page changes or is incrementally - * scrolled. See {@link android.support.v4.view.ViewPager.OnPageChangeListener}. - * - * @param listener Listener to set - */ - public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { - mOnPageChangeListener = listener; - } - - /** - * Set a {@link android.support.v4.view.ViewPager.PageTransformer} that will be called for each attached page whenever - * the scroll position is changed. This allows the application to apply custom property - * transformations to each page, overriding the default sliding look and feel. - *

- *

Note: Prior to Android 3.0 the property animation APIs did not exist. - * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.

- * - * @param reverseDrawingOrder true if the supplied PageTransformer requires page views - * to be drawn from last to first instead of first to last. - * @param transformer PageTransformer that will modify each page's animation properties - */ - public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) { - if (Build.VERSION.SDK_INT >= 11) { - final boolean hasTransformer = transformer != null; - final boolean needsPopulate = hasTransformer != (mPageTransformer != null); - mPageTransformer = transformer; - setChildrenDrawingOrderEnabledCompat(hasTransformer); - if (hasTransformer) { - mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; - } else { - mDrawingOrder = DRAW_ORDER_DEFAULT; - } - if (needsPopulate) populate(); - } - } - - void setChildrenDrawingOrderEnabledCompat(boolean enable) { - if (Build.VERSION.SDK_INT >= 7) { - if (mSetChildrenDrawingOrderEnabled == null) { - try { - mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( - "setChildrenDrawingOrderEnabled", new Class[]{Boolean.TYPE}); - } catch (NoSuchMethodException e) { - Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); - } - } - try { - mSetChildrenDrawingOrderEnabled.invoke(this, enable); - } catch (Exception e) { - Log.e(TAG, "Error changing children drawing order", e); - } - } - } - - @Override - protected int getChildDrawingOrder(int childCount, int i) { - final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; - final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; - return result; - } - - /** - * Set a separate OnPageChangeListener for internal use by the support library. - * - * @param listener Listener to set - * @return The old listener that was set, if any. - */ - ViewPager.OnPageChangeListener setInternalPageChangeListener(ViewPager.OnPageChangeListener listener) { - ViewPager.OnPageChangeListener oldListener = mInternalPageChangeListener; - mInternalPageChangeListener = listener; - return oldListener; - } - - /** - * Returns the number of pages that will be retained to either side of the - * current page in the view hierarchy in an idle state. Defaults to 1. - * - * @return How many pages will be kept offscreen on either side - * @see #setOffscreenPageLimit(int) - */ - public int getOffscreenPageLimit() { - return mOffscreenPageLimit; - } - - /** - * Set the number of pages that should be retained to either side of the - * current page in the view hierarchy in an idle state. Pages beyond this - * limit will be recreated from the adapter when needed. - *

- *

This is offered as an optimization. If you know in advance the number - * of pages you will need to support or have lazy-loading mechanisms in place - * on your pages, tweaking this setting can have benefits in perceived smoothness - * of paging animations and interaction. If you have a small number of pages (3-4) - * that you can keep active all at once, less time will be spent in layout for - * newly created view subtrees as the user pages back and forth.

- *

- *

You should keep this limit low, especially if your pages have complex layouts. - * This setting defaults to 1.

- * - * @param limit How many pages will be kept offscreen in an idle state. - */ - public void setOffscreenPageLimit(int limit) { - if (limit < DEFAULT_OFFSCREEN_PAGES) { - Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + - DEFAULT_OFFSCREEN_PAGES); - limit = DEFAULT_OFFSCREEN_PAGES; - } - if (limit != mOffscreenPageLimit) { - mOffscreenPageLimit = limit; - populate(); - } - } - - /** - * Set the margin between pages. - * - * @param marginPixels Distance between adjacent pages in pixels - * @see #getPageMargin() - * @see #setPageMarginDrawable(Drawable) - * @see #setPageMarginDrawable(int) - */ - public void setPageMargin(int marginPixels) { - final int oldMargin = mPageMargin; - mPageMargin = marginPixels; - - final int height = getHeight(); - recomputeScrollPosition(height, height, marginPixels, oldMargin); - - requestLayout(); - } - - /** - * Return the margin between pages. - * - * @return The size of the margin in pixels - */ - public int getPageMargin() { - return mPageMargin; - } - - /** - * Set a drawable that will be used to fill the margin between pages. - * - * @param d Drawable to display between pages - */ - public void setPageMarginDrawable(Drawable d) { - mMarginDrawable = d; - if (d != null) refreshDrawableState(); - setWillNotDraw(d == null); - invalidate(); - } - - /** - * Set a drawable that will be used to fill the margin between pages. - * - * @param resId Resource ID of a drawable to display between pages - */ - public void setPageMarginDrawable(int resId) { - setPageMarginDrawable(getContext().getResources().getDrawable(resId)); - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || who == mMarginDrawable; - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - final Drawable d = mMarginDrawable; - if (d != null && d.isStateful()) { - d.setState(getDrawableState()); - } - } - - // We want the duration of the page snap animation to be influenced by the distance that - // the screen has to travel, however, we don't want this duration to be effected in a - // purely linear fashion. Instead, we use this method to moderate the effect that the distance - // of travel has on the overall snap duration. - float distanceInfluenceForSnapDuration(float f) { - f -= 0.5f; // center the values about 0. - f *= 0.3f * Math.PI / 2.0f; - return (float) Math.sin(f); - } - - /** - * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. - * - * @param x the number of pixels to scroll by on the X axis - * @param y the number of pixels to scroll by on the Y axis - */ - void smoothScrollTo(int x, int y) { - smoothScrollTo(x, y, 0); - } - - /** - * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. - * - * @param x the number of pixels to scroll by on the X axis - * @param y the number of pixels to scroll by on the Y axis - * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) - */ - void smoothScrollTo(int x, int y, int velocity) { - if (getChildCount() == 0) { - // Nothing to do. - setScrollingCacheEnabled(false); - return; - } - int sx = getScrollX(); - int sy = getScrollY(); - int dx = x - sx; - int dy = y - sy; - if (dx == 0 && dy == 0) { - completeScroll(false); - populate(); - setScrollState(SCROLL_STATE_IDLE); - return; - } - - setScrollingCacheEnabled(true); - setScrollState(SCROLL_STATE_SETTLING); - - final int height = getClientHeight(); - final int halfHeight = height / 2; - final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / height); - final float distance = halfHeight + halfHeight * - distanceInfluenceForSnapDuration(distanceRatio); - - int duration = 0; - velocity = Math.abs(velocity); - if (velocity > 0) { - duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); - } else { - final float pageHeight = height * mAdapter.getPageWidth(mCurItem); - final float pageDelta = (float) Math.abs(dx) / (pageHeight + mPageMargin); - duration = (int) ((pageDelta + 1) * 100); - } - duration = Math.min(duration, MAX_SETTLE_DURATION); - - mScroller.startScroll(sx, sy, dx, dy, duration); - ViewCompat.postInvalidateOnAnimation(this); - } - - ItemInfo addNewItem(int position, int index) { - ItemInfo ii = new ItemInfo(); - ii.position = position; - ii.object = mAdapter.instantiateItem(this, position); - ii.heightFactor = mAdapter.getPageWidth(position); - if (index < 0 || index >= mItems.size()) { - mItems.add(ii); - } else { - mItems.add(index, ii); - } - return ii; - } - - void dataSetChanged() { - // This method only gets called if our observer is attached, so mAdapter is non-null. - - final int adapterCount = mAdapter.getCount(); - mExpectedAdapterCount = adapterCount; - boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && - mItems.size() < adapterCount; - int newCurrItem = mCurItem; - - boolean isUpdating = false; - for (int i = 0; i < mItems.size(); i++) { - final ItemInfo ii = mItems.get(i); - final int newPos = mAdapter.getItemPosition(ii.object); - - if (newPos == PagerAdapter.POSITION_UNCHANGED) { - continue; - } - - if (newPos == PagerAdapter.POSITION_NONE) { - mItems.remove(i); - i--; - - if (!isUpdating) { - mAdapter.startUpdate(this); - isUpdating = true; - } - - mAdapter.destroyItem(this, ii.position, ii.object); - needPopulate = true; - - if (mCurItem == ii.position) { - // Keep the current item in the valid range - newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); - needPopulate = true; - } - continue; - } - - if (ii.position != newPos) { - if (ii.position == mCurItem) { - // Our current item changed position. Follow it. - newCurrItem = newPos; - } - - ii.position = newPos; - needPopulate = true; - } - } - - if (isUpdating) { - mAdapter.finishUpdate(this); - } - - Collections.sort(mItems, COMPARATOR); - - if (needPopulate) { - // Reset our known page widths; populate will recompute them. - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (!lp.isDecor) { - lp.heightFactor = 0.f; - } - } - - setCurrentItemInternal(newCurrItem, false, true); - requestLayout(); - } - } - - void populate() { - populate(mCurItem); - } - - void populate(int newCurrentItem) { - ItemInfo oldCurInfo = null; - int focusDirection = View.FOCUS_FORWARD; - if (mCurItem != newCurrentItem) { - focusDirection = mCurItem < newCurrentItem ? View.FOCUS_DOWN : View.FOCUS_UP; - oldCurInfo = infoForPosition(mCurItem); - mCurItem = newCurrentItem; - } - - if (mAdapter == null) { - sortChildDrawingOrder(); - return; - } - - // Bail now if we are waiting to populate. This is to hold off - // on creating views from the time the user releases their finger to - // fling to a new position until we have finished the scroll to - // that position, avoiding glitches from happening at that point. - if (mPopulatePending) { - if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); - sortChildDrawingOrder(); - return; - } - - // Also, don't populate until we are attached to a window. This is to - // avoid trying to populate before we have restored our view hierarchy - // state and conflicting with what is restored. - if (getWindowToken() == null) { - return; - } - - mAdapter.startUpdate(this); - - final int pageLimit = mOffscreenPageLimit; - final int startPos = Math.max(0, mCurItem - pageLimit); - final int N = mAdapter.getCount(); - final int endPos = Math.min(N - 1, mCurItem + pageLimit); - - if (N != mExpectedAdapterCount) { - String resName; - try { - resName = getResources().getResourceName(getId()); - } catch (Resources.NotFoundException e) { - resName = Integer.toHexString(getId()); - } - throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + - " contents without calling PagerAdapter#notifyDataSetChanged!" + - " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + - " Pager id: " + resName + - " Pager class: " + getClass() + - " Problematic adapter: " + mAdapter.getClass()); - } - - // Locate the currently focused item or add it if needed. - int curIndex = -1; - ItemInfo curItem = null; - for (curIndex = 0; curIndex < mItems.size(); curIndex++) { - final ItemInfo ii = mItems.get(curIndex); - if (ii.position >= mCurItem) { - if (ii.position == mCurItem) curItem = ii; - break; - } - } - - if (curItem == null && N > 0) { - curItem = addNewItem(mCurItem, curIndex); - } - - // Fill 3x the available width or up to the number of offscreen - // pages requested to either side, whichever is larger. - // If we have no current item we have no work to do. - if (curItem != null) { - float extraHeightTop = 0.f; - int itemIndex = curIndex - 1; - ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; - final int clientHeight = getClientHeight(); - final float topHeightNeeded = clientHeight <= 0 ? 0 : - 2.f - curItem.heightFactor + (float) getPaddingLeft() / (float) clientHeight; - for (int pos = mCurItem - 1; pos >= 0; pos--) { - if (extraHeightTop >= topHeightNeeded && pos < startPos) { - if (ii == null) { - break; - } - if (pos == ii.position && !ii.scrolling) { - mItems.remove(itemIndex); - mAdapter.destroyItem(this, pos, ii.object); - if (DEBUG) { - Log.i(TAG, "populate() - destroyItem() with pos: " + pos + - " view: " + ((View) ii.object)); - } - itemIndex--; - curIndex--; - ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; - } - } else if (ii != null && pos == ii.position) { - extraHeightTop += ii.heightFactor; - itemIndex--; - ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; - } else { - ii = addNewItem(pos, itemIndex + 1); - extraHeightTop += ii.heightFactor; - curIndex++; - ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; - } - } - - float extraHeightBottom = curItem.heightFactor; - itemIndex = curIndex + 1; - if (extraHeightBottom < 2.f) { - ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; - final float bottomHeightNeeded = clientHeight <= 0 ? 0 : - (float) getPaddingRight() / (float) clientHeight + 2.f; - for (int pos = mCurItem + 1; pos < N; pos++) { - if (extraHeightBottom >= bottomHeightNeeded && pos > endPos) { - if (ii == null) { - break; - } - if (pos == ii.position && !ii.scrolling) { - mItems.remove(itemIndex); - mAdapter.destroyItem(this, pos, ii.object); - if (DEBUG) { - Log.i(TAG, "populate() - destroyItem() with pos: " + pos + - " view: " + ((View) ii.object)); - } - ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; - } - } else if (ii != null && pos == ii.position) { - extraHeightBottom += ii.heightFactor; - itemIndex++; - ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; - } else { - ii = addNewItem(pos, itemIndex); - itemIndex++; - extraHeightBottom += ii.heightFactor; - ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; - } - } - } - - calculatePageOffsets(curItem, curIndex, oldCurInfo); - } - - if (DEBUG) { - Log.i(TAG, "Current page list:"); - for (int i = 0; i < mItems.size(); i++) { - Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); - } - } - - mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); - - mAdapter.finishUpdate(this); - - // Check width measurement of current pages and drawing sort order. - // Update LayoutParams as needed. - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - lp.childIndex = i; - if (!lp.isDecor && lp.heightFactor == 0.f) { - // 0 means requery the adapter for this, it doesn't have a valid width. - final ItemInfo ii = infoForChild(child); - if (ii != null) { - lp.heightFactor = ii.heightFactor; - lp.position = ii.position; - } - } - } - sortChildDrawingOrder(); - - if (hasFocus()) { - View currentFocused = findFocus(); - ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; - if (ii == null || ii.position != mCurItem) { - for (int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - ii = infoForChild(child); - if (ii != null && ii.position == mCurItem) { - if (child.requestFocus(focusDirection)) { - break; - } - } - } - } - } - } - - private void sortChildDrawingOrder() { - if (mDrawingOrder != DRAW_ORDER_DEFAULT) { - if (mDrawingOrderedChildren == null) { - mDrawingOrderedChildren = new ArrayList(); - } else { - mDrawingOrderedChildren.clear(); - } - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - mDrawingOrderedChildren.add(child); - } - Collections.sort(mDrawingOrderedChildren, sPositionComparator); - } - } - - private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { - final int N = mAdapter.getCount(); - final int height = getClientHeight(); - final float marginOffset = height > 0 ? (float) mPageMargin / height : 0; - // Fix up offsets for later layout. - if (oldCurInfo != null) { - final int oldCurPosition = oldCurInfo.position; - // Base offsets off of oldCurInfo. - if (oldCurPosition < curItem.position) { - int itemIndex = 0; - ItemInfo ii = null; - float offset = oldCurInfo.offset + oldCurInfo.heightFactor + marginOffset; - for (int pos = oldCurPosition + 1; - pos <= curItem.position && itemIndex < mItems.size(); pos++) { - ii = mItems.get(itemIndex); - while (pos > ii.position && itemIndex < mItems.size() - 1) { - itemIndex++; - ii = mItems.get(itemIndex); - } - while (pos < ii.position) { - // We don't have an item populated for this, - // ask the adapter for an offset. - offset += mAdapter.getPageWidth(pos) + marginOffset; - pos++; - } - ii.offset = offset; - offset += ii.heightFactor + marginOffset; - } - } else if (oldCurPosition > curItem.position) { - int itemIndex = mItems.size() - 1; - ItemInfo ii = null; - float offset = oldCurInfo.offset; - for (int pos = oldCurPosition - 1; - pos >= curItem.position && itemIndex >= 0; pos--) { - ii = mItems.get(itemIndex); - while (pos < ii.position && itemIndex > 0) { - itemIndex--; - ii = mItems.get(itemIndex); - } - while (pos > ii.position) { - // We don't have an item populated for this, - // ask the adapter for an offset. - offset -= mAdapter.getPageWidth(pos) + marginOffset; - pos--; - } - offset -= ii.heightFactor + marginOffset; - ii.offset = offset; - } - } - } - - // Base all offsets off of curItem. - final int itemCount = mItems.size(); - float offset = curItem.offset; - int pos = curItem.position - 1; - mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; - mLastOffset = curItem.position == N - 1 ? - curItem.offset + curItem.heightFactor - 1 : Float.MAX_VALUE; - // Previous pages - for (int i = curIndex - 1; i >= 0; i--, pos--) { - final ItemInfo ii = mItems.get(i); - while (pos > ii.position) { - offset -= mAdapter.getPageWidth(pos--) + marginOffset; - } - offset -= ii.heightFactor + marginOffset; - ii.offset = offset; - if (ii.position == 0) mFirstOffset = offset; - } - offset = curItem.offset + curItem.heightFactor + marginOffset; - pos = curItem.position + 1; - // Next pages - for (int i = curIndex + 1; i < itemCount; i++, pos++) { - final ItemInfo ii = mItems.get(i); - while (pos < ii.position) { - offset += mAdapter.getPageWidth(pos++) + marginOffset; - } - if (ii.position == N - 1) { - mLastOffset = offset + ii.heightFactor - 1; - } - ii.offset = offset; - offset += ii.heightFactor + marginOffset; - } - - mNeedCalculatePageOffsets = false; - } - - /** - * This is the persistent state that is saved by ViewPager. Only needed - * if you are creating a sublass of ViewPager that must save its own - * state, in which case it should implement a subclass of this which - * contains that state. - */ - public static class SavedState extends BaseSavedState { - int position; - Parcelable adapterState; - ClassLoader loader; - - public SavedState(Parcelable superState) { - super(superState); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(position); - out.writeParcelable(adapterState, flags); - } - - @Override - public String toString() { - return "FragmentPager.SavedState{" - + Integer.toHexString(System.identityHashCode(this)) - + " position=" + position + "}"; - } - - public static final Parcelable.Creator CREATOR - = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() { - @Override - public SavedState createFromParcel(Parcel in, ClassLoader loader) { - return new SavedState(in, loader); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }); - - SavedState(Parcel in, ClassLoader loader) { - super(in); - if (loader == null) { - loader = getClass().getClassLoader(); - } - position = in.readInt(); - adapterState = in.readParcelable(loader); - this.loader = loader; - } - } - - @Override - public Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - SavedState ss = new SavedState(superState); - ss.position = mCurItem; - if (mAdapter != null) { - ss.adapterState = mAdapter.saveState(); - } - return ss; - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - if (!(state instanceof SavedState)) { - super.onRestoreInstanceState(state); - return; - } - - SavedState ss = (SavedState) state; - super.onRestoreInstanceState(ss.getSuperState()); - - if (mAdapter != null) { - mAdapter.restoreState(ss.adapterState, ss.loader); - setCurrentItemInternal(ss.position, false, true); - } else { - mRestoredCurItem = ss.position; - mRestoredAdapterState = ss.adapterState; - mRestoredClassLoader = ss.loader; - } - } - - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - if (!checkLayoutParams(params)) { - params = generateLayoutParams(params); - } - final LayoutParams lp = (LayoutParams) params; - lp.isDecor |= child instanceof Decor; - if (mInLayout) { - if (lp != null && lp.isDecor) { - throw new IllegalStateException("Cannot add pager decor view during layout"); - } - lp.needsMeasure = true; - addViewInLayout(child, index, params); - } else { - super.addView(child, index, params); - } - - if (USE_CACHE) { - if (child.getVisibility() != GONE) { - child.setDrawingCacheEnabled(mScrollingCacheEnabled); - } else { - child.setDrawingCacheEnabled(false); - } - } - } - - @Override - public void removeView(View view) { - if (mInLayout) { - removeViewInLayout(view); - } else { - super.removeView(view); - } - } - - ItemInfo infoForChild(View child) { - for (int i = 0; i < mItems.size(); i++) { - ItemInfo ii = mItems.get(i); - if (mAdapter.isViewFromObject(child, ii.object)) { - return ii; - } - } - return null; - } - - ItemInfo infoForAnyChild(View child) { - ViewParent parent; - while ((parent = child.getParent()) != this) { - if (parent == null || !(parent instanceof View)) { - return null; - } - child = (View) parent; - } - return infoForChild(child); - } - - ItemInfo infoForPosition(int position) { - for (int i = 0; i < mItems.size(); i++) { - ItemInfo ii = mItems.get(i); - if (ii.position == position) { - return ii; - } - } - return null; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mFirstLayout = true; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // For simple implementation, our internal size is always 0. - // We depend on the container to specify the layout size of - // our view. We can't really know what it is since we will be - // adding and removing different arbitrary views and do not - // want the layout to change as this happens. - setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), - getDefaultSize(0, heightMeasureSpec)); - - final int measuredHeight = getMeasuredHeight(); - final int maxGutterSize = measuredHeight / 10; - mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); - - // Children are just made to fill our space. - int childWidthSize = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); - int childHeightSize = measuredHeight - getPaddingTop() - getPaddingBottom(); - - /* - * Make sure all children have been properly measured. Decor views first. - * Right now we cheat and make this less complicated by assuming decor - * views won't intersect. We will pin to edges based on gravity. - */ - int size = getChildCount(); - for (int i = 0; i < size; ++i) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp != null && lp.isDecor) { - final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; - final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; - int widthMode = MeasureSpec.AT_MOST; - int heightMode = MeasureSpec.AT_MOST; - boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; - boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; - - if (consumeVertical) { - widthMode = MeasureSpec.EXACTLY; - } else if (consumeHorizontal) { - heightMode = MeasureSpec.EXACTLY; - } - - int widthSize = childWidthSize; - int heightSize = childHeightSize; - if (lp.width != LayoutParams.WRAP_CONTENT) { - widthMode = MeasureSpec.EXACTLY; - if (lp.width != LayoutParams.FILL_PARENT) { - widthSize = lp.width; - } - } - if (lp.height != LayoutParams.WRAP_CONTENT) { - heightMode = MeasureSpec.EXACTLY; - if (lp.height != LayoutParams.FILL_PARENT) { - heightSize = lp.height; - } - } - final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); - final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); - child.measure(widthSpec, heightSpec); - - if (consumeVertical) { - childHeightSize -= child.getMeasuredHeight(); - } else if (consumeHorizontal) { - childWidthSize -= child.getMeasuredWidth(); - } - } - } - } - - mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); - mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); - - // Make sure we have created all fragments that we need to have shown. - mInLayout = true; - populate(); - mInLayout = false; - - // Page views next. - size = getChildCount(); - for (int i = 0; i < size; ++i) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child - + ": " + mChildWidthMeasureSpec); - - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp == null || !lp.isDecor) { - final int heightSpec = MeasureSpec.makeMeasureSpec( - (int) (childHeightSize * lp.heightFactor), MeasureSpec.EXACTLY); - child.measure(mChildWidthMeasureSpec, heightSpec); - } - } - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - // Make sure scroll position is set correctly. - if (h != oldh) { - recomputeScrollPosition(h, oldh, mPageMargin, mPageMargin); - } - } - - private void recomputeScrollPosition(int height, int oldHeight, int margin, int oldMargin) { - if (oldHeight > 0 && !mItems.isEmpty()) { - final int heightWithMargin = height - getPaddingTop() - getPaddingBottom() + margin; - final int oldHeightWithMargin = oldHeight - getPaddingTop() - getPaddingBottom() - + oldMargin; - final int ypos = getScrollY(); - final float pageOffset = (float) ypos / oldHeightWithMargin; - final int newOffsetPixels = (int) (pageOffset * heightWithMargin); - - scrollTo(getScrollX(), newOffsetPixels); - if (!mScroller.isFinished()) { - // We now return to your regularly scheduled scroll, already in progress. - final int newDuration = mScroller.getDuration() - mScroller.timePassed(); - ItemInfo targetInfo = infoForPosition(mCurItem); - mScroller.startScroll(0, newOffsetPixels, - 0, (int) (targetInfo.offset * height), newDuration); - } - } else { - final ItemInfo ii = infoForPosition(mCurItem); - final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; - final int scrollPos = (int) (scrollOffset * - (height - getPaddingTop() - getPaddingBottom())); - if (scrollPos != getScrollY()) { - completeScroll(false); - scrollTo(getScrollX(), scrollPos); - } - } - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - final int count = getChildCount(); - int width = r - l; - int height = b - t; - int paddingLeft = getPaddingLeft(); - int paddingTop = getPaddingTop(); - int paddingRight = getPaddingRight(); - int paddingBottom = getPaddingBottom(); - final int scrollY = getScrollY(); - - int decorCount = 0; - - // First pass - decor views. We need to do this in two passes so that - // we have the proper offsets for non-decor views later. - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - int childLeft = 0; - int childTop = 0; - if (lp.isDecor) { - final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; - final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; - switch (hgrav) { - default: - childLeft = paddingLeft; - break; - case Gravity.LEFT: - childLeft = paddingLeft; - paddingLeft += child.getMeasuredWidth(); - break; - case Gravity.CENTER_HORIZONTAL: - childLeft = Math.max((width - child.getMeasuredWidth()) / 2, - paddingLeft); - break; - case Gravity.RIGHT: - childLeft = width - paddingRight - child.getMeasuredWidth(); - paddingRight += child.getMeasuredWidth(); - break; - } - switch (vgrav) { - default: - childTop = paddingTop; - break; - case Gravity.TOP: - childTop = paddingTop; - paddingTop += child.getMeasuredHeight(); - break; - case Gravity.CENTER_VERTICAL: - childTop = Math.max((height - child.getMeasuredHeight()) / 2, - paddingTop); - break; - case Gravity.BOTTOM: - childTop = height - paddingBottom - child.getMeasuredHeight(); - paddingBottom += child.getMeasuredHeight(); - break; - } - childTop += scrollY; - child.layout(childLeft, childTop, - childLeft + child.getMeasuredWidth(), - childTop + child.getMeasuredHeight()); - decorCount++; - } - } - } - - final int childHeight = height - paddingTop - paddingBottom; - // Page views. Do this once we have the right padding offsets from above. - for (int i = 0; i < count; i++) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - ItemInfo ii; - if (!lp.isDecor && (ii = infoForChild(child)) != null) { - int toff = (int) (childHeight * ii.offset); - int childLeft = paddingLeft; - int childTop = paddingTop + toff; - if (lp.needsMeasure) { - // This was added during layout and needs measurement. - // Do it now that we know what we're working with. - lp.needsMeasure = false; - final int widthSpec = MeasureSpec.makeMeasureSpec( - (int) (width - paddingLeft - paddingRight), - MeasureSpec.EXACTLY); - final int heightSpec = MeasureSpec.makeMeasureSpec( - (int) (childHeight * lp.heightFactor), - MeasureSpec.EXACTLY); - child.measure(widthSpec, heightSpec); - } - if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object - + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() - + "x" + child.getMeasuredHeight()); - child.layout(childLeft, childTop, - childLeft + child.getMeasuredWidth(), - childTop + child.getMeasuredHeight()); - } - } - } - mLeftPageBounds = paddingLeft; - mRightPageBounds = width - paddingRight; - mDecorChildCount = decorCount; - - if (mFirstLayout) { - scrollToItem(mCurItem, false, 0, false); - } - mFirstLayout = false; - } - - @Override - public void computeScroll() { - if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { - int oldX = getScrollX(); - int oldY = getScrollY(); - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - - if (oldX != x || oldY != y) { - scrollTo(x, y); - if (!pageScrolled(y)) { - mScroller.abortAnimation(); - scrollTo(x, 0); - } - } - - // Keep on drawing until the animation has finished. - ViewCompat.postInvalidateOnAnimation(this); - return; - } - - // Done with scroll, clean up state. - completeScroll(true); - } - - private boolean pageScrolled(int ypos) { - if (mItems.size() == 0) { - mCalledSuper = false; - onPageScrolled(0, 0, 0); - if (!mCalledSuper) { - throw new IllegalStateException( - "onPageScrolled did not call superclass implementation"); - } - return false; - } - final ItemInfo ii = infoForCurrentScrollPosition(); - final int height = getClientHeight(); - final int heightWithMargin = height + mPageMargin; - final float marginOffset = (float) mPageMargin / height; - final int currentPage = ii.position; - final float pageOffset = (((float) ypos / height) - ii.offset) / - (ii.heightFactor + marginOffset); - final int offsetPixels = (int) (pageOffset * heightWithMargin); - - mCalledSuper = false; - onPageScrolled(currentPage, pageOffset, offsetPixels); - if (!mCalledSuper) { - throw new IllegalStateException( - "onPageScrolled did not call superclass implementation"); - } - return true; - } - - /** - * This method will be invoked when the current page is scrolled, either as part - * of a programmatically initiated smooth scroll or a user initiated touch scroll. - * If you override this method you must call through to the superclass implementation - * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled - * returns. - * - * @param position Position index of the first page currently being displayed. - * Page position+1 will be visible if positionOffset is nonzero. - * @param offset Value from [0, 1) indicating the offset from the page at position. - * @param offsetPixels Value in pixels indicating the offset from position. - */ - protected void onPageScrolled(int position, float offset, int offsetPixels) { - // Offset any decor views if needed - keep them on-screen at all times. - if (mDecorChildCount > 0) { - final int scrollY = getScrollY(); - int paddingTop = getPaddingTop(); - int paddingBottom = getPaddingBottom(); - final int height = getHeight(); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (!lp.isDecor) continue; - - final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; - int childTop = 0; - switch (vgrav) { - default: - childTop = paddingTop; - break; - case Gravity.TOP: - childTop = paddingTop; - paddingTop += child.getHeight(); - break; - case Gravity.CENTER_VERTICAL: - childTop = Math.max((height - child.getMeasuredHeight()) / 2, - paddingTop); - break; - case Gravity.BOTTOM: - childTop = height - paddingBottom - child.getMeasuredHeight(); - paddingBottom += child.getMeasuredHeight(); - break; - } - childTop += scrollY; - - final int childOffset = childTop - child.getTop(); - if (childOffset != 0) { - child.offsetTopAndBottom(childOffset); - } - } - } - - if (mOnPageChangeListener != null) { - mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); - } - if (mInternalPageChangeListener != null) { - mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); - } - - if (mPageTransformer != null) { - final int scrollY = getScrollY(); - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - - if (lp.isDecor) continue; - - final float transformPos = (float) (child.getTop() - scrollY) / getClientHeight(); - mPageTransformer.transformPage(child, transformPos); - } - } - - mCalledSuper = true; - } - - private void completeScroll(boolean postEvents) { - boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; - if (needPopulate) { - // Done with scroll, no longer want to cache view drawing. - setScrollingCacheEnabled(false); - mScroller.abortAnimation(); - int oldX = getScrollX(); - int oldY = getScrollY(); - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - if (oldX != x || oldY != y) { - scrollTo(x, y); - } - } - mPopulatePending = false; - for (int i = 0; i < mItems.size(); i++) { - ItemInfo ii = mItems.get(i); - if (ii.scrolling) { - needPopulate = true; - ii.scrolling = false; - } - } - if (needPopulate) { - if (postEvents) { - ViewCompat.postOnAnimation(this, mEndScrollRunnable); - } else { - mEndScrollRunnable.run(); - } - } - } - - private boolean isGutterDrag(float y, float dy) { - return (y < mGutterSize && dy > 0) || (y > getHeight() - mGutterSize && dy < 0); - } - - private void enableLayers(boolean enable) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final int layerType = enable ? - ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; - ViewCompat.setLayerType(getChildAt(i), layerType, null); - } - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - /* - * This method JUST determines whether we want to intercept the motion. - * If we return true, onMotionEvent will be called and we do the actual - * scrolling there. - */ - - final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; - - // Always take care of the touch gesture being complete. - if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { - // Release the drag. - if (DEBUG) Log.v(TAG, "Intercept done!"); - mIsBeingDragged = false; - mIsUnableToDrag = false; - mActivePointerId = INVALID_POINTER; - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - return false; - } - - // Nothing more to do here if we have decided whether or not we - // are dragging. - if (action != MotionEvent.ACTION_DOWN) { - if (mIsBeingDragged) { - if (DEBUG) Log.v(TAG, "Intercept returning true!"); - return true; - } - if (mIsUnableToDrag) { - if (DEBUG) Log.v(TAG, "Intercept returning false!"); - return false; - } - } - - switch (action) { - case MotionEvent.ACTION_MOVE: { - /* - * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check - * whether the user has moved far enough from his original down touch. - */ - - /* - * Locally do absolute value. mLastMotionY is set to the y value - * of the down event. - */ - final int activePointerId = mActivePointerId; - if (activePointerId == INVALID_POINTER) { - // If we don't have a valid id, the touch down wasn't on content. - break; - } - - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float dy = y - mLastMotionY; - final float yDiff = Math.abs(dy); - final float x = MotionEventCompat.getX(ev, pointerIndex); - final float xDiff = Math.abs(x - mInitialMotionX); - if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); - - if (dy != 0 && !isGutterDrag(mLastMotionY, dy) && - canScroll(this, false, (int) dy, (int) x, (int) y)) { - // Nested view has scrollable area under this point. Let it be handled there. - mLastMotionX = x; - mLastMotionY = y; - mIsUnableToDrag = true; - return false; - } - if (yDiff > mTouchSlop && yDiff * 0.5f > xDiff) { - if (DEBUG) Log.v(TAG, "Starting drag!"); - mIsBeingDragged = true; - requestParentDisallowInterceptTouchEvent(true); - setScrollState(SCROLL_STATE_DRAGGING); - mLastMotionY = dy > 0 ? mInitialMotionY + mTouchSlop : - mInitialMotionY - mTouchSlop; - mLastMotionX = x; - setScrollingCacheEnabled(true); - } else if (xDiff > mTouchSlop) { - // The finger has moved enough in the vertical - // direction to be counted as a drag... abort - // any attempt to drag horizontally, to work correctly - // with children that have scrolling containers. - if (DEBUG) Log.v(TAG, "Starting unable to drag!"); - mIsUnableToDrag = true; - } - if (mIsBeingDragged) { - // Scroll to follow the motion event - if (performDrag(y)) { - ViewCompat.postInvalidateOnAnimation(this); - } - } - break; - } - - case MotionEvent.ACTION_DOWN: { - /* - * Remember location of down touch. - * ACTION_DOWN always refers to pointer index 0. - */ - mLastMotionX = mInitialMotionX = ev.getX(); - mLastMotionY = mInitialMotionY = ev.getY(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - mIsUnableToDrag = false; - - mScroller.computeScrollOffset(); - if (mScrollState == SCROLL_STATE_SETTLING && - Math.abs(mScroller.getFinalY() - mScroller.getCurrY()) > mCloseEnough) { - // Let the user 'catch' the pager as it animates. - mScroller.abortAnimation(); - mPopulatePending = false; - populate(); - mIsBeingDragged = true; - requestParentDisallowInterceptTouchEvent(true); - setScrollState(SCROLL_STATE_DRAGGING); - } else { - completeScroll(false); - mIsBeingDragged = false; - } - - if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY - + " mIsBeingDragged=" + mIsBeingDragged - + "mIsUnableToDrag=" + mIsUnableToDrag); - break; - } - - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; - } - - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - /* - * The only time we want to intercept motion events is if we are in the - * drag mode. - */ - return mIsBeingDragged; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (mFakeDragging) { - // A fake drag is in progress already, ignore this real one - // but still eat the touch events. - // (It is likely that the user is multi-touching the screen.) - return true; - } - - if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { - // Don't handle edge touches immediately -- they may actually belong to one of our - // descendants. - return false; - } - - if (mAdapter == null || mAdapter.getCount() == 0) { - // Nothing to present or scroll; nothing to touch. - return false; - } - - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - final int action = ev.getAction(); - boolean needsInvalidate = false; - - switch (action & MotionEventCompat.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mScroller.abortAnimation(); - mPopulatePending = false; - populate(); - - // Remember where the motion event started - mLastMotionX = mInitialMotionX = ev.getX(); - mLastMotionY = mInitialMotionY = ev.getY(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - break; - } - case MotionEvent.ACTION_MOVE: - if (!mIsBeingDragged) { - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = Math.abs(y - mLastMotionY); - final float x = MotionEventCompat.getX(ev, pointerIndex); - final float xDiff = Math.abs(x - mLastMotionX); - if (DEBUG) - Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); - if (yDiff > mTouchSlop && yDiff > xDiff) { - if (DEBUG) Log.v(TAG, "Starting drag!"); - mIsBeingDragged = true; - requestParentDisallowInterceptTouchEvent(true); - mLastMotionY = y - mInitialMotionY > 0 ? mInitialMotionY + mTouchSlop : - mInitialMotionY - mTouchSlop; - mLastMotionX = x; - setScrollState(SCROLL_STATE_DRAGGING); - setScrollingCacheEnabled(true); - - // Disallow Parent Intercept, just in case - ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - } - } - // Not else! Note that mIsBeingDragged can be set above. - if (mIsBeingDragged) { - // Scroll to follow the motion event - final int activePointerIndex = MotionEventCompat.findPointerIndex( - ev, mActivePointerId); - final float y = MotionEventCompat.getY(ev, activePointerIndex); - needsInvalidate |= performDrag(y); - } - break; - case MotionEvent.ACTION_UP: - if (mIsBeingDragged) { - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int initialVelocity = (int) VelocityTrackerCompat.getYVelocity( - velocityTracker, mActivePointerId); - mPopulatePending = true; - final int height = getClientHeight(); - final int scrollY = getScrollY(); - final ItemInfo ii = infoForCurrentScrollPosition(); - final int currentPage = ii.position; - final float pageOffset = (((float) scrollY / height) - ii.offset) / ii.heightFactor; - final int activePointerIndex = - MotionEventCompat.findPointerIndex(ev, mActivePointerId); - final float y = MotionEventCompat.getY(ev, activePointerIndex); - final int totalDelta = (int) (y - mInitialMotionY); - int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, - totalDelta); - setCurrentItemInternal(nextPage, true, true, initialVelocity); - - mActivePointerId = INVALID_POINTER; - endDrag(); - needsInvalidate = mTopEdge.onRelease() | mBottomEdge.onRelease(); - } - break; - case MotionEvent.ACTION_CANCEL: - if (mIsBeingDragged) { - scrollToItem(mCurItem, true, 0, false); - mActivePointerId = INVALID_POINTER; - endDrag(); - needsInvalidate = mTopEdge.onRelease() | mBottomEdge.onRelease(); - } - break; - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int index = MotionEventCompat.getActionIndex(ev); - final float y = MotionEventCompat.getY(ev, index); - mLastMotionY = y; - mActivePointerId = MotionEventCompat.getPointerId(ev, index); - break; - } - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - mLastMotionY = MotionEventCompat.getY(ev, - MotionEventCompat.findPointerIndex(ev, mActivePointerId)); - break; - } - if (needsInvalidate) { - ViewCompat.postInvalidateOnAnimation(this); - } - return true; - } - - private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) { - final ViewParent parent = getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(disallowIntercept); - } - } - - private boolean performDrag(float y) { - boolean needsInvalidate = false; - - final float deltaY = mLastMotionY - y; - mLastMotionY = y; - - float oldScrollY = getScrollY(); - float scrollY = oldScrollY + deltaY; - final int height = getClientHeight(); - - float topBound = height * mFirstOffset; - float bottomBound = height * mLastOffset; - boolean topAbsolute = true; - boolean bottomAbsolute = true; - - final ItemInfo firstItem = mItems.get(0); - final ItemInfo lastItem = mItems.get(mItems.size() - 1); - if (firstItem.position != 0) { - topAbsolute = false; - topBound = firstItem.offset * height; - } - if (lastItem.position != mAdapter.getCount() - 1) { - bottomAbsolute = false; - bottomBound = lastItem.offset * height; - } - - if (scrollY < topBound) { - if (topAbsolute) { - float over = topBound - scrollY; - needsInvalidate = mTopEdge.onPull(Math.abs(over) / height); - } - scrollY = topBound; - } else if (scrollY > bottomBound) { - if (bottomAbsolute) { - float over = scrollY - bottomBound; - needsInvalidate = mBottomEdge.onPull(Math.abs(over) / height); - } - scrollY = bottomBound; - } - // Don't lose the rounded component - mLastMotionX += scrollY - (int) scrollY; - scrollTo(getScrollX(), (int) scrollY); - pageScrolled((int) scrollY); - - return needsInvalidate; - } - - /** - * @return Info about the page at the current scroll position. - * This can be synthetic for a missing middle page; the 'object' field can be null. - */ - private ItemInfo infoForCurrentScrollPosition() { - final int height = getClientHeight(); - final float scrollOffset = height > 0 ? (float) getScrollY() / height : 0; - final float marginOffset = height > 0 ? (float) mPageMargin / height : 0; - int lastPos = -1; - float lastOffset = 0.f; - float lastHeight = 0.f; - boolean first = true; - - ItemInfo lastItem = null; - for (int i = 0; i < mItems.size(); i++) { - ItemInfo ii = mItems.get(i); - float offset; - if (!first && ii.position != lastPos + 1) { - // Create a synthetic item for a missing page. - ii = mTempItem; - ii.offset = lastOffset + lastHeight + marginOffset; - ii.position = lastPos + 1; - ii.heightFactor = mAdapter.getPageWidth(ii.position); - i--; - } - offset = ii.offset; - - final float topBound = offset; - final float bottomBound = offset + ii.heightFactor + marginOffset; - if (first || scrollOffset >= topBound) { - if (scrollOffset < bottomBound || i == mItems.size() - 1) { - return ii; - } - } else { - return lastItem; - } - first = false; - lastPos = ii.position; - lastOffset = offset; - lastHeight = ii.heightFactor; - lastItem = ii; - } - - return lastItem; - } - - private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaY) { - int targetPage; - if (Math.abs(deltaY) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { - targetPage = velocity > 0 ? currentPage : currentPage + 1; - } else { - final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; - targetPage = (int) (currentPage + pageOffset + truncator); - } - - if (mItems.size() > 0) { - final ItemInfo firstItem = mItems.get(0); - final ItemInfo lastItem = mItems.get(mItems.size() - 1); - - // Only let the user target pages we have items for - targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); - } - - return targetPage; - } - - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - boolean needsInvalidate = false; - - final int overScrollMode = ViewCompat.getOverScrollMode(this); - if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || - (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && - mAdapter != null && mAdapter.getCount() > 1)) { - if (!mTopEdge.isFinished()) { - final int restoreCount = canvas.save(); - final int height = getHeight(); - final int width = getWidth() - getPaddingLeft() - getPaddingRight(); - - canvas.translate(getPaddingLeft(), mFirstOffset * height); - mTopEdge.setSize(width, height); - needsInvalidate |= mTopEdge.draw(canvas); - canvas.restoreToCount(restoreCount); - } - if (!mBottomEdge.isFinished()) { - final int restoreCount = canvas.save(); - final int height = getHeight(); - final int width = getWidth() - getPaddingLeft() - getPaddingRight(); - - canvas.rotate(180); - canvas.translate(-width - getPaddingLeft(), -(mLastOffset + 1) * height); - mBottomEdge.setSize(width, height); - needsInvalidate |= mBottomEdge.draw(canvas); - canvas.restoreToCount(restoreCount); - } - } else { - mTopEdge.finish(); - mBottomEdge.finish(); - } - - if (needsInvalidate) { - // Keep animating - ViewCompat.postInvalidateOnAnimation(this); - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - // Draw the margin drawable between pages if needed. - if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { - final int scrollY = getScrollY(); - final int height = getHeight(); - - final float marginOffset = (float) mPageMargin / height; - int itemIndex = 0; - ItemInfo ii = mItems.get(0); - float offset = ii.offset; - final int itemCount = mItems.size(); - final int firstPos = ii.position; - final int lastPos = mItems.get(itemCount - 1).position; - for (int pos = firstPos; pos < lastPos; pos++) { - while (pos > ii.position && itemIndex < itemCount) { - ii = mItems.get(++itemIndex); - } - - float drawAt; - if (pos == ii.position) { - drawAt = (ii.offset + ii.heightFactor) * height; - offset = ii.offset + ii.heightFactor + marginOffset; - } else { - float heightFactor = mAdapter.getPageWidth(pos); - drawAt = (offset + heightFactor) * height; - offset += heightFactor + marginOffset; - } - - if (drawAt + mPageMargin > scrollY) { - mMarginDrawable.setBounds(mLeftPageBounds, (int) drawAt, - mRightPageBounds, (int) (drawAt + mPageMargin + 0.5f)); - mMarginDrawable.draw(canvas); - } - - if (drawAt > scrollY + height) { - break; // No more visible, no sense in continuing - } - } - } - } - - /** - * Start a fake drag of the pager. - *

- *

A fake drag can be useful if you want to synchronize the motion of the ViewPager - * with the touch scrolling of another view, while still letting the ViewPager - * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) - * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call - * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. - *

- *

During a fake drag the ViewPager will ignore all touch events. If a real drag - * is already in progress, this method will return false. - * - * @return true if the fake drag began successfully, false if it could not be started. - * @see #fakeDragBy(float) - * @see #endFakeDrag() - */ - public boolean beginFakeDrag() { - if (mIsBeingDragged) { - return false; - } - mFakeDragging = true; - setScrollState(SCROLL_STATE_DRAGGING); - mInitialMotionY = mLastMotionY = 0; - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } else { - mVelocityTracker.clear(); - } - final long time = SystemClock.uptimeMillis(); - final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); - mVelocityTracker.addMovement(ev); - ev.recycle(); - mFakeDragBeginTime = time; - return true; - } - - /** - * End a fake drag of the pager. - * - * @see #beginFakeDrag() - * @see #fakeDragBy(float) +public class VerticalViewPager extends PageSlider implements PageSlider.PageChangedListener { + private static final int SLID_LEFT = 0; + private static final int SLID_LEFT_ELASTIC = 1; + private static final int SLID_RIGHT = 2; + private static final int SLID_RIGHT_ELASTIC = 3; + private static final int SLID_NONE = 4; + private static final int SCROLL_RIGHT = -1; + private int mCurrentState = 0; + private int mCurrentItemPos = 0; + private int mItemPosOffsetPixels = 0; + private int mLastScrollState; + private float mItemPosOffset = 0; + private float mOriginalOffset = 0; + private List mComponents; + private VerticalViewPager.PageTransformer mPageTransformer; + + /** + * 此类为了适配PageSlide滑动监听参数问题 + * + * @param context context */ - public void endFakeDrag() { - if (!mFakeDragging) { - throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); - } - - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int initialVelocity = (int) VelocityTrackerCompat.getYVelocity( - velocityTracker, mActivePointerId); - mPopulatePending = true; - final int height = getClientHeight(); - final int scrollY = getScrollY(); - final ItemInfo ii = infoForCurrentScrollPosition(); - final int currentPage = ii.position; - final float pageOffset = (((float) scrollY / height) - ii.offset) / ii.heightFactor; - final int totalDelta = (int) (mLastMotionY - mInitialMotionY); - int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, - totalDelta); - setCurrentItemInternal(nextPage, true, true, initialVelocity); - endDrag(); - - mFakeDragging = false; + public VerticalViewPager(Context context) { + this(context, null); } /** - * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. + * 此类为了适配PageSlide滑动监听参数问题 * - * @param yOffset Offset in pixels to drag by. - * @see #beginFakeDrag() - * @see #endFakeDrag() + * @param context context + * @param attrSet attrSet */ - public void fakeDragBy(float yOffset) { - if (!mFakeDragging) { - throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); - } - - mLastMotionY += yOffset; - - float oldScrollY = getScrollY(); - float scrollY = oldScrollY - yOffset; - final int height = getClientHeight(); - - float topBound = height * mFirstOffset; - float bottomBound = height * mLastOffset; - - final ItemInfo firstItem = mItems.get(0); - final ItemInfo lastItem = mItems.get(mItems.size() - 1); - if (firstItem.position != 0) { - topBound = firstItem.offset * height; - } - if (lastItem.position != mAdapter.getCount() - 1) { - bottomBound = lastItem.offset * height; - } - - if (scrollY < topBound) { - scrollY = topBound; - } else if (scrollY > bottomBound) { - scrollY = bottomBound; - } - // Don't lose the rounded component - mLastMotionY += scrollY - (int) scrollY; - scrollTo(getScrollX(), (int) scrollY); - pageScrolled((int) scrollY); - - // Synthesize an event for the VelocityTracker. - final long time = SystemClock.uptimeMillis(); - final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, - 0, mLastMotionY, 0); - mVelocityTracker.addMovement(ev); - ev.recycle(); + public VerticalViewPager(Context context, AttrSet attrSet) { + this(context, attrSet, null); + addPageChangedListener(this); } /** - * Returns true if a fake drag is in progress. + * 此类为了适配PageSlide滑动监听参数问题 * - * @return true if currently in a fake drag, false otherwise. - * @see #beginFakeDrag() - * @see #fakeDragBy(float) - * @see #endFakeDrag() + * @param context context + * @param attrSet attrSet + * @param styleName style name */ - public boolean isFakeDragging() { - return mFakeDragging; - } - - private void onSecondaryPointerUp(MotionEvent ev) { - final int pointerIndex = MotionEventCompat.getActionIndex(ev); - final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex); - mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); - if (mVelocityTracker != null) { - mVelocityTracker.clear(); - } - } - } - - private void endDrag() { - mIsBeingDragged = false; - mIsUnableToDrag = false; - - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - - private void setScrollingCacheEnabled(boolean enabled) { - if (mScrollingCacheEnabled != enabled) { - mScrollingCacheEnabled = enabled; - if (USE_CACHE) { - final int size = getChildCount(); - for (int i = 0; i < size; ++i) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - child.setDrawingCacheEnabled(enabled); - } - } - } - } + public VerticalViewPager(Context context, AttrSet attrSet, String styleName) { + super(context, attrSet, styleName); } - public boolean internalCanScrollVertically(int direction) { - if (mAdapter == null) { - return false; - } - - final int height = getClientHeight(); - final int scrollY = getScrollY(); - if (direction < 0) { - return (scrollY > (int) (height * mFirstOffset)); - } else if (direction > 0) { - return (scrollY < (int) (height * mLastOffset)); - } else { - return false; - } + @Override + public void onPageSliding(int position, float offset, int offsetPixels) { + onPageScrolled(position, offset, offsetPixels); } - /** - * Tests scrollability within child views of v given a delta of dx. - * - * @param v View to test for horizontal scrollability - * @param checkV Whether the view v passed should itself be checked for scrollability (true), - * or just its children (false). - * @param dy Delta scrolled in pixels - * @param x X coordinate of the active touch point - * @param y Y coordinate of the active touch point - * @return true if child views of v can be scrolled by delta of dx. - */ - protected boolean canScroll(View v, boolean checkV, int dy, int x, int y) { - if (v instanceof ViewGroup) { - final ViewGroup group = (ViewGroup) v; - final int scrollX = v.getScrollX(); - final int scrollY = v.getScrollY(); - final int count = group.getChildCount(); - // Count backwards - let topmost views consume scroll distance first. - for (int i = count - 1; i >= 0; i--) { - // TODO: Add versioned support here for transformed views. - // This will not work for transformed views in Honeycomb+ - final View child = group.getChildAt(i); - if (y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && - x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && - canScroll(child, true, dy, x + scrollX - child.getLeft(), - y + scrollY - child.getTop())) { - return true; - } - } - } - - return checkV && ViewCompat.canScrollVertically(v, -dy); + @Override + public void onPageSlideStateChanged(int state) { + mCurrentState = state; } @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // Let the focused view and/or our descendants get the key first - return super.dispatchKeyEvent(event) || executeKeyEvent(event); + public void onPageChosen(int i) { + // NOTHING } /** - * You can call this function yourself to have the scroll view perform - * scrolling from a key event, just as if the event had been dispatched to - * it by the view hierarchy. + * 设置PageSlide所有子组件 * - * @param event The key event to execute. - * @return Return true if the event was handled, else false. + * @param components 子组件集合 */ - public boolean executeKeyEvent(KeyEvent event) { - boolean handled = false; - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_LEFT: - handled = arrowScroll(FOCUS_LEFT); - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - handled = arrowScroll(FOCUS_RIGHT); - break; - case KeyEvent.KEYCODE_TAB: - if (Build.VERSION.SDK_INT >= 11) { - // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD - // before Android 3.0. Ignore the tab key on those devices. - if (KeyEventCompat.hasNoModifiers(event)) { - handled = arrowScroll(FOCUS_FORWARD); - } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { - handled = arrowScroll(FOCUS_BACKWARD); - } - } - break; - } - } - return handled; - } - - public boolean arrowScroll(int direction) { - View currentFocused = findFocus(); - if (currentFocused == this) { - currentFocused = null; - } else if (currentFocused != null) { - boolean isChild = false; - for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; - parent = parent.getParent()) { - if (parent == this) { - isChild = true; - break; - } - } - if (!isChild) { - // This would cause the focus search down below to fail in fun ways. - final StringBuilder sb = new StringBuilder(); - sb.append(currentFocused.getClass().getSimpleName()); - for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; - parent = parent.getParent()) { - sb.append(" => ").append(parent.getClass().getSimpleName()); - } - Log.e(TAG, "arrowScroll tried to find focus based on non-child " + - "current focused view " + sb.toString()); - currentFocused = null; - } - } - - boolean handled = false; - - View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, - direction); - if (nextFocused != null && nextFocused != currentFocused) { - if (direction == View.FOCUS_UP) { - // If there is nothing to the left, or this is causing us to - // jump to the right, then what we really want to do is page left. - final int nextTop = getChildRectInPagerCoordinates(mTempRect, nextFocused).top; - final int currTop = getChildRectInPagerCoordinates(mTempRect, currentFocused).top; - if (currentFocused != null && nextTop >= currTop) { - handled = pageUp(); - } else { - handled = nextFocused.requestFocus(); - } - } else if (direction == View.FOCUS_DOWN) { - // If there is nothing to the right, or this is causing us to - // jump to the left, then what we really want to do is page right. - final int nextDown = getChildRectInPagerCoordinates(mTempRect, nextFocused).bottom; - final int currDown = getChildRectInPagerCoordinates(mTempRect, currentFocused).bottom; - if (currentFocused != null && nextDown <= currDown) { - handled = pageDown(); - } else { - handled = nextFocused.requestFocus(); - } - } - } else if (direction == FOCUS_UP || direction == FOCUS_BACKWARD) { - // Trying to move left and nothing there; try to page. - handled = pageUp(); - } else if (direction == FOCUS_DOWN || direction == FOCUS_FORWARD) { - // Trying to move right and nothing there; try to page. - handled = pageDown(); - } - if (handled) { - playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); - } - return handled; - } - - private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { - if (outRect == null) { - outRect = new Rect(); - } - if (child == null) { - outRect.set(0, 0, 0, 0); - return outRect; - } - outRect.left = child.getLeft(); - outRect.right = child.getRight(); - outRect.top = child.getTop(); - outRect.bottom = child.getBottom(); - - ViewParent parent = child.getParent(); - while (parent instanceof ViewGroup && parent != this) { - final ViewGroup group = (ViewGroup) parent; - outRect.left += group.getLeft(); - outRect.right += group.getRight(); - outRect.top += group.getTop(); - outRect.bottom += group.getBottom(); - - parent = group.getParent(); - } - return outRect; - } - - boolean pageUp() { - if (mCurItem > 0) { - setCurrentItem(mCurItem - 1, true); - return true; - } - return false; - } - - boolean pageDown() { - if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) { - setCurrentItem(mCurItem + 1, true); - return true; - } - return false; + public void setPages(List components) { + this.mComponents = components; } /** - * We only want the current page that is being shown to be focusable. + * 设置动画接口 + * + * @param pageTransformer 动画接口实现类 */ - @Override - public void addFocusables(ArrayList views, int direction, int focusableMode) { - final int focusableCount = views.size(); - - final int descendantFocusability = getDescendantFocusability(); - - if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { - for (int i = 0; i < getChildCount(); i++) { - final View child = getChildAt(i); - if (child.getVisibility() == VISIBLE) { - ItemInfo ii = infoForChild(child); - if (ii != null && ii.position == mCurItem) { - child.addFocusables(views, direction, focusableMode); - } - } - } - } - - // we add ourselves (if focusable) in all cases except for when we are - // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is - // to avoid the focus search finding layouts when a more precise search - // among the focusable children would be more interesting. - if ( - descendantFocusability != FOCUS_AFTER_DESCENDANTS || - // No focusable descendants - (focusableCount == views.size())) { - // Note that we can't call the superclass here, because it will - // add all views in. So we need to do the same thing View does. - if (!isFocusable()) { - return; - } - if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && - isInTouchMode() && !isFocusableInTouchMode()) { - return; - } - if (views != null) { - views.add(this); - } - } + public void setPageTransformer(VerticalViewPager.PageTransformer pageTransformer) { + this.mPageTransformer = pageTransformer; } - /** - * We only want the current page that is being shown to be touchable. - */ - @Override - public void addTouchables(ArrayList views) { - // Note that we don't call super.addTouchables(), which means that - // we don't call View.addTouchables(). This is okay because a ViewPager - // is itself not touchable. - for (int i = 0; i < getChildCount(); i++) { - final View child = getChildAt(i); - if (child.getVisibility() == VISIBLE) { - ItemInfo ii = infoForChild(child); - if (ii != null && ii.position == mCurItem) { - child.addTouchables(views); - } - } + private void onPageScrolled(int position, float offset, int offsetPixels) { + if (mPageTransformer != null) { + onPageTransformer(position, offset, offsetPixels); } } - /** - * We only want the current page that is being shown to be focusable. - */ - @Override - protected boolean onRequestFocusInDescendants(int direction, - Rect previouslyFocusedRect) { - int index; - int increment; - int end; - int count = getChildCount(); - if ((direction & FOCUS_FORWARD) != 0) { - index = 0; - increment = 1; - end = count; - } else { - index = count - 1; - increment = -1; - end = -1; - } - for (int i = index; i != end; i += increment) { - View child = getChildAt(i); - if (child.getVisibility() == VISIBLE) { - ItemInfo ii = infoForChild(child); - if (ii != null && ii.position == mCurItem) { - if (child.requestFocus(direction, previouslyFocusedRect)) { - return true; - } - } - } - } - return false; - } + private void onPageTransformer(int position, float positionOffset, int offsetPixels) { + mOriginalOffset = positionOffset; + this.mCurrentItemPos = position; + this.mItemPosOffset = positionOffset; + this.mItemPosOffsetPixels = offsetPixels; - @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - // Dispatch scroll events from this ViewPager. - if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) { - return super.dispatchPopulateAccessibilityEvent(event); + int realSlidState = getRealSlidState(); + if (realSlidState != SLID_NONE) { + mLastScrollState = realSlidState; } - - // Dispatch all other accessibility events from the current page. - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.getVisibility() == VISIBLE) { - final ItemInfo ii = infoForChild(child); - if (ii != null && ii.position == mCurItem && - child.dispatchPopulateAccessibilityEvent(event)) { - return true; - } - } + switch (mLastScrollState) { + case SLID_LEFT: + scrollLeft(position, positionOffset); + break; + case SLID_RIGHT: + scrollRight(position, positionOffset); + break; + case SLID_LEFT_ELASTIC: + // 向左滑动但未达到临界回弹 + elasticLeft(position, positionOffset); + break; + case SLID_RIGHT_ELASTIC: + // 向右滑动但未达到临界回弹 + elasticRight(position, positionOffset); + break; + default: + break; } - - return false; } - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(); + private void elasticLeft(int position, float positionOffset) { + Component in = mComponents.get(position); + Component out = mComponents.get(position + 1); + mPageTransformer.transformPage(out, mOriginalOffset); + mPageTransformer.transformPage(in, MathUtils.floatToAdd(SCROLL_RIGHT, positionOffset)); } - @Override - protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return generateDefaultLayoutParams(); + private void elasticRight(int position, float positionOffset) { + Component out = mComponents.get(position - 1); + Component in = mComponents.get(position); + mPageTransformer.transformPage(in, MathUtils.floatToSubtract(1, positionOffset)); + mPageTransformer.transformPage(out, MathUtils.floatToSubtract(0, positionOffset)); } - @Override - protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof LayoutParams && super.checkLayoutParams(p); + private void scrollRight(int position, float positionOffset) { + // 从左往右滑动 + Component in = mComponents.get(position - 1); + Component out = mComponents.get(position); + mPageTransformer.transformPage(out, mOriginalOffset); + mPageTransformer.transformPage(in, MathUtils.floatToAdd(SCROLL_RIGHT, positionOffset)); } - @Override - public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new LayoutParams(getContext(), attrs); + private void scrollLeft(int position, float positionOffset) { + Component in = mComponents.get(position + 1); + Component out = mComponents.get(position); + mPageTransformer.transformPage(in, MathUtils.floatToSubtract(1, positionOffset)); + mPageTransformer.transformPage(out, MathUtils.floatToSubtract(0, positionOffset)); } - class MyAccessibilityDelegate extends AccessibilityDelegateCompat { - - @Override - public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(host, event); - event.setClassName(ViewPager.class.getName()); - final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain(); - recordCompat.setScrollable(canScroll()); - if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED - && mAdapter != null) { - recordCompat.setItemCount(mAdapter.getCount()); - recordCompat.setFromIndex(mCurItem); - recordCompat.setToIndex(mCurItem); - } - } - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { - super.onInitializeAccessibilityNodeInfo(host, info); - info.setClassName(ViewPager.class.getName()); - info.setScrollable(canScroll()); - if (internalCanScrollVertically(1)) { - info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); - } - if (internalCanScrollVertically(-1)) { - info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); - } + private int getRealSlidState() { + if (mItemPosOffset == 1) { + return SLID_NONE; } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if (super.performAccessibilityAction(host, action, args)) { - return true; + if (mCurrentState == PageSlider.SLIDING_STATE_DRAGGING) { + if (mItemPosOffsetPixels > 0) { + return SLID_LEFT; + } else if (mItemPosOffsetPixels < 0) { + return SLID_RIGHT; } - switch (action) { - case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { - if (internalCanScrollVertically(1)) { - setCurrentItem(mCurItem + 1); - return true; - } + } else if (mCurrentState == PageSlider.SLIDING_STATE_SETTLING) { + if (mCurrentItemPos != getCurrentPage()) { + if (mItemPosOffsetPixels > 0) { + return SLID_RIGHT; + } else if (mItemPosOffsetPixels < 0) { + return SLID_LEFT; } - return false; - case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { - if (internalCanScrollVertically(-1)) { - setCurrentItem(mCurItem - 1); - return true; - } + } else { + if (mItemPosOffsetPixels > 0) { + return SLID_LEFT_ELASTIC; + } else if (mItemPosOffsetPixels < 0) { + return SLID_RIGHT_ELASTIC; } - return false; } - return false; - } - - private boolean canScroll() { - return (mAdapter != null) && (mAdapter.getCount() > 1); - } - } - - private class PagerObserver extends DataSetObserver { - @Override - public void onChanged() { - dataSetChanged(); - } - - @Override - public void onInvalidated() { - dataSetChanged(); } + return SLID_NONE; } /** - * Layout parameters that should be supplied for views added to a - * ViewPager. + * PageSlide的动画接口 + * + * @since 2021-04-12 */ - public static class LayoutParams extends ViewGroup.LayoutParams { - /** - * true if this view is a decoration on the pager itself and not - * a view supplied by the adapter. - */ - public boolean isDecor; - - /** - * Gravity setting for use on decor views only: - * Where to position the view page within the overall ViewPager - * container; constants are defined in {@link android.view.Gravity}. - */ - public int gravity; - - /** - * Width as a 0-1 multiplier of the measured pager width - */ - float heightFactor = 0.f; - - /** - * true if this view was added during layout and needs to be measured - * before being positioned. - */ - boolean needsMeasure; - + public interface PageTransformer { /** - * Adapter position this view is for if !isDecor + * 动画接口 + * + * @param page 子组件 + * @param position position */ - int position; - - /** - * Current child index within the ViewPager that this view occupies - */ - int childIndex; - - public LayoutParams() { - super(FILL_PARENT, FILL_PARENT); - } - - public LayoutParams(Context context, AttributeSet attrs) { - super(context, attrs); - - final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); - gravity = a.getInteger(0, Gravity.TOP); - a.recycle(); - } - } - - static class ViewPositionComparator implements Comparator { - @Override - public int compare(View lhs, View rhs) { - final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); - final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); - if (llp.isDecor != rlp.isDecor) { - return llp.isDecor ? 1 : -1; - } - return llp.position - rlp.position; - } + void transformPage(Component page, float position); } } diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/AccordionTransformer.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/AccordionTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..4df8c0a6241f784887626c4d8a815daa582610d5 --- /dev/null +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/AccordionTransformer.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.transformer; + +import ohos.agp.components.Component; + +/** + * Accordion Transformer + * + * @author shetaotao + * @since 2021-04-26 + */ +public class AccordionTransformer extends BaseTransformer { + @Override + public void onTransform(Component component, float position) { + component.setPivotX(position < (float) 0 ? 0.0F : (float) component.getWidth()); + component.setScaleX(position < (float) 0 ? MathUtils.floatToAdd(1.0F, position) + : MathUtils.floatToSubtract(1.0F, position)); + } +} diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/BaseTransformer.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/BaseTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..3bf9ff5c60a8c066aca7f5b3864d797acb9de3d5 --- /dev/null +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/BaseTransformer.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.transformer; + +import fr.castorflex.android.verticalviewpager.VerticalViewPager; +import ohos.agp.components.Component; + +/** + * Base transformer + * + * @author shetaotao + * @since 2021-04-26 + */ +public abstract class BaseTransformer implements VerticalViewPager.PageTransformer { + private static final float SCROLL_RIGHT = -1.0F; + private static final float SCROLL_LEFT = 1.0F; + + @Override + public void transformPage(Component component, float position) { + float clampedPosition = clampPosition(position); + onPreTransform(component, clampedPosition); + onTransform(component, clampedPosition); + onPostTransform(component, clampedPosition); + } + + /** + * PreTransform + * + * @param component component + * @param position position + */ + protected void onPreTransform(Component component, float position) { + float width = (float) component.getWidth(); + component.setRotation(0.0F); + component.setScaleX(1.0F); + component.setScaleY(1.0F); + component.setPivotX(0.0F); + component.setPivotY(0.0F); + component.setTranslationY(0.0F); + component.setTranslationX(isPagingEnabled() ? 0.0F : -width * position); + if (hideOffscreenPages()) { + if (position <= SCROLL_RIGHT || position >= SCROLL_LEFT) { + component.setAlpha(0f); + } else { + component.setAlpha(1f); + } + component.setEnabled(false); + } else { + component.setEnabled(true); + component.setAlpha(1.0F); + } + } + + private float clampPosition(float position) { + float clampPosition; + if (position <= SCROLL_RIGHT) { + clampPosition = SCROLL_RIGHT; + } else if (position >= 1F) { + clampPosition = 1.0F; + } else if (Float.isNaN(position)) { + clampPosition = 0.0F; + } else { + clampPosition = position; + } + return clampPosition; + } + + /** + * Is paging enabled + * + * @return false + */ + public boolean isPagingEnabled() { + return false; + } + + /** + * Hide Off screen Pages + * + * @return true + */ + protected boolean hideOffscreenPages() { + return true; + } + + /** + * PostTransform + * + * @param component component + * @param position position + */ + protected void onPostTransform(Component component, float position) { + } + + /** + * Abstract transform + * + * @param component component + * @param position position + */ + protected abstract void onTransform(Component component, float position); +} diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/MathUtils.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/MathUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..f889b9991594183e5f3ede9ac04ec25f9e07e3c9 --- /dev/null +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/MathUtils.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.transformer; + +import java.math.BigDecimal; +import java.text.DecimalFormat; + +/** + * 精确计算 + * + * @author shetaotao + * @since 2021-04-27 + */ +public class MathUtils { + private MathUtils() { + } + + /** + * Subtract + * + * @param f1 float1 + * @param f2 float2 + * @return subtract value + */ + public static float floatToSubtract(float f1, float f2) { + BigDecimal b1 = BigDecimal.valueOf(f1); + BigDecimal b2 = BigDecimal.valueOf(f2); + DecimalFormat df = new DecimalFormat("0.00000"); + return Float.valueOf(df.format(b1.subtract(b2))); + } + + /** + * Addition + * + * @param f1 float1 + * @param f2 float2 + * @return Addition value + */ + public static float floatToAdd(float f1, float f2) { + BigDecimal b1 = BigDecimal.valueOf(f1); + BigDecimal b2 = BigDecimal.valueOf(f2); + DecimalFormat df = new DecimalFormat("0.00000"); + return Float.valueOf(df.format(b1.add(b2))); + } +} diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/TransformerItem.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/TransformerItem.java new file mode 100644 index 0000000000000000000000000000000000000000..4a66b2407c8dcb51f8132c6f42f0882cfd19da69 --- /dev/null +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/TransformerItem.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.transformer; + +import fr.castorflex.android.verticalviewpager.VerticalViewPager; + +/** + * 扩展了PageSlide的动画接口 + * + * @author shetaotao + * @since 2021-04-26 + */ +public class TransformerItem { + private Class mClass; + + /** + * Transformer item + * + * @param itemClass Item class + */ + public TransformerItem(Class itemClass) { + this.mClass = itemClass; + } + + /** + * Get page transformer + * + * @return Page transformer + */ + public VerticalViewPager.PageTransformer getPageTransformer() { + try { + return mClass.newInstance(); + } catch (IllegalAccessException e) { + return new AccordionTransformer(); + } catch (InstantiationException e) { + return new AccordionTransformer(); + } + } +} diff --git a/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/ZoomOutSlideTransformer.java b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/ZoomOutSlideTransformer.java new file mode 100644 index 0000000000000000000000000000000000000000..bad55a96a5cabeea2ee2ffd5b30926694f2890c9 --- /dev/null +++ b/library/src/main/java/fr/castorflex/android/verticalviewpager/transformer/ZoomOutSlideTransformer.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain an copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.castorflex.android.verticalviewpager.transformer; + +import ohos.agp.components.Component; + +/** + * 页面缩放动画接口 + * + * @author shetaotao + * @since 2021-04-26 + */ +public class ZoomOutSlideTransformer extends BaseTransformer { + private static final float ALPHA = 0.14999998F; + private static final float ALPHA_MAX = 0.85F; + private static final float ALPHA_DEFAULT = 0.7F; + private static final float SCALE_MAX = 0.85F; + private static final float PIVOT_X = 0.5F; + private static final float PIVOT_Y = 0.5F; + private static final float HALF = 2.0F; + private static final float SCROLL_RIGHT = -1.0F; + private static final float SCROLL_LEFT = 1.0F; + + @Override + protected void onTransform(Component component, float position) { + if (position >= SCROLL_RIGHT || position <= SCROLL_LEFT) { + float height = (float) component.getHeight(); + float width = (float) component.getWidth(); + float scaleFactor = Math.max(SCALE_MAX, MathUtils.floatToSubtract(SCROLL_LEFT, Math.abs(position))); + float vertMargin = height * MathUtils.floatToSubtract(SCROLL_LEFT, scaleFactor) / HALF; + float horzMargin = width * MathUtils.floatToSubtract(SCROLL_LEFT, scaleFactor) / HALF; + component.setPivotY(PIVOT_X * height); + component.setPivotX(PIVOT_Y * width); + component.setTranslationX(position < (float) 0 + ? MathUtils.floatToSubtract(horzMargin, vertMargin / HALF) + : MathUtils.floatToAdd(-horzMargin, vertMargin / HALF)); + component.setScaleX(scaleFactor); + component.setScaleY(scaleFactor); + component.setAlpha(MathUtils.floatToAdd(ALPHA_DEFAULT, + MathUtils.floatToSubtract(scaleFactor, ALPHA_MAX) / ALPHA / HALF)); + } + } +} diff --git a/library/src/main/resources/base/element/string.json b/library/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..6c298286373e6266fd910aac81429792f08df437 --- /dev/null +++ b/library/src/main/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "Library" + } + ] +} diff --git a/mvn_push.gradle b/mvn_push.gradle deleted file mode 100644 index 92fdb4d8fec9c4747c9b6385b82c3cbd184eba0d..0000000000000000000000000000000000000000 --- a/mvn_push.gradle +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2013 Chris Banes - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'maven' -apply plugin: 'signing' - -def isReleaseBuild() { - return version.contains("SNAPSHOT") == false -} - -def getReleaseRepositoryUrl() { - return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - -def getSnapshotRepositoryUrl() { - return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL - : "https://oss.sonatype.org/content/repositories/snapshots/" -} - -def getRepositoryUsername() { - return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" -} - -def getRepositoryPassword() { - return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" -} - -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - pom.artifactId = POM_ARTIFACT_ID - - repository(url: getReleaseRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - snapshotRepository(url: getSnapshotRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - - pom.project { - name POM_NAME - packaging POM_PACKAGING - description POM_DESCRIPTION - url POM_URL - - scm { - url POM_SCM_URL - connection POM_SCM_CONNECTION - developerConnection POM_SCM_DEV_CONNECTION - } - - licenses { - license { - name POM_LICENCE_NAME - url POM_LICENCE_URL - distribution POM_LICENCE_DIST - } - } - - developers { - developer { - id POM_DEVELOPER_ID - name POM_DEVELOPER_NAME - } - } - } - } - } - } - - signing { - required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } - sign configurations.archives - } - - task androidJavadocs(type: Javadoc) { - source = android.sourceSets.main.allJava - } - - task androidJavadocsJar(type: Jar) { - classifier = 'javadoc' - from androidJavadocs.destinationDir - } - - task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.allSource - } - - artifacts { - archives androidSourcesJar - archives androidJavadocsJar - } -} \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle deleted file mode 100644 index ef7c77369bd65d984ee64eeb90da03c2db032f48..0000000000000000000000000000000000000000 --- a/sample/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -apply plugin: 'android' - -repositories { - mavenCentral() -} - -dependencies { - compile project(':library') - compile 'com.android.support:support-v13:19.0.0' -} - -android { - compileSdkVersion 19 - buildToolsVersion "19.0.0" - - defaultConfig { - minSdkVersion 14 - targetSdkVersion 19 - versionName project.VERSION_NAME - versionCode Integer.parseInt(project.VERSION_CODE) - } - - signingConfigs { - release - } - buildTypes { - release { - signingConfig project.hasProperty('storeFile') ? signingConfigs.release : signingConfigs.debug - } - } -} -if (project.hasProperty('storeFile')) { - android.signingConfigs.release.storeFile = file(storeFile) -} -if (project.hasProperty('keyAlias')) { - android.signingConfigs.release.keyAlias = keyAlias -} -if (project.hasProperty('storePassword')) { - android.signingConfigs.release.storePassword = storePassword -} -if (project.hasProperty('keyPassword')) { - android.signingConfigs.release.keyPassword = keyPassword -} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml deleted file mode 100644 index 6d530ab6d1ac59b12371d0443814eba59e4088fd..0000000000000000000000000000000000000000 --- a/sample/src/main/AndroidManifest.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - diff --git a/sample/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainActivity.java b/sample/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainActivity.java deleted file mode 100644 index 648db98c3045d96e361ba8d072f4bce03d8d2a1c..0000000000000000000000000000000000000000 --- a/sample/src/main/java/fr/castorflex/android/verticalviewpager/sample/MainActivity.java +++ /dev/null @@ -1,144 +0,0 @@ -package fr.castorflex.android.verticalviewpager.sample; - -import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentManager; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.support.v13.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.Locale; - -import fr.castorflex.android.verticalviewpager.VerticalViewPager; - -public class MainActivity extends Activity { - - private static final float MIN_SCALE = 0.75f; - private static final float MIN_ALPHA = 0.75f; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - VerticalViewPager verticalViewPager = (VerticalViewPager) findViewById(R.id.verticalviewpager); - - verticalViewPager.setAdapter(new DummyAdapter(getFragmentManager())); - verticalViewPager.setPageMargin(getResources().getDimensionPixelSize(R.dimen.pagemargin)); - verticalViewPager.setPageMarginDrawable(new ColorDrawable(getResources().getColor(android.R.color.holo_green_dark))); - - verticalViewPager.setPageTransformer(true, new ViewPager.PageTransformer() { - @Override - public void transformPage(View view, float position) { - int pageWidth = view.getWidth(); - int pageHeight = view.getHeight(); - - if (position < -1) { // [-Infinity,-1) - // This page is way off-screen to the left. - view.setAlpha(0); - - } else if (position <= 1) { // [-1,1] - // Modify the default slide transition to shrink the page as well - float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); - float vertMargin = pageHeight * (1 - scaleFactor) / 2; - float horzMargin = pageWidth * (1 - scaleFactor) / 2; - if (position < 0) { - view.setTranslationY(vertMargin - horzMargin / 2); - } else { - view.setTranslationY(-vertMargin + horzMargin / 2); - } - - // Scale the page down (between MIN_SCALE and 1) - view.setScaleX(scaleFactor); - view.setScaleY(scaleFactor); - - // Fade the page relative to its size. - view.setAlpha(MIN_ALPHA + - (scaleFactor - MIN_SCALE) / - (1 - MIN_SCALE) * (1 - MIN_ALPHA)); - - } else { // (1,+Infinity] - // This page is way off-screen to the right. - view.setAlpha(0); - } - } - }); - } - - public class DummyAdapter extends FragmentPagerAdapter { - - public DummyAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public Fragment getItem(int position) { - // getItem is called to instantiate the fragment for the given page. - // Return a PlaceholderFragment (defined as a static inner class below). - return PlaceholderFragment.newInstance(position + 1); - } - - @Override - public int getCount() { - // Show 3 total pages. - return 3; - } - - @Override - public CharSequence getPageTitle(int position) { - Locale l = Locale.getDefault(); - switch (position) { - case 0: - return "PAGE 1"; - case 1: - return "PAGE 2"; - case 2: - return "PAGE 3"; - } - return null; - } - - } - - /** - * A placeholder fragment containing a simple view. - */ - public static class PlaceholderFragment extends Fragment { - /** - * The fragment argument representing the section number for this - * fragment. - */ - private static final String ARG_SECTION_NUMBER = "section_number"; - - /** - * Returns a new instance of this fragment for the given section - * number. - */ - public static PlaceholderFragment newInstance(int sectionNumber) { - PlaceholderFragment fragment = new PlaceholderFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_SECTION_NUMBER, sectionNumber); - fragment.setArguments(args); - return fragment; - } - - public PlaceholderFragment() { - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_layout, container, false); - TextView textView = (TextView) rootView.findViewById(R.id.textview); - textView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER))); - return rootView; - } - - - } - -} diff --git a/sample/src/main/res/drawable-hdpi/ic_launcher.png b/sample/src/main/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 55621cc1074fe21c736a80abdd0837c4e8132bdf..0000000000000000000000000000000000000000 Binary files a/sample/src/main/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/sample/src/main/res/drawable-mdpi/ic_launcher.png b/sample/src/main/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 11ec2068be19999e4826062377ec8cd169c893bf..0000000000000000000000000000000000000000 Binary files a/sample/src/main/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/sample/src/main/res/drawable-xhdpi/ic_launcher.png b/sample/src/main/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index 7c02b784aa5d7e2b7608ee8f96eb387ab3ab87d6..0000000000000000000000000000000000000000 Binary files a/sample/src/main/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/sample/src/main/res/drawable-xxhdpi/ic_launcher.png b/sample/src/main/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 915d9144134970b4366fac25f08ca53571c7dc9b..0000000000000000000000000000000000000000 Binary files a/sample/src/main/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml deleted file mode 100644 index 6e4b605242c789b51132b48b1e42c7a01c77884e..0000000000000000000000000000000000000000 --- a/sample/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_layout.xml b/sample/src/main/res/layout/fragment_layout.xml deleted file mode 100644 index 1cf8f2c87abee81a11883782c14a644e0073552c..0000000000000000000000000000000000000000 --- a/sample/src/main/res/layout/fragment_layout.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml deleted file mode 100644 index d5fae0f72098079882b77f9f3af7bbfcc9e81456..0000000000000000000000000000000000000000 --- a/sample/src/main/res/values/dimens.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 16dp - \ No newline at end of file diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml deleted file mode 100644 index 8ee06093ffa2035c1b6a70445cb606e3d541f8a2..0000000000000000000000000000000000000000 --- a/sample/src/main/res/values/strings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - VerticalViewPager - - diff --git a/settings.gradle b/settings.gradle index c504e934182ddc70f1df254ac96828fd208f54a2..0330f9c23909f6c01f3328c32bc99d015c4d9b3e 100755 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ -include ':sample' -include ':library' +include ':entry', ':Library'