master 47a5fb2db5e9 cached
352 files
1.0 MB
250.9k tokens
1197 symbols
1 requests
Download .txt
Showing preview only (1,182K chars total). Download the full file or copy to clipboard to get everything.
Repository: ksoichiro/Android-ObservableScrollView
Branch: master
Commit: 47a5fb2db5e9
Files: 352
Total size: 1.0 MB

Directory structure:
gitextract_qypqnipg/

├── .editorconfig
├── .gitignore
├── .travis-script.sh
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── build.gradle
├── docs/
│   ├── _data.json
│   ├── _layout.ejs
│   ├── advanced/
│   │   ├── _data.json
│   │   ├── index.md
│   │   ├── sliding-up.md
│   │   └── viewpager.md
│   ├── basic/
│   │   ├── _data.json
│   │   ├── filling-gap.md
│   │   ├── flexible-space-toolbar.md
│   │   ├── flexible-space-with-image.md
│   │   ├── index.md
│   │   ├── parallax-image.md
│   │   ├── show-hide-action-bar.md
│   │   ├── sticky-header.md
│   │   └── translating-toolbar.md
│   ├── contributor/
│   │   ├── _data.json
│   │   ├── ci.md
│   │   ├── index.md
│   │   ├── release.md
│   │   └── update-website.md
│   ├── example/
│   │   ├── _data.json
│   │   ├── android-studio.md
│   │   ├── eclipse.md
│   │   ├── google-play.md
│   │   ├── index.md
│   │   └── wercker.md
│   ├── faq.md
│   ├── overview.md
│   ├── quick-start/
│   │   ├── _data.json
│   │   ├── animation.md
│   │   ├── dependencies.md
│   │   ├── index.md
│   │   └── layout.md
│   └── reference/
│       ├── _data.json
│       ├── environment.md
│       ├── index.md
│       ├── release-notes.md
│       └── supported-widgets.md
├── gradle/
│   ├── gradle-mvn-push.gradle
│   ├── version.gradle
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── gradle.properties
│   ├── res/
│   │   └── .gitkeep
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── lipsum.html
│       │   ├── java/
│       │   │   └── com/
│       │   │       ├── github/
│       │   │       │   └── ksoichiro/
│       │   │       │       └── android/
│       │   │       │           └── observablescrollview/
│       │   │       │               ├── SavedStateTest.java
│       │   │       │               └── test/
│       │   │       │                   ├── GridViewActivity.java
│       │   │       │                   ├── GridViewActivityTest.java
│       │   │       │                   ├── HeaderGridViewActivity.java
│       │   │       │                   ├── HeaderGridViewActivityTest.java
│       │   │       │                   ├── ListViewActivity.java
│       │   │       │                   ├── ListViewActivityTest.java
│       │   │       │                   ├── ListViewScrollFromBottomActivity.java
│       │   │       │                   ├── ListViewScrollFromBottomActivityTest.java
│       │   │       │                   ├── RecyclerViewActivity.java
│       │   │       │                   ├── RecyclerViewActivityTest.java
│       │   │       │                   ├── RecyclerViewScrollFromBottomActivity.java
│       │   │       │                   ├── RecyclerViewScrollFromBottomActivityTest.java
│       │   │       │                   ├── ScrollUtilsTest.java
│       │   │       │                   ├── ScrollViewActivity.java
│       │   │       │                   ├── ScrollViewActivityTest.java
│       │   │       │                   ├── SimpleHeaderRecyclerAdapter.java
│       │   │       │                   ├── SimpleRecyclerAdapter.java
│       │   │       │                   ├── TouchInterceptionGridViewActivity.java
│       │   │       │                   ├── TouchInterceptionGridViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionListViewActivity.java
│       │   │       │                   ├── TouchInterceptionListViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionRecyclerViewActivity.java
│       │   │       │                   ├── TouchInterceptionRecyclerViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionScrollViewActivity.java
│       │   │       │                   ├── TouchInterceptionScrollViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionWebViewActivity.java
│       │   │       │                   ├── TouchInterceptionWebViewActivityTest.java
│       │   │       │                   ├── UiTestUtils.java
│       │   │       │                   ├── ViewPagerTab2Activity.java
│       │   │       │                   ├── ViewPagerTab2ActivityTest.java
│       │   │       │                   ├── ViewPagerTab2GridViewFragment.java
│       │   │       │                   ├── ViewPagerTab2ListViewFragment.java
│       │   │       │                   ├── ViewPagerTab2RecyclerViewFragment.java
│       │   │       │                   ├── ViewPagerTab2ScrollViewFragment.java
│       │   │       │                   ├── ViewPagerTab2WebViewFragment.java
│       │   │       │                   ├── ViewPagerTabActivity.java
│       │   │       │                   ├── ViewPagerTabActivityTest.java
│       │   │       │                   ├── ViewPagerTabListViewFragment.java
│       │   │       │                   ├── ViewPagerTabRecyclerViewFragment.java
│       │   │       │                   ├── ViewPagerTabScrollViewFragment.java
│       │   │       │                   ├── WebViewActivity.java
│       │   │       │                   └── WebViewActivityTest.java
│       │   │       └── google/
│       │   │           └── samples/
│       │   │               └── apps/
│       │   │                   └── iosched/
│       │   │                       └── ui/
│       │   │                           └── widget/
│       │   │                               ├── SlidingTabLayout.java
│       │   │                               └── SlidingTabStrip.java
│       │   └── res/
│       │       ├── color/
│       │       │   └── tab_text_color.xml
│       │       ├── layout/
│       │       │   ├── activity_gridview.xml
│       │       │   ├── activity_listview.xml
│       │       │   ├── activity_recyclerview.xml
│       │       │   ├── activity_scrollview.xml
│       │       │   ├── activity_touchinterception_gridview.xml
│       │       │   ├── activity_touchinterception_listview.xml
│       │       │   ├── activity_touchinterception_recyclerview.xml
│       │       │   ├── activity_touchinterception_scrollview.xml
│       │       │   ├── activity_touchinterception_webview.xml
│       │       │   ├── activity_viewpagertab.xml
│       │       │   ├── activity_viewpagertab2.xml
│       │       │   ├── activity_webview.xml
│       │       │   ├── fragment_gridview.xml
│       │       │   ├── fragment_listview.xml
│       │       │   ├── fragment_recyclerview.xml
│       │       │   ├── fragment_scrollview.xml
│       │       │   ├── fragment_scrollview_noheader.xml
│       │       │   ├── fragment_webview.xml
│       │       │   ├── padding.xml
│       │       │   └── tab_indicator.xml
│       │       └── values/
│       │           ├── colors.xml
│       │           ├── dimens.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── main/
│           └── java/
│               └── com/
│                   └── github/
│                       └── ksoichiro/
│                           └── android/
│                               └── observablescrollview/
│                                   ├── CacheFragmentStatePagerAdapter.java
│                                   ├── ObservableGridView.java
│                                   ├── ObservableListView.java
│                                   ├── ObservableRecyclerView.java
│                                   ├── ObservableScrollView.java
│                                   ├── ObservableScrollViewCallbacks.java
│                                   ├── ObservableWebView.java
│                                   ├── ScrollState.java
│                                   ├── ScrollUtils.java
│                                   ├── Scrollable.java
│                                   └── TouchInterceptionFrameLayout.java
├── samples/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── README.md
│   ├── assets/
│   │   ├── handletouch.html
│   │   └── lipsum.html
│   ├── build.gradle
│   ├── proguard-rules.pro
│   ├── res/
│   │   ├── color/
│   │   │   └── tab_text_color.xml
│   │   ├── drawable/
│   │   │   ├── gradient_header_background.xml
│   │   │   └── sliding_header_overlay.xml
│   │   ├── layout/
│   │   │   ├── activity_about.xml
│   │   │   ├── activity_actionbarcontrolgridview.xml
│   │   │   ├── activity_actionbarcontrollistview.xml
│   │   │   ├── activity_actionbarcontrolrecyclerview.xml
│   │   │   ├── activity_actionbarcontrolscrollview.xml
│   │   │   ├── activity_actionbarcontrolwebview.xml
│   │   │   ├── activity_fillgap3listview.xml
│   │   │   ├── activity_fillgap3recyclerview.xml
│   │   │   ├── activity_fillgap3scrollview.xml
│   │   │   ├── activity_fillgaplistview.xml
│   │   │   ├── activity_fillgaprecyclerview.xml
│   │   │   ├── activity_fillgapscrollview.xml
│   │   │   ├── activity_flexiblespacetoolbarscrollview.xml
│   │   │   ├── activity_flexiblespacetoolbarwebview.xml
│   │   │   ├── activity_flexiblespacewithimagegridview.xml
│   │   │   ├── activity_flexiblespacewithimagelistview.xml
│   │   │   ├── activity_flexiblespacewithimagerecyclerview.xml
│   │   │   ├── activity_flexiblespacewithimagescrollview.xml
│   │   │   ├── activity_flexiblespacewithimagewithviewpagertab.xml
│   │   │   ├── activity_flexiblespacewithimagewithviewpagertab2.xml
│   │   │   ├── activity_fragmentactionbarcontrol.xml
│   │   │   ├── activity_fragmenttransition.xml
│   │   │   ├── activity_handletouchgridview.xml
│   │   │   ├── activity_handletouchlistview.xml
│   │   │   ├── activity_handletouchrecyclerview.xml
│   │   │   ├── activity_handletouchscrollview.xml
│   │   │   ├── activity_handletouchwebview.xml
│   │   │   ├── activity_main.xml
│   │   │   ├── activity_parallaxtoolbargridview.xml
│   │   │   ├── activity_parallaxtoolbarlistview.xml
│   │   │   ├── activity_parallaxtoolbarscrollview.xml
│   │   │   ├── activity_slidingupgridview.xml
│   │   │   ├── activity_slidinguplistview.xml
│   │   │   ├── activity_slidinguprecyclerview.xml
│   │   │   ├── activity_slidingupscrollview.xml
│   │   │   ├── activity_slidingupwebview.xml
│   │   │   ├── activity_stickyheaderlistview.xml
│   │   │   ├── activity_stickyheaderrecyclerview.xml
│   │   │   ├── activity_stickyheaderscrollview.xml
│   │   │   ├── activity_stickyheaderwebview.xml
│   │   │   ├── activity_toolbarcontrolgridview.xml
│   │   │   ├── activity_toolbarcontrollistview.xml
│   │   │   ├── activity_toolbarcontrolrecyclerview.xml
│   │   │   ├── activity_toolbarcontrolscrollview.xml
│   │   │   ├── activity_toolbarcontrolwebview.xml
│   │   │   ├── activity_viewpagertab.xml
│   │   │   ├── activity_viewpagertab2.xml
│   │   │   ├── activity_viewpagertabfragment.xml
│   │   │   ├── divider.xml
│   │   │   ├── fragment_actionbarcontrollistview.xml
│   │   │   ├── fragment_flexiblespacewithimagegridview.xml
│   │   │   ├── fragment_flexiblespacewithimagelistview.xml
│   │   │   ├── fragment_flexiblespacewithimagerecyclerview.xml
│   │   │   ├── fragment_flexiblespacewithimagescrollview.xml
│   │   │   ├── fragment_fragmenttransition_default.xml
│   │   │   ├── fragment_fragmenttransition_second.xml
│   │   │   ├── fragment_gridview.xml
│   │   │   ├── fragment_listview.xml
│   │   │   ├── fragment_recyclerview.xml
│   │   │   ├── fragment_scrollview.xml
│   │   │   ├── fragment_scrollview_noheader.xml
│   │   │   ├── fragment_scrollviewwithfab.xml
│   │   │   ├── fragment_viewpagertabfragment_parent.xml
│   │   │   ├── fragment_webview.xml
│   │   │   ├── gradient_header.xml
│   │   │   ├── list_item_handletouch.xml
│   │   │   ├── list_item_main.xml
│   │   │   ├── padding.xml
│   │   │   ├── recycler_header.xml
│   │   │   └── tab_indicator.xml
│   │   ├── layout-v11/
│   │   │   └── tab_indicator.xml
│   │   ├── menu/
│   │   │   └── menu_main.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimens.xml
│   │   │   ├── strings.xml
│   │   │   ├── strings_license.xml
│   │   │   └── styles.xml
│   │   ├── values-ar/
│   │   │   └── strings.xml
│   │   └── values-w820dp/
│   │       └── dimens.xml
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── github/
│       │               └── ksoichiro/
│       │                   └── app/
│       │                       └── ApplicationTest.java
│       └── main/
│           └── java/
│               └── com/
│                   ├── github/
│                   │   └── ksoichiro/
│                   │       └── android/
│                   │           └── observablescrollview/
│                   │               └── samples/
│                   │                   ├── AboutActivity.java
│                   │                   ├── ActionBarControlGridViewActivity.java
│                   │                   ├── ActionBarControlListViewActivity.java
│                   │                   ├── ActionBarControlRecyclerViewActivity.java
│                   │                   ├── ActionBarControlScrollViewActivity.java
│                   │                   ├── ActionBarControlWebViewActivity.java
│                   │                   ├── BaseActivity.java
│                   │                   ├── BaseFragment.java
│                   │                   ├── FillGap2BaseActivity.java
│                   │                   ├── FillGap2ListViewActivity.java
│                   │                   ├── FillGap2RecyclerViewActivity.java
│                   │                   ├── FillGap2ScrollViewActivity.java
│                   │                   ├── FillGap3BaseActivity.java
│                   │                   ├── FillGap3ListViewActivity.java
│                   │                   ├── FillGap3RecyclerViewActivity.java
│                   │                   ├── FillGap3ScrollViewActivity.java
│                   │                   ├── FillGapBaseActivity.java
│                   │                   ├── FillGapListViewActivity.java
│                   │                   ├── FillGapRecyclerViewActivity.java
│                   │                   ├── FillGapScrollViewActivity.java
│                   │                   ├── FlexibleSpaceToolbarScrollViewActivity.java
│                   │                   ├── FlexibleSpaceToolbarWebViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageBaseFragment.java
│                   │                   ├── FlexibleSpaceWithImageGridViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageGridViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageListViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageListViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageRecyclerViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageRecyclerViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageScrollViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageScrollViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageWithViewPagerTab2Activity.java
│                   │                   ├── FlexibleSpaceWithImageWithViewPagerTabActivity.java
│                   │                   ├── FragmentActionBarControlListViewActivity.java
│                   │                   ├── FragmentActionBarControlListViewFragment.java
│                   │                   ├── FragmentTransitionActivity.java
│                   │                   ├── FragmentTransitionDefaultFragment.java
│                   │                   ├── FragmentTransitionSecondFragment.java
│                   │                   ├── HandleTouchGridViewActivity.java
│                   │                   ├── HandleTouchListViewActivity.java
│                   │                   ├── HandleTouchRecyclerViewActivity.java
│                   │                   ├── HandleTouchScrollViewActivity.java
│                   │                   ├── HandleTouchWebViewActivity.java
│                   │                   ├── MainActivity.java
│                   │                   ├── ParallaxToolbarGridViewActivity.java
│                   │                   ├── ParallaxToolbarListViewActivity.java
│                   │                   ├── ParallaxToolbarScrollViewActivity.java
│                   │                   ├── ScrollFromBottomListViewActivity.java
│                   │                   ├── ScrollFromBottomRecyclerViewActivity.java
│                   │                   ├── SimpleHeaderRecyclerAdapter.java
│                   │                   ├── SimpleRecyclerAdapter.java
│                   │                   ├── SlidingUpBaseActivity.java
│                   │                   ├── SlidingUpGridViewActivity.java
│                   │                   ├── SlidingUpListViewActivity.java
│                   │                   ├── SlidingUpRecyclerViewActivity.java
│                   │                   ├── SlidingUpScrollViewActivity.java
│                   │                   ├── SlidingUpWebViewActivity.java
│                   │                   ├── StickyHeaderListViewActivity.java
│                   │                   ├── StickyHeaderRecyclerViewActivity.java
│                   │                   ├── StickyHeaderScrollViewActivity.java
│                   │                   ├── StickyHeaderWebViewActivity.java
│                   │                   ├── ToolbarControlBaseActivity.java
│                   │                   ├── ToolbarControlGridViewActivity.java
│                   │                   ├── ToolbarControlListViewActivity.java
│                   │                   ├── ToolbarControlRecyclerViewActivity.java
│                   │                   ├── ToolbarControlScrollViewActivity.java
│                   │                   ├── ToolbarControlWebViewActivity.java
│                   │                   ├── ViewPagerTab2Activity.java
│                   │                   ├── ViewPagerTab2GridViewFragment.java
│                   │                   ├── ViewPagerTab2ListViewFragment.java
│                   │                   ├── ViewPagerTab2RecyclerViewFragment.java
│                   │                   ├── ViewPagerTab2ScrollViewFragment.java
│                   │                   ├── ViewPagerTab2WebViewFragment.java
│                   │                   ├── ViewPagerTabActivity.java
│                   │                   ├── ViewPagerTabFragmentActivity.java
│                   │                   ├── ViewPagerTabFragmentGridViewFragment.java
│                   │                   ├── ViewPagerTabFragmentListViewFragment.java
│                   │                   ├── ViewPagerTabFragmentParentFragment.java
│                   │                   ├── ViewPagerTabFragmentRecyclerViewFragment.java
│                   │                   ├── ViewPagerTabFragmentScrollViewFragment.java
│                   │                   ├── ViewPagerTabFragmentWebViewFragment.java
│                   │                   ├── ViewPagerTabGridViewFragment.java
│                   │                   ├── ViewPagerTabListViewActivity.java
│                   │                   ├── ViewPagerTabListViewFragment.java
│                   │                   ├── ViewPagerTabRecyclerViewFragment.java
│                   │                   ├── ViewPagerTabScrollViewActivity.java
│                   │                   ├── ViewPagerTabScrollViewFragment.java
│                   │                   ├── ViewPagerTabScrollViewWithFabActivity.java
│                   │                   └── ViewPagerTabScrollViewWithFabFragment.java
│                   └── google/
│                       └── samples/
│                           └── apps/
│                               └── iosched/
│                                   └── ui/
│                                       └── widget/
│                                           ├── SlidingTabLayout.java
│                                           └── SlidingTabStrip.java
├── settings.gradle
├── website/
│   ├── .bowerrc
│   ├── .gitignore
│   ├── bower.json
│   ├── gulpfile.js
│   ├── harp.json
│   ├── package.json
│   └── public/
│       ├── 404.ejs
│       ├── _data.json
│       ├── _footer.ejs
│       ├── _head.ejs
│       ├── _layout.ejs
│       ├── _nav.ejs
│       ├── browserconfig.xml
│       ├── css/
│       │   ├── _code.less
│       │   ├── _colors.less
│       │   ├── _fonts.less
│       │   ├── _footer.less
│       │   ├── _layout.less
│       │   ├── _misc.less
│       │   ├── _mixins.less
│       │   ├── _navbar.less
│       │   ├── _roboto-fonts.less
│       │   ├── _sidebar.less
│       │   ├── _site-top.less
│       │   └── main.less
│       ├── index.ejs
│       ├── js/
│       │   └── main.coffee
│       └── manifest.json
└── wercker.yml

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{.travis.yml,.travis-script.sh,*.json,*.coffee,*.less}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false


================================================
FILE: .gitignore
================================================
.gradle
*.iml
*.keystore
/local.properties
private.properties
/.idea/
.DS_Store
/build
bin/
gen/
libs/
aarDependencies/
.project
.classpath
project.properties
*.swp


================================================
FILE: .travis-script.sh
================================================
#!/bin/bash

echo "TEST_TARGET=${TEST_TARGET}"
echo "TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST}"
echo "TRAVIS_BRANCH=${TRAVIS_BRANCH}"

if [ "$TEST_TARGET" = "android" ]; then
  # Release build type is only for Google Play store currently,
  # which resolve dependency from Maven Central.
  # This causes build errors while developing a new feature, so disable release build.
  ./gradlew --full-stacktrace assembleDevDebug :library:connectedCheck
elif [ "$TEST_TARGET" = "website" ]; then
  if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ ! -z "$GH_TOKEN" ]; then
    echo "Update website..."
    pushd website > /dev/null 2>&1
    npm run deploy
    popd > /dev/null 2>&1
  fi
fi


================================================
FILE: .travis.yml
================================================
language: android
sudo: false
env:
  global:
  - GIT_COMMITTER_NAME=ksoichiro
  - GIT_COMMITTER_EMAIL=soichiro.kashima@gmail.com
  - GIT_AUTHOR_NAME=ksoichiro
  - GIT_AUTHOR_EMAIL=soichiro.kashima@gmail.com
  - secure: Iw0mIseFZ6M/HGi/ERPBT4fabx0G1OVeHCbu6ANoVybO8yHBRHHuUc4pdZOOtEi+Ce/4a5TPZXbGPIVMZrN1ewS3uDAHsEFjmtehsqjk5iKXapvy04dwLsX9jCsQNl0n5679tRZ2eXUGqyVSddc5pIyWwJAGgBmnM/SHDaRy4YA=
  matrix:
  - TEST_TARGET=android
  - TEST_TARGET=website
cache:
  directories:
  - website/node_modules
  - website/bower_components
install:
- true && ([ "$TEST_TARGET" != "website" ] || (cd website && npm install && cd ..))
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=tools)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=build-tools-23.0.2)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=android-19)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=android-21)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=android-22)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=android-23)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=sys-img-armeabi-v7a-android-19)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=extra-android-support)
- true && ([ "$TEST_TARGET" != "android" ] || android-update-sdk --accept-licenses='android-sdk-license-.+' --components=extra-android-m2repository)
before_script:
- true && ([ "$TEST_TARGET" != "android" ] || (echo no | android create avd --force -n test -t android-19 --abi default/armeabi-v7a))
- true && ([ "$TEST_TARGET" != "android" ] || emulator -avd test -no-skin -no-audio -no-window &)
- true && ([ "$TEST_TARGET" != "android" ] || android-wait-for-emulator)
script:
- "/bin/bash .travis-script.sh"
after_success:
- true && ([ "$TEST_TARGET" != "android" ] || ./gradlew :library:coveralls)


================================================
FILE: CONTRIBUTING.md
================================================
# Thank you for your contribution!

Any contributions will be greatly appreciated.

Before submitting a new issue, please check the following guideline.

## Describe your issue as much as possible

The library itself only provides the scroll information,
and creating awesome scrolling effects depends deeply on how you use it: layout, offset calculation to animate views, etc.

Therefore, if you find an issue, please describe not only the issue itself but also the following information:

### If you find it in the sample app of this project

* Required
    * Activity name
    * Operation to produce the issue
    * Modified code
        * If you modified some codes in the sample, it should be described with modified codes
* Preferred
    * Version (git commit hash) of the codes
    * Android OS version
    * device
        * Nexus5, x86 emulator, etc.

### If you find it in your app

* Required
    * Operation to produce the issue
    * Related code
        * Without the related codes, I can't say anything.  
          Screenshot / movie is useful to understand the issue,
          but not enough to discuss the cause of the issue.
* Preferred
    * Version of the library
    * Android OS version
    * device
        * Nexus5, x86 emulator, etc.


================================================
FILE: LICENSE.txt
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   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.


================================================
FILE: README.md
================================================
# Android-ObservableScrollView

[![Build Status](http://img.shields.io/travis/ksoichiro/Android-ObservableScrollView.svg?style=flat)](https://travis-ci.org/ksoichiro/Android-ObservableScrollView)
[![Coverage Status](https://img.shields.io/coveralls/ksoichiro/Android-ObservableScrollView/master.svg?style=flat)](https://coveralls.io/r/ksoichiro/Android-ObservableScrollView?branch=master)
[![Maven Central](http://img.shields.io/maven-central/v/com.github.ksoichiro/android-observablescrollview.svg?style=flat)](https://github.com/ksoichiro/Android-ObservableScrollView/releases/latest)
[![API](https://img.shields.io/badge/API-9%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=9)
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Android--ObservableScrollView-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1136)

Android library to observe scroll events on scrollable views.  
It's easy to interact with the Toolbar introduced in Android 5.0 Lollipop  and may be helpful to implement look and feel of Material Design apps.

![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo12.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo10.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo11.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo13.gif)

![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo1.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo2.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo3.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo4.gif)

![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo5.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo6.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo7.gif)
![](https://raw.githubusercontent.com/ksoichiro/Android-ObservableScrollView/master/samples/images/demo8.gif)


## Examples

### Download from Google Play

<a href="https://play.google.com/store/apps/details?id=com.github.ksoichiro.android.observablescrollview.samples2"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" height="50px"/></a>

Please note that the app on the Play store is not always the latest version.

### Download from wercker

If you are a wercker user, you can download the latest build artifact.  
[See here for details](docs/example/wercker.md).

[![wercker status](https://app.wercker.com/status/8d1e27d9f4a662b25dbe70402733582b/m/master "wercker status")](https://app.wercker.com/project/bykey/8d1e27d9f4a662b25dbe70402733582b)

### Install manually

Just clone and execute `installDevDebug` task with Gradle.  
[See here for details](docs/example/android-studio.md).

## Usage

1. Add `com.github.ksoichiro:android-observablescrollview` to your `dependencies` in `build.gradle`.
1. Add `ObservableListView` or other views you'd like to use.
1. Write some animation codes to the callbacks such as `onScrollChanged`, `onUpOrCancelMotionEvent`, etc.

See [the quick start guide for details](docs/quick-start/index.md),
and [the documentation](docs/overview.md) for further more.

## Reference

* [Supported widgets](docs/reference/supported-widgets.md)
* [Environment](docs/reference/environment.md)
* [Release notes](docs/reference/release-notes.md)
* [FAQ](docs/faq.md)

## Apps that use this library
[![Badge](http://www.libtastic.com/static/osbadges/4.png)](http://www.libtastic.com/technology/4/)

* [Jair Player](https://play.google.com/store/apps/details?id=aj.jair.music) by Akshay Chordiya
* [My Gradle](https://play.google.com/store/apps/details?id=se.project.generic.mygradle) by Erick Chavez Alcarraz
* [ThemeDIY](https://play.google.com/store/apps/details?id=net.darkion.theme.maker) by Darkion Avey
* [{Soft} Skills](https://play.google.com/store/apps/details?id=com.fanaticdevs.androider) by Fanatic Devs

If you're using this library in your app and you'd like to list it here,  
please let me know via [email](mailto:soichiro.kashima@gmail.com) or [pull requests](https://github.com/ksoichiro/Android-ObservableScrollView/pulls) or [issues](https://github.com/ksoichiro/Android-ObservableScrollView/issues).


## Contributions

Any contributions are welcome!  
Please check the [FAQ](docs/faq.md) and [contributing guideline](https://github.com/ksoichiro/Android-ObservableScrollView/tree/master/CONTRIBUTING.md) before submitting a new issue.


## Developed By

* Soichiro Kashima - [soichiro.kashima@gmail.com](mailto:soichiro.kashima@gmail.com)


## Thanks

* Inspired by `ObservableScrollView` in [romannurik-code](https://code.google.com/p/romannurik-code/).


## License

```license
Copyright 2014 Soichiro Kashima

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.
```


================================================
FILE: build.gradle
================================================
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.github.ksoichiro:gradle-eclipse-aar-plugin:0.1.1'
        // Related issue: https://code.google.com/p/android/issues/detail?id=192875
        classpath 'org.jacoco:org.jacoco.core:0.7.5.201505241946'
    }
}

allprojects {
    group = GROUP
    version = VERSION_NAME
    repositories {
        mavenCentral()
    }
}

subprojects {
    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:1.5.0'
            classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.1.0'
        }
    }
}

apply plugin: 'com.github.ksoichiro.eclipse.aar'

eclipseAar {
    projectNamePrefix = 'observablescrollview-'
    cleanLibsDirectoryEnabled = true
}


================================================
FILE: docs/_data.json
================================================
{
  "overview": {
    "title": "Overview"
  },
  "faq": {
    "title": "FAQ"
  }
}


================================================
FILE: docs/_layout.ejs
================================================
<!DOCTYPE html>
<html prefix="og: http://ogp.me/ns#">
<head>
<%- partial("../_head", { title: title, ogType: "article" }) %>
</head>
<body>

<%- partial("../_nav") %>

<div class="container">
<p class="visible-xs">
    <button type="button" class="btn-sidebar-toggle" data-toggle="offcanvas">Show menu</button>
</p>
<div id="grid-content">
<div id="sidebar">
    <ul>
        <li><ul><li class="topic"><a href="<%- baseUrl %>/docs/overview">Overview</a></li></ul></li>
        <% for (var sectionSlug in public._data) { %>
            <% if (sectionSlug == "index") { continue; } %>
            <li>
                <h4 class="section"><a href="<%- baseUrl %>/docs/<%- sectionSlug %>/"><%- public._data[sectionSlug].title %></a></h4>
                <ul>
                    <% for (var topicSlug in public.docs[sectionSlug]._data) { %>
                        <% if (topicSlug !== "index") { %>
                            <li class="topic"><a href="<%- baseUrl %>/docs/<%- sectionSlug %>/<%- topicSlug %>"><%- public.docs[sectionSlug]._data[topicSlug].title %></a></li>
                        <% } %>
                    <% } %>
                </ul>
            </li>
        <% } %>
    </ul>
</div>
<div id="sidebar-main-content">
<%- yield %>
</div>
</div>
</div>

<%- partial("../_footer") %>
</body>
</html>


================================================
FILE: docs/advanced/_data.json
================================================
{
  "index": {
    "title": "Advanced techniques"
  },
  "sliding-up": {
    "title": "Sliding up pattern"
  },
  "viewpager": {
    "title": "ViewPager pattern"
  }
}


================================================
FILE: docs/advanced/index.md
================================================
# Advanced techniques

This section describes advanced scrolling techniques.  
When you've done this topic, you could be be an expert of handling scrolls!  
I'd appreciate it if you could suggest new patterns or improvements of the library.

1. [Sliding up pattern](../../docs/advanced/sliding-up.md)
1. [ViewPager pattern](../../docs/advanced/viewpager.md)

[Next: Sliding up pattern &raquo;](../../docs/advanced/sliding-up.md)


================================================
FILE: docs/advanced/sliding-up.md
================================================
# Sliding up pattern

This topic describes how to slide a panel from the bottom like Google's "Map" app,
which are implemented in the following examples.

* SlidingUpBaseActivity
* SlidingUpGridViewActivity
* SlidingUpListViewActivity
* SlidingUpRecyclerViewActivity
* SlidingUpScrollViewActivity
* SlidingUpWebViewActivity

---

Coming soon...

[Next: ViewPager pattern &raquo;](../../docs/advanced/viewpager.md)


================================================
FILE: docs/advanced/viewpager.md
================================================
# ViewPager pattern

This topic describes how to integrate scrollable views with ViewPager,
which are implemented in the following examples.

* ViewPagerTab2Activity
* ViewPagerTabActivity
* ViewPagerTabFragmentActivity
* ViewPagerTabListViewActivity
* ViewPagerTabScrollViewActivity

---

Coming soon...


================================================
FILE: docs/basic/_data.json
================================================
{
  "index": {
    "title": "Basic techniques"
  },
  "show-hide-action-bar": {
    "title": "Show and hide the ActionBar"
  },
  "translating-toolbar": {
    "title": "Translating the Toolbar"
  },
  "parallax-image": {
    "title": "Parallax image"
  },
  "sticky-header": {
    "title": "Sticky header"
  },
  "flexible-space-toolbar": {
    "title": "Flexible space on the Toolbar"
  },
  "flexible-space-with-image": {
    "title": "Flexible space with image"
  },
  "filling-gap": {
    "title": "Filling gap on top of the Toolbar"
  }
}


================================================
FILE: docs/basic/filling-gap.md
================================================
# Filling gap on top of the Toolbar

This topic describes how to fill the gap on top of the Toolbar,
which are implemented in the following examples.

* FillGapBaseActivity
* FillGapListViewActivity
* FillGapRecyclerViewActivity
* FillGapScrollViewActivity
* FillGap2BaseActivity
* FillGap2ListViewActivity
* FillGap2RecyclerViewActivity
* FillGap2ScrollViewActivity
* FillGap3BaseActivity
* FillGap3ListViewActivity
* FillGap3RecyclerViewActivity
* FillGap3ScrollViewActivity

Please note that these patterns only works for Android 4+.

---

## Overview

There are many examples for this pattern, but they can be classified to the following:

* FillGap
    * When swiping up, the header bar expands and fill the gap between the header and the top of the screen.
* FillGap2
    * Almost same as FillGap, but in this pattern,
      after the gap is filled with primary color, the filled space is going to shrink,
      and the header bar moves.
* FillGap3
    * Usually FillGap should work only when the Scrollable view can scroll.
      But sometimes you may want to scroll them with few items, and you can achieve it with this pattern.
    * This uses `TouchInterceptionFrameLayout` (one of the widgets in this library),
      and this component does not handle "velocity" of scrolls,
      so as soon as you touch up your fingers, translation will be stopped.

## Pattern1 (FillGap)

### ScrollView

#### Basic structure

```xml
<FrameLayout android:clipChildren="false">
  <FrameLayout android:id="@+id/image_holder">
    <ImageView android:id="@+id/image"/>
  </FrameLayout>
  <ObservableScrollView android:id="@+id/scroll">
    <TextView android:id="@+id/container"/>
  </ObservableScrollView>
  <FrameLayout android:id="@+id/header" android:clipChildren="false">
    <View android:id="@+id/header_background"/>
    <LinearLayout android:id="@+id/header_bar">
      <TextView android:id="@+id/title"/>
    </LinearLayout>
  </FrameLayout>
</FrameLayout>
```

`clipChildren` attribute is important.
Without it, part of the views are not drawn.

Incorrect (without `android:clipChildren="false"`):

![](../../docs/images/basic_7.png)

Correct (with `android:clipChildren="false"`):

![](../../docs/images/basic_6.png)

Coming soon...

## Pattern2 (FillGap2)

Coming soon...

## Pattern3 (FillGap3)

Coming soon...

[Next: Advanced techniques &raquo;](../../docs/advanced/index.md)


================================================
FILE: docs/basic/flexible-space-toolbar.md
================================================
# Flexible space on the Toolbar

This topic describes how to create flexible space on the Toolbar,
which are implemented in the following examples.

* FlexibleSpaceToolbarScrollViewActivity
* FlexibleSpaceToolbarWebViewActivity

I originally tried implementing this pattern (only the title animation):  
[Flexible space with image](http://material-design.storage.googleapis.com/publish/material_v_3/material_ext_publish/0B969e8h0awhvQ3lJdU9WVTh1WWM/patterns_scrolling_flexspaceimage.webm)

---

## Using ScrollView

### Layout with ScrollView

#### Basic structure

```xml
<FrameLayout>
  <ObservableScrollView android:id="@+id/scroll">
    <FrameLayout android:id="@+id/body">
      <TextView/>
    </FrameLayout>
  </ObservableScrollView>
  <View android:id="@+id/flexible_space"/>
  <Toolbar android:id="@+id/toolbar"/>
  <RelativeLayout android:paddingLeft="@dimen/toolbar_margin_start">
    <TextView android:id="@+id/title"/>
    <LinearLayout android:orientation="vertical">
      <View android:layout_height="?attr/actionBarSize"/>
      <View android:layout_height="@dimen/flexible_space_height"/>
    </LinearLayout>
  </RelativeLayout>
</FrameLayout>
```

The root `FrameLayout` is used for moving children separately.

The second `FrameLayout`(`@id/body`) inside the ScrollView is the main content,
and you can put any views as you like.
This time, we'll add just a `TextView`.

`View`(`@id/flexible_space`) is for a "flexible space" which has a opaque background.
This view will be translated vertically on scrolling.

`Toolbar` is a normal Toolbar, but this Toolbar will not have "title".

The next `RelativeLayout` and its children are a little tricky.
The `TextView`(`@id/title`) is the real title view,
and other views (`LinearLayout`, `View`) are padding.
In this "flexible space" pattern, `TextView`'s text should move and its font size should change,
so it needs additional space.
We'll achieve these animations by animate `TextView` itself, so paddings should be outside the `TextView`.

To confirm other attributes,
please see `res/layout/activity_flexiblespacetoolbarscrollview.xml` in the example app.

### Initialization

At first, set the Toolbar as the ActionBar and show "homeAsUp" button.

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_flexiblespacetoolbarscrollview);

  setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
  getSupportActionBar().setDisplayHomeAsUpEnabled(true);
```

And get the Activity's title and set it to the `TextView` which has the ID `@id/title`.

```java
  mTitleView = (TextView) findViewById(R.id.title);
  mTitleView.setText(getTitle());
  setTitle(null);
```

And initialize other views and fields.

```java
private View mFlexibleSpaceView;
private View mToolbarView;
private TextView mTitleView;
private int mFlexibleSpaceHeight;

@Override
protected void onCreate(Bundle savedInstanceState) {
  // Codes that are already explained above are omitted
  mFlexibleSpaceView = findViewById(R.id.flexible_space);
  mToolbarView = findViewById(R.id.toolbar);

  final ObservableScrollView scrollView = (ObservableScrollView) findViewById(R.id.scroll);
  scrollView.setScrollViewCallbacks(this);

  mFlexibleSpaceHeight = getResources().getDimensionPixelSize(R.dimen.flexible_space_height);
  int flexibleSpaceAndToolbarHeight = mFlexibleSpaceHeight + getActionBarSize();

  findViewById(R.id.body).setPadding(0, flexibleSpaceAndToolbarHeight, 0, 0);
  mFlexibleSpaceView.getLayoutParams().height = flexibleSpaceAndToolbarHeight;
}
```

You should also add `implements ObservableScrollViewCallbacks` to the Activity
and implement those methods as always.

### Animation

We use `onScrollChanged()` to create animation.
We must write following codes:

* Translate the flexible space view
* Translate and scale the title view

#### Translate the flexible space view

This is easy, just translate it using `scrollY`:

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  ViewHelper.setTranslationY(mFlexibleSpaceView, -scrollY);
}
```

#### Scale the title view

How do you change the size of the font?  
At first I tried just changing the size of the font, but it didn't work. It should be scaled.

The scale should change from `1` to `1.x`. You can change `.x` to fit your app.
In this case, I used the height of the flexible space and the height of the Toolbar. This calculates the maximum `.x`:

```java
float maxScale = (float) (mFlexibleSpaceHeight - mToolbarView.getHeight()) / mToolbarView.getHeight();
```

The scale (we call `.x` part as "scale" from here) should change between 0 to `maxScale`, so it can be written as follows.

```java
// scrollY should be limited.
int adjustedScrollY = (int) ScrollUtils.getFloat(scrollY, 0, mFlexibleSpaceHeight);

// When scrollY is 0, scale equals to maxScale.
// When scrollY reaches to mFlexibleSpaceHeight, scale will be 0.
float scale = maxScale * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight;
```

When scaling the view, we need to set the center point of scaling.
You can handle this by using `pivotX` and `pivotY`, and we should set them to `(0, 0)` like this image:

![](../images/basic_4.png)

We will set `pivotX` and `pivotY` first, and then change the scale:

```java
// Pivot the title view to (0, 0)
ViewHelper.setPivotX(mTitleView, 0);
ViewHelper.setPivotY(mTitleView, 0);

// Scale the title view
ViewHelper.setScaleX(mTitleView, 1 + scale);
ViewHelper.setScaleY(mTitleView, 1 + scale);
```

#### Translate the title view

And about `translationY`, this is a little complicated.
Let's see the following picture.

![](../images/basic_5.png)

The minimum `translationY` is obviously 0, and we want to know
the maximum `translationY`.
As we can see in the picture, the maximum `translationY` can be calculated with `ht1 + hf - ht2`, so we can write like this:

```java
int maxTitleTranslationY = mToolbarView.getHeight() + mFlexibleSpaceHeight - (int) (mTitleView.getHeight() * (1 + scale));
```

And we should vary this value using `scrollY`.
`scrollY` should be limited and it's already calculated as `adjustedY`:

```java
  int titleTranslationY = (int) (maxTitleTranslationY * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight);
  ViewHelper.setTranslationY(mTitleView, titleTranslationY);
```

Finally, we've finished translation and scaling.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  ViewHelper.setTranslationY(mFlexibleSpaceView, -scrollY);

  // Calculate scale
  int adjustedScrollY = (int) ScrollUtils.getFloat(scrollY, 0, mFlexibleSpaceHeight);
  float maxScale = (float) (mFlexibleSpaceHeight - mToolbarView.getHeight()) / mToolbarView.getHeight();
  float scale = maxScale * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight;

  // Pivot the title view to (0, 0)
  ViewHelper.setPivotX(mTitleView, 0);
  ViewHelper.setPivotY(mTitleView, 0);

  // Scale the title view
  ViewHelper.setScaleX(mTitleView, 1 + scale);
  ViewHelper.setScaleY(mTitleView, 1 + scale);

  // Translate the title view
  int maxTitleTranslationY = mToolbarView.getHeight() + mFlexibleSpaceHeight - (int) (mTitleView.getHeight() * (1 + scale));
  int titleTranslationY = (int) (maxTitleTranslationY * ((float) mFlexibleSpaceHeight - adjustedScrollY) / mFlexibleSpaceHeight);
  ViewHelper.setTranslationY(mTitleView, titleTranslationY);
}
```

#### Adjust the initial state of the title

It's almost finished, but maybe you will notice
that when the screen is launched,
the title is located at the top of the screen.
It should be located at the bottom of the header view area and have larger font.

This is because `onScrollChanged()` is not called.  
You can fix that by calling `onScrollChanged()` just after the views are laied out.
And you can handle this "laid out" event by using `ViewTreeObserver#addOnGlobalLayoutListener()`.

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
  // Other initialization codes are omitted
  ViewTreeObserver vto = mTitleView.getViewTreeObserver();
  vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
      } else {
        view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
      }
      updateFlexibleSpaceText(scrollView.getCurrentScrollY());
    }
  });
}

@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  updateFlexibleSpaceText(scrollY);
}

private void updateFlexibleSpaceText(scrollY) {
  // Original animation codes are omitted
}
```

You can replace the following `ViewTreeObserver` codes

```java
ViewTreeObserver vto = mTitleView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
      view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
    } else {
      view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
    }
    updateFlexibleSpaceText(scrollView.getCurrentScrollY());
  }
});
```

to this:

```java
ScrollUtils.addOnGlobalLayoutListener(mTitleView, new Runnable() {
  @Override
  public void run() {
    updateFlexibleSpaceText(scrollView.getCurrentScrollY());
  }
});
```

That's all!

[Next: Flexible space with image &raquo;](../../docs/basic/flexible-space-with-image.md)


================================================
FILE: docs/basic/flexible-space-with-image.md
================================================
# Flexible space with image

This topic describes how to create flexible space with image,
which are implemented in the following examples.

* FlexibleSpaceWithImageListViewActivity
* FlexibleSpaceWithImageRecyclerViewActivity
* FlexibleSpaceWithImageScrollViewActivity

First, please check the "[Flexible space on the Toolbar](../../docs/basic/flexible-space-toolbar.md)"
tutorial, if you haven't.  

---

## Using ScrollView

### Layout with ScrollView

#### Basic structure

```xml
<FrameLayout>
    <ImageView android:id="@+id/image"/>
    <View android:id="@+id/overlay"/>
    <ObservableScrollView android:id="@+id/scroll">
        <LinearLayout android:orientation="vertical">
            <View/>
            <TextView/>
        </LinearLayout>
    </ObservableScrollView>
    <LinearLayout android:orientation="vertical">
        <TextView android:id="@+id/title"/>
        <View/>
    </LinearLayout>
    <FloatingActionButton android:id="@+id/fab"/>
</FrameLayout>
```

The root `FrameLayout` is used for moving children separately.

`ImageView`(`@id/image`) is the image that will be translated with parallax effect.

`View`(`@id/overlay`) is a overlay view as the name suggests.  
If you try this Activity in the demo app, you can see the image is fading in and out.
This view overlaps with the image and its opacity is changed by scroll position.

`LinearLayout` and its chlidren are the real title views.  
You would have read the former tutorial, so I will not explain it so much.

`FloatingActionButton` is a widget from the simple and awesome [FloatingActionButton](https://github.com/makovkastar/FloatingActionButton) library.  
But this is optional, so you can remove it if you are not going to place any buttons.
I added it just because I think it's a very symbolic widget of the Material Design
and some of you might be interested in it.

To confirm other attributes,
please see `res/layout/activity_flexiblespacewithimagescrollview.xml` in the example app.

### Initialization

Most of the codes are easy and not related to this pattern.  
Just write the following initialization codes:

Copy the title to the title view (`TextView`) and set null to the original title:

```java
mTitleView.setText(getTitle());
setTitle(null);
```

Get the dimension values and save them to fields (to simplify animation codes):

```Java
mFlexibleSpaceImageHeight = getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
mFlexibleSpaceShowFabOffset = getResources().getDimensionPixelSize(R.dimen.flexible_space_show_fab_offset);
mFabMargin = getResources().getDimensionPixelSize(R.dimen.margin_standard);
mActionBarSize = getActionBarSize();
```

Get the views which has ID to fields (to simplify animation codes), and initialize them if necessary:

```java
mImageView = findViewById(R.id.image);
mOverlayView = findViewById(R.id.overlay);
mScrollView = (ObservableScrollView) findViewById(R.id.scroll);
mScrollView.setScrollViewCallbacks(this);
mTitleView = (TextView) findViewById(R.id.title);
mFab = findViewById(R.id.fab);
```

Although this is not so related to the scroll animation,
you should scale the floating action button (FAB) to 0 in `onCreate()`,
because we'd like to hide it at the beginning and gradually show (scale) it
by scrolling.

```java
ViewHelper.setScaleX(mFab, 0);
ViewHelper.setScaleY(mFab, 0);
```

You should also add `implements ObservableScrollViewCallbacks` to the Activity
and implement those methods as always.

### Animation

We use `onScrollChanged()` to create animation.  
We'll write the following codes:

* Translate the overlay view and the image view
* Change the alpha of the overlay view
* Translate and scale the title view
* Translate the FAB
* Show/hide the FAB

Let's see one by one.

#### Translate the overlay view and the image view

As we implemented in the former tutorials,
to move `ImageView` which is outside the ScrollView,
we must use `-scrollY` and divide it by 2 to create "parallax" effect.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  float flexibleRange = mFlexibleSpaceImageHeight - mActionBarSize;
  int minOverlayTransitionY = mActionBarSize - mOverlayView.getHeight();
  ViewHelper.setTranslationY(mOverlayView, ScrollUtils.getFloat(-scrollY, minOverlayTransitionY, 0));
  ViewHelper.setTranslationY(mImageView, ScrollUtils.getFloat(-scrollY / 2, minOverlayTransitionY, 0));
```

Although we want to move the overlay view with the image,
we don't have to make the scroll speed of the overlay to the same as the image view.
So translate `mOverlayView` to `-scrollY` (not `-scrollY / 2`).

#### Change the alpha of the overlay view

Calculating the alpha value is easy, just convert the `scrollY` to range between 0 and 1.
To do this, we divide `scrollY` by `flexibleRange` (which we assigned above),
and limit the value range from 0 to 1 by using `ScrollUtils.getFloat()`.

```java
  ViewHelper.setAlpha(mOverlayView, ScrollUtils.getFloat((float) scrollY / flexibleRange, 0, 1));
```

#### Translate and scale the title view

This is almost the same as the "Flexible space on the Toolbar" pattern.
The differences are how to calculate the scale and the translationY.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  // Codes that are already explained above are omitted

  float scale = 1 + ScrollUtils.getFloat((flexibleRange - scrollY) / flexibleRange, 0, MAX_TEXT_SCALE_DELTA);
  ViewHelper.setPivotX(mTitleView, 0);
  ViewHelper.setPivotY(mTitleView, 0);
  ViewHelper.setScaleX(mTitleView, scale);
  ViewHelper.setScaleY(mTitleView, scale);

  int maxTitleTranslationY = (int) (mFlexibleSpaceImageHeight - mTitleView.getHeight() * scale);
  int titleTranslationY = maxTitleTranslationY - scrollY;
  ViewHelper.setTranslationY(mTitleView, titleTranslationY);
```

#### Translate the FAB

Translating the FAB is actually not related to this topic, but I'll explain for your reference.

The basic idea is to change the `translationY` property of the FAB,
but on pre-Honeycomb devices, this doesn't work when you use `setOnClickListener`.
To fix the issue, we'll set the margins of the FrameLayout and lay it out again by calling `requestLayout()`.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  // Codes that are already explained above are omitted

  int maxFabTranslationY = mFlexibleSpaceImageHeight - mFab.getHeight() / 2;
  float fabTranslationY = ScrollUtils.getFloat(
      -scrollY + mFlexibleSpaceImageHeight - mFab.getHeight() / 2,
      mActionBarSize - mFab.getHeight() / 2,
      maxFabTranslationY);
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
    // On pre-honeycomb, ViewHelper.setTranslationX/Y does not set margin,
    // which causes FAB's OnClickListener not working.
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mFab.getLayoutParams();
    lp.leftMargin = mOverlayView.getWidth() - mFabMargin - mFab.getWidth();
    lp.topMargin = (int) fabTranslationY;
    mFab.requestLayout();
  } else {
    ViewHelper.setTranslationX(mFab, mOverlayView.getWidth() - mFabMargin - mFab.getWidth());
    ViewHelper.setTranslationY(mFab, fabTranslationY);
  }
```

The expression `- mFab.getHeight() / 2` in the calculation of `maxFabTranslationY` means
that the half of the FAB overlaps to the image.

And about the `fabTranslationY` calculation,
you might think that the expression `mActionBarSize - mFab.getHeight() / 2` for the min value
is meaningless, but this is required when you scroll the view fast.
Because if it scrolls faster than the FAB scaling to 0, it looks as if it just moved away.

#### Show/hide the FAB

Showing or hiding the FAB is easy.
If the translationY of the FAB exceeds the threshold, then hide it.
Otherwise, show it.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  // Codes that are already explained above are omitted

  if (fabTranslationY < mFlexibleSpaceShowFabOffset) {
    hideFab();
  } else {
    showFab();
  }
}
```

`hideFab()` and `showFab()` methods can be implemented like this:

```java
  private boolean mFabIsShown;

  private void showFab() {
    if (!mFabIsShown) {
      ViewPropertyAnimator.animate(mFab).cancel();
      ViewPropertyAnimator.animate(mFab).scaleX(1).scaleY(1).setDuration(200).start();
      mFabIsShown = true;
    }
  }

  private void hideFab() {
    if (mFabIsShown) {
      ViewPropertyAnimator.animate(mFab).cancel();
      ViewPropertyAnimator.animate(mFab).scaleX(0).scaleY(0).setDuration(200).start();
      mFabIsShown = false;
    }
  }
```

We need a state variable to indicate whether the FAB is shown or not.

That's all.

[Next: Filling gap on top of the Toolbar &raquo;](../../docs/basic/filling-gap.md)


================================================
FILE: docs/basic/index.md
================================================
# Basic techniques

This section explains the basic scrolling techniques.  

1. [Show and hide the ActionBar](../../docs/basic/show-hide-action-bar.md)
1. [Translating the Toolbar](../../docs/basic/translating-toolbar.md)
1. [Parallax image](../../docs/basic/parallax-image.md)
1. [Sticky header](../../docs/basic/sticky-header.md)
1. [Flexible space on the Toolbar](../../docs/basic/flexible-space-toolbar.md)
1. [Flexible space with image](../../docs/basic/flexible-space-with-image.md)
1. [Filling gap on top of the Toolbar](../../docs/basic/filling-gap.md)

[Next: Show and hide the ActionBar &raquo;](../../docs/basic/show-hide-action-bar.md)


================================================
FILE: docs/basic/parallax-image.md
================================================
# Parallax image

This topic describes how to create parallax effect,
which are implemented in the following examples.

* ParallaxToolbarScrollViewActivity
* ParallaxToolbarListViewActivity

---

## Overview

In this topic, "parallax" means the following layout and behavior:

* The layout has an image on the top of the layout.
* The image will move with half the speed of that of the ScrollView.
* ScrollView itself has a big padding, which is like a "window" to see the image.

To make the image "parallax", we need to do some tricks on the layout.  

`ObservableScrollView` and `ObservableListView` are a little different
around handling paddings.
I'll explain from `ObservableScrollView`.

---

## ScrollView

### Layout

#### Basic structure

At first, let's see the following basic structure of the layout.

```xml
<FrameLayout>
  <ObservableScrollView>
    <RelativeLayout>
      <ImageView/>
      <View/>
      <TextView/>
    </RelativeLayout>
  </ObservableScrollView>
  <Toolbar/>
</FrameLayout>
```

Please note that in this XML, I intentionally omitted attributes(`android:XXX`)
and package name (`com.github.XXX`) for readability.

##### Why should we use FrameLayout?

As you can see on the example app, Toolbar is overlaid to the ObservableScrollView.
To do this, we need to use `FrameLayout` or `RelativeLayout`.

##### What's inside of the ObservableScrollView?

`ObservableScrollView` extends `ScrollView`, so it can have no more than 1 child.
However we need more children, so placing a `ViewGroup` as the child of `ObservableScrollView` is required.

`ImageView` is the `View` which is going to have "parallax" effect.
You can replace it to other type of `View` if you want.

`TextView` is the main content of the screen, you can also replace it to other type of `View`.

`View` is an "anchor", I'll explain it later.

We need to move the content and the image separately,
so the parent of them &mdash; child of `ObservableScrollView` &mdash;
should be `RelativeLayout` or `FrameLayout`.
This time, we use `RelativeLayout` for that purpose.

#### Don't move the content when its parent is scrolled

How do you place the main content (a `TextView` for this time) under the `ImageView`?

Suppose you define the position with `android:layout_below` attribute:

```xml
<!-- some attributes are omitted -->
<RelativeLayout>
  <ImageView android:id="@+id/image">
  <TextView android:layout_below="@id/image">
</RelativeLayout>
```

We need to move `ImageView` but if we do this, 
the `TextView` moves with the same speed as `ImageView`
because its layout is defined with `android:layout_below="@id/image"`.
So we should define the `TextView`'s position with another "anchor" view:

```xml
<!-- some attributes are omitted -->
<RelativeLayout>
  <ImageView android:id="@+id/image"
             android:layout_height="@dimen/parallax_image_height">
  <View android:id="@+id/anchor"
        android:layout_height="@dimen/parallax_image_height"
        android:minHeight="@dimen/parallax_image_height" />
  <TextView android:layout_below="@id/anchor">
</RelativeLayout>
```

With this anchor view, we can move only `ImageView`.
The anchor `View` and `TextView` will remain in their position.

#### Set the content color explicitly

We need to set the background color of the main content explicitly,
because the image is underlying.

```xml
<TextView android:layout_below="@id/anchor"
  android:background="@android:color/white" />
```

#### Complete the layout

Now set the rest of the attributes of the layout,
such as `android:layout_width`, `android:padding`, etc.  
Please see the folloing codes for details.

* `res/layout/activity_parallaxtoolbarscrollview.java`

### Animation

#### Basic structure of Activity

We use `AppCompatActivity` of the v7 appcompat library for the base `Activity` class,
and implement `ObservableScrollViewCallbacks`.

```java
public class ParallaxToolbarScrollViewActivity
  extends AppCompatActivity implements ObservableScrollViewCallbacks {
```

#### Initialize views

Then initialize the views like this.

```java
// Fields
private View mImageView;
private View mToolbarView;
private ObservableScrollView mScrollView;
private int mParallaxImageHeight;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_parallaxtoolbarscrollview);

  setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

  mImageView = findViewById(R.id.image);
  mToolbarView = findViewById(R.id.toolbar);
  mToolbarView.setBackgroundColor(
    ScrollUtils.getColorWithAlpha(0, getResources().getColor(R.color.primary)));

  mScrollView = (ObservableScrollView) findViewById(R.id.scroll);
  mScrollView.setScrollViewCallbacks(this);

  mParallaxImageHeight = getResources().getDimensionPixelSize(
    R.dimen.parallax_image_height);
}
```

The Toolbar should be transparent at the beginning, so set the alpha of the background color to 0
by using the `ScrollUtils` utility class.
This is optional and you can omit this if you don't use the Toolbar.

#### Change the position on scrolling

We use `onScrollChanged()` method, one of `ObservableScrollViewCallbacks`, to animate the view.
What we need to do in this method is:

1. translate the `ImageView` in Y-axis using `scrollY` parameter
1. change the alpha value of the background color of the `Toolbar` using `scrollY` parameter

The second one is optional. You can omit this if you don't use the Toolbar.

##### Translate the ImageView

Just set the `translateY` property to half of `scrollY`.  
If you want to change the "depth" of the parallax effect, adjust this value (`scrollY / 2`).

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  ViewHelper.setTranslationY(mImageView, scrollY / 2);
}
```

##### Change the alpha of the Toolbar background color

We should change the alpha value of the background color of the Toolbar,
so we can write like this.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  int baseColor = getResources().getColor(R.color.primary);
  float alpha = 0; // TODO Fix this value
  mToolbarView.setBackgroundColor(ScrollUtils.getColorWithAlpha(alpha, baseColor));
```

Changing alpha is a little complicated, so I wrote `float alpha = 0` temporarily.  
Let's confirm the conditions of the colors and fix the `alpha` value.

* If the `ObservableScrollView` is not scrolled, Toolbar is transparent.  
  (If `scrollY` equals to 0, alpha of the Toolbar is 0.)
* If the `ObservableScrollView` is scrolled, it becomes opaque gradually,
  and when it's scrolled to a certain point, Toolbar is completely opaque.  
  (If `scrollY` equals to `mParallaxImageHeight`, alpha of the Toolbar is 1.)

We need to express these conditions as a formula.

`alpha` should changes from 0 to 1, but `scrollY` changes from 0 to thousands,
so `scrollY` should be scaled.  
We should divide `scrollY` with `mParallaxImageHeight` because
when `alpha` becomes 1, `scrollY` should be equal to `mParallaxImageHeight`.

```java
float alpha = (float) scrollY / mParallaxImageHeight;
```

Please note that `scrollY` and `mParallaxImageHeight` are both type `int`,
so you need to cast one of them to `float`.

But how is it when `scrollY` becomes more than `mParallaxImageHeight`?  
Let's simulate the result values:

| `scrollY` | `mParallaxImageHeight` | `alpha`   | Valid alpha?  |
| ---------:| ----------------------:| ---------:| ------------- |
| 0         | 300                    | 0         | Valid         |
| 150       | 300                    | 0.5       | Valid         |
| 300       | 300                    | 1.0       | Valid         |
| 450       | 300                    | _**1.5**_ | _**Invalid**_ |

As we can see in the 4th row (`scrollY == 450`),
we need to control `alpha` so that it will not exceed 1.0.
This time we use `Math.min()` to limit the value from 0 to 1.

```java
float alpha = Math.min(1, (float) scrollY / mParallaxImageHeight);
```

Now it's done.  
`onScrollChanged` will be like this:

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  int baseColor = getResources().getColor(R.color.primary);
  float alpha = Math.min(1, (float) scrollY / mParallaxImageHeight);
  mToolbarView.setBackgroundColor(ScrollUtils.getColorWithAlpha(alpha, baseColor));
  ViewHelper.setTranslationY(mImageView, scrollY / 2);
}
```

#### Restore scroll state

We need to handle one more thing: restoring scroll state when the Activity is restored.  
`ObservableScrollView` itself stores its scroll position,
so you just need to update the view
in the `onRestoreInstanceState()` method.

```java
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  onScrollChanged(mScrollView.getCurrentScrollY(), false, false);
}
```

---

## ListView

Let's see the difference of the implementation between ListView version and ScrollView version.

### Layout

#### Basic structure

```xml
<FrameLayout>
  <ImageView/>
  <View/>
  <ObservableListView/>
  <Toolbar/>
</FrameLayout>
```

We use `FrameLayout` to the root view, just like ScrollView pattern.  
`FrameLayout` can be used to move children views separately.

`ImageView` is the view which should have "parallax" effect.

The next `View` is used for different purpose from that of ScrollView.
I'll explain this later.


#### Why do we use different layout?

Unlike ScrollView, ListView cannot have children views,
so `ImageView` should be outside of the scrollable view (ListView)
and we should move the `ImageView` manually.

#### How do we place ImageView and ListView?

`ImageView` is going to be scrolled slower than ListView
(because we're going to make "parallax" effect), 
so `ImageView` should be underneath the ListView.
Otherwise, the bottom of the `ImageView` overlaps with the top of the ListView.

Also, ListView should have a big padding
at the top of the ListView to make `ImageView` visible.  
We achieve this by adding a transparent header view to the ListView.

#### Why do we need a View?

As I mentioned above, ListView should have a transparent header,
so its background color should be also transparent.
But if we do this, not only the header view but also the items of the ListView
become transparent.

![](../images/basic_1.png)


To avoid this, we set a dummy background view under the ListView.

### Animation

#### Basic structure of Activity

It's same as `ParallaxToolbarScrollViewActivity` example.

```java
public class ParallaxToolbarListViewActivity
  extends BaseActivity implements ObservableScrollViewCallbacks {
```

#### Initialize views

Like ScrollView, initialize the `ObservableListView`, `ImageView`, Toolbar, etc.  
And as I explained, ListView should have a header view.

```java
private View mImageView;
private View mToolbarView;
private View mListBackgroundView;
private ObservableListView mListView;
private int mParallaxImageHeight;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_parallaxtoolbarlistview) ;

  setSupportActionBar((Toolbar) findViewById(R.id.toolbar));

  mImageView = findViewById(R.id.image);
  mToolbarView = findViewById(R.id.toolbar);
  mToolbarView.setBackgroundColor(ScrollUtils.getColorWithAlpha(0, getResources().getColor(R.color.primary)));

  mParallaxImageHeight = getResources().getDimensionPixelSize(R.dimen.parallax_image_height);

  mListView = (ObservableListView) findViewById(R.id.list);
  mListView.setScrollViewCallbacks(this);
  // Set padding view for ListView. This is the flexible space.
  View paddingView = new View(this);
  AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
          mParallaxImageHeight);
  paddingView.setLayoutParams(lp);
  paddingView.setClickable(true);

  mListView.addHeaderView(paddingView);
  setDummyData(mListView);
  mListBackgroundView = findViewById(R.id.list_background);
```

Note that following code is necessary to disable header view's list selector effect.

```java
  paddingView.setClickable(true);
```

`setDummyData()` should be replaced to appropriate data population codes.

#### Change the position on scrolling

##### Translate the ImageView

We use `onScrollChanged` method to translate views.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
}
```

Basically, we should just set the translateY property to half of `scrollY`.
But be careful, unlike ScrollView, when `scrollY` gets larger then `translateY` of `ImageView` should become smaller
because `ImageView` is not a child of the ListView.
So we should use `-scrollY / 2` as `translationY` (and you can adjust "`/ 2`" if you want).

```java
ViewHelper.setTranslationY(mImageView, -scrollY / 2);
```

##### Translate the background view

The background should move with ListView, but it should have an offset `mParallaxImageHeight`
so we can write like this:

```java
ViewHelper.setTranslationY(mListBackgroundView, mParallaxImageHeight - scrollY);
```

But how is it when `scrollY` becomes more than `mParallaxImageHeight`?  
Let's simulate the result values:

| `mParallaxImageHeight` | `scrollY` | `mParallaxImageHeight - scrollY` | TranslationY of `mListViewBackgroundView` should be |
| ----------------------:| ---------:|---------------------------------:|----------------------------------------------------:|
| 300                    | 0         | 300                              | 300                                                 |
| 300                    | 150       | 150                              | 150                                                 |
| 300                    | 300       | 0                                | 0                                                   |
| 300                    | 450       | -150                             | 0                                                   |

The 4th `mParallaxImageHeight - scrollY` becomes negative and it's invalid.  
So use `Math.max()` to avoid this.

```java
ViewHelper.setTranslationY(mListBackgroundView, Math.max(0, -scrollY + mParallaxImageHeight));
```

That's all.  
The rest of the codes are the same as `ObservableScrollView` example.

[Next: Sticky header &raquo;](../../docs/basic/sticky-header.md)


================================================
FILE: docs/basic/show-hide-action-bar.md
================================================
# Show and hide the ActionBar

This topic describes how to show and hide the ActionBar,
which are implemented in the following examples.

* ActionBarControlGridViewActivity
* ActionBarControlListViewActivity
* ActionBarControlRecyclerViewActivity
* ActionBarControlScrollViewActivity
* ActionBarControlWebViewActivity

---

## Using the basic callbacks

Suppose you've already checked the "[Quick start](../../docs/quick-start/index.md)" section,
you wouldn't know the meaning of the codes yet.  
So at first, let's see how those codes work.

### ObservableScrollViewCallbacks

In the quick start guide, you wrote the implementation of `ObservableScrollViewCallbacks` (following methods).

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
}
@Override
public void onDownMotionEvent() {
}
@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
}
```

These are the methods of `ObservableScrollViewCallbacks` interface and all the `Observable*View`s can handle this callbacks.

### onScrollChanged callback

This is called when the scroll change events occurred.  
This won't be called just after the view is laid out, so if you'd like to initialize the position of your views with this method, you should call this manually or invoke scroll as appropriate.

You would expect it to be called after `onCreate`,
but `ListView` (or other views) does not call back
scroll change event, so `Observable*Views` cannot
call this.
Therefore you should write like this:

```java
onScrollChanged(mListView.getCurrentScrollY(), false, false);
```

I know it's a bad pattern to call the "callback" methods from us, they should be called by the library when they should be. However, we cannot improve this because this behavior depends on the view classes in the Android SDK.

### onDownMotionEvent callback

This is called when the down motion events occur.  
This can be useful if you'd like to know when the touch (or dragging) has begun.

### onUpOrCancelMotionEvent callback

This is called when the dragging ended or canceled.
This is useful when you move some views when the scroll ends: showing/hiding a view, sliding a view to the anchor point, etc.

## How it works: ActionBar animation

As I explained in the quick start section, the main animation code is in the `onUpOrCancelMotionEvent`.

What we want to do is:

1. to hide the ActionBar when we swipe up the view, because we want to see the contents.
1. to show the ActionBar when we swipe down the view, because we want to tap a button on the ActionBar (it could be sharing the contents or going back to the former screen, for example).

Either way, we should get the direction of scrolling when the dragging ends.
`onUpOrCancelMotionEvent` callback has a `ScrollState` parameter. This parameter indicates the direction of the scroll, so we can write like this:

```java
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  if (scrollState == ScrollState.UP) {
    // TODO show or hide the ActionBar
  } else if (scrollState == ScrollState.DOWN) {
    // TODO show or hide the ActionBar
  }
}
```

When you move your finger from the bottom of the screen to the top (swiping up), the state will be `ScrollState.UP`. So we can write `ActionBar#hide()` in this condition.
And this event occurs every time you scroll the view, so if the `ActionBar` is already hidden, you don't have to hide it anymore.

Now you know how to handle the other direction.
Show the ActionBar when `ScrollState.DOWN` is passed to the callback.

```java
ActionBar ab = getSupportActionBar();
if (scrollState == ScrollState.UP) {
  if (ab.isShowing()) {
    ab.hide();
  }
} else if (scrollState == ScrollState.DOWN) {
  if (!ab.isShowing()) {
    ab.show();
  }
}
```

## Conclusion

If you'd like to animate the ActionBar, you should write animation codes in the `onUpOrCancelMotionEvent` callback.
Also, we used `ObservableListView` in the quick start, but in this pattern all types of `Observable*View`s have the same behavior, so you can write exactly the same.

[Next: Translating the Toolbar &raquo;](../../docs/basic/translating-toolbar.md)


================================================
FILE: docs/basic/sticky-header.md
================================================
# Sticky header

This topic describes how to keep header on top of the screen,
which are implemented in the following examples.

* StickyHeaderListViewActivity
* StickyHeaderRecyclerViewActivity
* StickyHeaderScrollViewActivity
* StickyHeaderWebViewActivity

---

## Overview

This is a complex version of [Toolbar translation pattern](../../docs/basic/translating-toolbar.md).

We add a features to keep the half of the header view to the top of the screen.
And this time I'll explain using ScrollView.
Replacing it to other type of scrollable views are not so difficult.

## Using ScrollView

### Layout with ScrollView

Let's look at the layout file as always.

Here is the basic structure of StickyHeader pattern with ScrollView.
This is a little difficult than Toolbar's one.

```xml
<FrameLayout>
  <ObservableScrollView android:id="@+id/scroll">
    <LinearLayout android:orientation="vertical">
      <View android:minHeight="?attr/actionBarSize"/>
      <View android:minHeight="?attr/actionBarSize"/>
      <TextView/>
    </LinearLayout>
  </ObservableScrollView>
  <LinearLayout
    android:id="@+id/header"
    android:orientation="vertical">
    <Toolbar
      android:id="@+id/toolbar"
      android:minHeight="?attr/actionBarSize"/>
    <TextView
      android:id="@+id/sticky"
      android:layout_height="?attr/actionBarSize"/>
  </LinearLayout>
</FrameLayout>
```

In Toolbar translation pattern, we used only `ObservableScrollView` and `Toolbar` in `FrameLayout`.
This time, we need to make each views more complex.

#### Create header space for ScrollView with twice the size of ActionBar

At the initial state of views, ScrollView needs to have a header view with twice the size of the ActionBar.
The half of this header view will be "sticky".  
So we simply add 2 `View`s with the height `?attr/actionBarSize` above the `TextView`.

You can also add just 1 `View` with a certain size with `dp`,
but it's better to use `?attr/actionBarSize` because it has multiple values for several size of screens,
screen rotation and OS versions, and using the standard size is good for users.

Another way to achieve this, is to set the height of the `View` programmatically.
You can resolve the value of `?attr/actionBarSize` in `Activity#onCreate()`, multiply it by 2 and set it to the `View`.

And please note that `TextView` is the real content of the ScrollView, so you can replace it to other view if you want.

#### Create sticky part for Toolbar

Toolbar is replaced to `LinearLayout`, and it contains a Toolbar and a `TextView`.
`TextView` will be the "sticky" view.
You can replace it to some complex views.

### Animate the views with ScrollView callbacks

This time, we use two callbacks: `onScrollChanged()` and `onUpOrCancelMotionEvent()` to animate views.
We are going to implement the following animation.

1. Move the Toolbar and the sticky view (we call "header views") when the ScrollView is scrolled.
1. When we scroll the ScrollView, the Toolbar will go out of the screen.
   But when we scroll it more, sticky view must keep its position to the top of the screen.
1. When the Toolbar is not completely hidden and we stop scrolling (touch up the ScrollView),
    * the Toolbar will be shown completely, if we were swiping down.
    * the Toolbar will be hidden completely, if we were swiping up.
1. When we swipe down the ScrollView and touch up, the header view should
   come out immediately. Sometimes it's called "Quick Return" pattern.

#### Move the header view when ScrollView is scrolled

Override the `onScrollChanged()`, and implement some codes with the condition `if (dragging)`.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  if (dragging) {
    // TODO implement the rest of the codes
  //} else { // ScrollView is scrolled by inertia
  }
}
```

This is because we want to move views only when it is dragged.
Without this, we cannot achieve the 3rd condition above: showing or hiding the Toolbar automatically
when the scroll ended.

Next step, implement the header view translation.  
At first, create a field with name `mHeaderView`, and initialize it in `onCreate()`:

```java
mHeaderView = findViewById(R.id.header);
```

When the scrollY parameter gets increased, the translationY of `mHeaderView` should decrease.
So we can write like this:

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  if (dragging) {
    ViewHelper.setTranslationY(mHeaderView, -scrollY);
  }
}
```

#### Sticky view must keep its position to the top of the screen

The header view will disappear completely, and this is not what we want.
`mHeaderView` should stop after moving the height of Toolbar.

```java
@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  if (dragging) {
    int toolbarHeight = mToolbarView.getHeight();
    ViewHelper.setTranslationY(mHeaderView, Math.max(-toolbarHeight, -scrollY));
  }
}
```

You can see the sticky view keeping its position to the top of the screen.

#### When Toolbar is not completely hidden, show or hide it completely

To do this, we should implement `onUpOrCancelMotionEvent`.  
If we swipe down, Toolbar should be shown,
and if we swipe up, Toolbar should be hidden.

```java
@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  if (scrollState == ScrollState.DOWN) {
    showToolbar();
  } else if (scrollState == ScrollState.UP) {
    hideToolbar();
  }
}
```

But when we swipe up and scrolled less than Toolbar's height,
hiding the Toolbar makes white space around the top of the ScrollView.  
So we should show the Toolbar if `scrollY` is less than Toolbar's height.

```java
@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  if (scrollState == ScrollState.DOWN) {
    showToolbar();
  } else if (scrollState == ScrollState.UP) {
    int toolbarHeight = mToolbarView.getHeight();
    int scrollY = mScrollView.getCurrentScrollY();
    if (toolbarHeight <= scrollY) {
      hideToolbar();
    } else {
      showToolbar();
    }
  }
}
```

And sometimes `scrollState` becomes `STOP` (or `null`).
If it becomes such values, the header view stops halfway.
To avoid this behavior, write `else` clause.

```java
@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  if (scrollState == ScrollState.DOWN) {
    showToolbar();
  } else if (scrollState == ScrollState.UP) {
    int toolbarHeight = mToolbarView.getHeight();
    int scrollY = mScrollView.getCurrentScrollY();
    if (toolbarHeight <= scrollY) {
      hideToolbar();
    } else {
      showToolbar();
    }
  } else {
    // Even if onScrollChanged occurs without scrollY changing, toolbar should be adjusted
    if (!toolbarIsShown() && !toolbarIsHidden()) {
      // Toolbar is moving but doesn't know which to move:
      // you can change this to hideToolbar()
      showToolbar();
    }
  }
}
```

Then write the unimplemented methods.  
Unlike Toolbar translation pattern, we use `ViewPropertyAnimator.animate()`
because it's simple and we don't have to change the height of views.

```java
private boolean toolbarIsShown() {
  return ViewHelper.getTranslationY(mHeaderView) == 0;
}

private boolean toolbarIsHidden() {
  return ViewHelper.getTranslationY(mHeaderView) == -mToolbarView.getHeight();
}

private void showToolbar() {
  float headerTranslationY = ViewHelper.getTranslationY(mHeaderView);
  if (headerTranslationY != 0) {
    ViewPropertyAnimator.animate(mHeaderView).cancel();
    ViewPropertyAnimator.animate(mHeaderView).translationY(0).setDuration(200).start();
  }
}

private void hideToolbar() {
  float headerTranslationY = ViewHelper.getTranslationY(mHeaderView);
  int toolbarHeight = mToolbarView.getHeight();
  if (headerTranslationY != -toolbarHeight) {
    ViewPropertyAnimator.animate(mHeaderView).cancel();
    ViewPropertyAnimator.animate(mHeaderView).translationY(-toolbarHeight).setDuration(200).start();
  }
}
```

Once `ViewPropertyAnimator.animate()` is called, animation will be running in the next 200ms.
And if the next animation(`showToolbar()` or `hideToolbar()`) is requested while the animation is running,
the current animation should be canceled.
Therefore we call `ViewPropertyAnimator.animate(mHeaderView).cancel()`
before calling `start()`.

#### When swiping up, header view should scroll

It's almost completed, and if you think it's OK, you don't have to write the following codes.

When we scroll so much and swip down little, the header view will be shown.
And after that, when we drag ScrollView to upper side,
I think that the header view should move with ScrollView, but it doesn't.

So we make the header view to scroll even when `scrollY` is larger than the Toolbar's height.

To do this, we just calculate the distance from the first touch point and the current point.
And the distance from the first touch point become larger than Toolbar's height,
the header view should not scroll any longer.

```java
// Add a field to keep the first scrollY
private int mBaseTranslationY;

@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
  if (dragging) {
    int toolbarHeight = mToolbarView.getHeight();
    if (firstScroll) { // Add this if clause
      float currentHeaderTranslationY = ViewHelper.getTranslationY(mHeaderView);
      if (-toolbarHeight < currentHeaderTranslationY) {
        mBaseTranslationY = scrollY;
      }
    }
    // Change -scrollY to -(scrollY - mBaseTranslationY)
    float headerTranslationY = Math.max(-toolbarHeight, -(scrollY - mBaseTranslationY));
    ViewPropertyAnimator.animate(mHeaderView).cancel();
    ViewHelper.setTranslationY(mHeaderView, headerTranslationY);
  }
}

@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    // Should be cleared when scroll ends
    mBaseTranslationY = 0;
```

It's almost done, but sometimes we can see a weird behavior:
the header view leaves the top of the screen.

![](../../docs/images/basic_2.png)

This is because `headerTranslationY` can become larger than 0,
so it should be limited by using `Math.min()`.

```java
float headerTranslationY = Math.min(0, Math.max(-toolbarHeight, -(scrollY - mBaseTranslationY));
```

Now it's working, but don't you think it's a little complicated expression?  
Android-ObservableScrollView provides a small utility class `ScrollUtils`,
and we can replace `Math.min(max, Math.max(min, value))` to `ScrollUtils.getFloat()`.

```java
float headerTranslationY = ScrollUtils.getFloat(-(scrollY - mBaseTranslationY), -toolbarHeight, 0);
```

Of course, you can confirm the meaning of each parameters easily.
Pressing `F1` key on `getFloat()` will show the javadoc window:

![](../../docs/images/basic_3.png)

[Next: Flexible space on the Toolbar &raquo;](../../docs/basic/flexible-space-toolbar.md)


================================================
FILE: docs/basic/translating-toolbar.md
================================================
# Translating the Toolbar

This topic describes how to translate the Toolbar,
which are implemented in the following examples.

* ToolbarControlBaseActivity
* ToolbarControlGridViewActivity
* ToolbarControlListViewActivity
* ToolbarControlRecyclerViewActivity
* ToolbarControlScrollViewActivity
* ToolbarControlWebViewActivity

---

## About the Toolbar

In this section we learn how to translate the Toolbar.  
Toolbar was introduced on Android 5.0, and you can also use it on pre-Lollipop devices
by using [v7 appcompat library](http://developer.android.com/tools/support-library/features.html#v7-appcompat)
of the Android Support Library package.

## Design of the examples

The existing examples above, `ToolbarControlBaseActivity` has most of the codes to avoid writing duplicate codes.
If you use one of them, you don't have to use this structure: extending Activity is not required to achieve this effect.

## Create layout file

In this topic, we use `ObservableListView` and `Toolbar`, and wrap them with `FrameLayout`.  
`FrameLayout` and `RelativeLayout` are useful to translate views inside of it separately.

```xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:minHeight="?attr/actionBarSize"
    app:popupTheme="@style/Theme.AppCompat.Light.DarkActionBar"
    app:theme="@style/Toolbar" />

  <com.github.ksoichiro.android.observablescrollview.ObservableListView
    android:id="@+id/scrollable"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="?attr/actionBarSize" />
</FrameLayout>
```

## How to translate the Toolbar

The basic idea about showing/hiding the Toolbar is exactly the same as the ActionBar.
However, the Toolbar class does not provide any convinient methods like `show()` and `hide()` which the ActionBar class has.
Therefore we should implement such methods to translate the Toolbar.
Our goal is to make the following codes work:

```java
@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  if (scrollState == ScrollState.UP) {
    if (toolbarIsShown()) { // TODO Not implemented
      hideToolbar(); // TODO Not implemented
    }
  } else if (scrollState == ScrollState.DOWN) {
    if (toolbarIsHidden()) { // TODO Not implemented
      showToolbar(); // TODO Not implemented
    }
  }
}
```

## Using NineOldAndroids

Before we begin, you should confirm whether you're going to support pre-Honeycomb devices.
To translate the Toolbar, we would like to use the [Property Animation APIs](http://developer.android.com/guide/topics/graphics/prop-animation.html)
which are introduced in API level 11, so if you are going to support pre-Honeycomb devices,
[JakeWharton/NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids/) might be useful (although it's marked as deprecated).

In this project, all the examples use NineOldAndroids.
So if you don't support pre-Honeycomb devices, please replace `ViewHelper.methodName(viewObject)` to `viewObject.methodName()`.

```
NineOldAndroids: ViewHelper.getTranslationY(mToolbar)
Platform API:    mToolbar.getTranslationY()
```

If you use NineOldAndroids, add an entry to the `dependencies` closure in your `build.gradle`:

```gradle
dependencies {
    compile 'com.nineoldandroids:library:2.4.0'
}
```

## toolbarIsShown()/toolbarIsHidden()

Now let's start from the easiest part.  
To avoid redundant translation, we need methods to check if the Toolbar is shown or hidden.  
With the property animation APIs (or NineOldAndroids), we just simply check the `translationY` property.

```java
private boolean toolbarIsShown() {
  // Toolbar is 0 in Y-axis, so we can say it's shown.
  return ViewHelper.getTranslationY(mToolbar) == 0;
}

private boolean toolbarIsHidden() {
  // Toolbar is outside of the screen and absolute Y matches the height of it.
  // So we can say it's hidden.
  return ViewHelper.getTranslationY(mToolbar) == -mToolbar.getHeight();
}
```

## Implement showToolbar()/hideToolbar()

Next, let's implement methods to animate the Toolbar.  
Before thinking about details, write some pseudocodes to simplify the problem.  
To show or hide the Toolbar, we just need one method to move the Toolbar.

```java
private void showToolbar() {
  moveToolbar(0);
}

private void hideToolbar() {
  moveToolbar(-mToolbar.getHeight());
}
```

This should work, if we implement the `moveToolbar` method correctly :)

Most of the animation codes are combination of property value calculations,
and I think it's very hard to keep these information in my brain or imagine correctly.
And this approach is useful to implement the complex animation.

## Implement moveToolbar()

Although we named the method `moveToolbar`, it's not everything we need to handle.
In ActionBar examples, not only the ActionBar is moved but also the height of the view (`Observable*View`) is changed.
And we need to implement this behavior for the Toolbar.

To use the changing property values, we can use `ValueAnimator`.  
`ValueAnimator` has a callback method `onAnimationUpdate`, and we can get the animation progress from it.  
`ValueAnimator` itself does not animate anything, we need to animate something using a parameter of the callback.

```java
ValueAnimator animator = ValueAnimator.ofFloat(0, 100).setDuration(200);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  @Override
  public void onAnimationUpdate(ValueAnimator animation) {
    float value = (float) animation.getAnimatedValue();
    // You can do whatever you want with the `value`.
  }
});
```

In the example code above, the local variable `value` changes from `0f` to `100f` in 200ms.  
In this case, we should change the `translationY` property of the Toolbar,
and change the height of the `Observable*View` like this:

```java
private void moveToolbar(float toTranslationY) {
  ValueAnimator animator = ValueAnimator.ofFloat(ViewHelper.getTranslationY(mToolbar), toTranslationY).setDuration(200);
  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
      float translationY = (float) animation.getAnimatedValue();
      ViewHelper.setTranslationY(mToolbar, translationY);
      ViewHelper.setTranslationY((View) mScrollable, translationY);
      FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) ((View) mScrollable).getLayoutParams();
      lp.height = (int) -translationY + getScreenHeight() - lp.topMargin;
      ((View) mScrollable).requestLayout();
    }
  });
  animator.start();
}
```

The `translationY` local variable changes from `ViewHelper.getTranslationY(mToolbar)`( == current translationY)
to `toTranslationY`.

To translate the Toolbar, we just call `ViewHelper.setTranslationY()`.  
And to change the height of the wrapper view (`FrameLayout`), set the height value of `FrameLayout.LayoutParams`
and update by calling `requestLayout()`.

## Avoid redundant animation

We'd better check the current `translationY` value
and if it's already equal to `toTranslationY`, stop the animation.

```java
private void moveToolbar(float toTranslationY) {
  // Check the current translationY
  if (ViewHelper.getTranslationY(mToolbar) == toTranslationY) {
    return;
  }
  // Codes after that are omitted
}
```

That's all.

[Next: Parallax image &raquo;](../../docs/basic/parallax-image.md)


================================================
FILE: docs/contributor/_data.json
================================================
{
  "index": {
    "title": "For contributors"
  },
  "ci": {
    "title": "CI"
  },
  "update-website": {
    "title": "Update website"
  },
  "release": {
    "title": "Release"
  }
}


================================================
FILE: docs/contributor/ci.md
================================================
# CI

Coming soon...


================================================
FILE: docs/contributor/index.md
================================================
# For contributors

This section explains some operations for managing the project.

1. [CI](../../docs/contributor/ci.md)
1. [Update website](../../docs/contributor/update-website.md)
1. [Release](../../docs/contributor/release.md)



================================================
FILE: docs/contributor/release.md
================================================
# Release

This is just a memo for me.

## Bump up the version

Edit `gradle.properties` and commit.

```
VERSION_NAME=x.x.x
```

If you set the version suffix `-SNAPSHOT`, it will be handled as a snapshot.

## Commit changes

Before the final confirmation and release, make sure that
there are no uncommitted changes in your repository.

## Confirm test

Check if all tests pass at your machine.  

```sh
./gradlew clean :library:assemble :library:connectedCheck
```

## Upload archives

### Set the credentials

If this is the first time for uploading archives,
you must write credentials to `~/.gradle/gradle.properties`.

```
NEXUS_USERNAME=xxxx
NEXUS_PASSWORD=xxxx
```

### Upload

```sh
./gradlew :library:uploadArchives
```

Or you can clean, test and upload at once.

```sh
./gradlew clean :library:assemble :library:connectedCheck :library:uploadArchives
```

## Close the repo on Sonatype

Open [Sonatype Nexus Professional](https://oss.sonatype.org/) on your browser,
find your repo and close it.
If there are no problems, repository will be staged to the URL like this.

```
https://oss.sonatype.org/content/repositories/TEMPORARY_REPO_NAME/GROUP/ARTIFACT_ID/VERSION/ARTIFACT_ID-VERSION.aar
```

You will receive an email with title "Nexus: Staging Completed",
you can know the appropriate URL from the email.

Set the URL to the `repositories` in your `build.gradle`, and sync.

```gradle
repositories {
  maven {
    url uri('https://oss.sonatype.org/content/repositories/TEMPORARY_REPO_NAME/')
  }
}
```

## Release

After that, click "Release" to promote.
If it's processed successfully, you will receive an email with title "Nexus: Promotion Completed".

It takes 3 or 4 hours to be synced to the Maven Central Repository.

## Create tag, update synced version and push

If it's successfully published to the Maven Central Repository,

* create a tag like `v1.5.0`
* update the `SYNCED_VERSION_NAME` in `gradle.properties`
* push the master branch and the tag to GitHub


================================================
FILE: docs/contributor/update-website.md
================================================
# Update website

Coming soon...


================================================
FILE: docs/example/_data.json
================================================
{
  "index": {
    "title": "Try the example app"
  },
  "google-play": {
    "title": "Download from Google Play"
  },
  "wercker": {
    "title": "Download from wercker"
  },
  "android-studio": {
    "title": "Build on Android Studio"
  },
  "eclipse": {
    "title": "Build on Eclipse"
  }
}


================================================
FILE: docs/example/android-studio.md
================================================
# Build on Android Studio

This library and samples basically support Android Studio and Gradle.  
(Actually, I'm using them to develop this library.)

If you're an Eclipse user, you can skip and go to the next topic.

## Prerequisites

Please [check here](../../docs/reference/environment.md) to see if your enviroment satisfies the prerequisites for building the app.

## Instructions

### Get the source codes

Get the source code of the library and example app, by cloning git repository or downloading archives.

If you use git, execute the following command in your workspace directory.

```
$ git clone https://github.com/ksoichiro/Android-ObservableScrollView.git
```

If you are using Windows, try it on GitBash or Cygwin or something that supports git.

### Import the project to Android Studio

1. Select File &gt; New &gt; Import Project... from the menu.
1. Select the directory that is cloned. If you can't see your cloned directory, click "Refresh" icon and find it.
1. Android Studio will import the project and build it. This might take minutes to complete. Even when the project window is opened, wait until the Gradle tasks are finished and indexed.
1. Click "Run 'samples'" button to build and launch the app. Don't forget to connect your devices to your machine.

### Build and install using Gradle

If you just want to install the app to your device, you don't have to import project to Android Studio.

After cloning the project, connect your device to your machine, and execute the following command on the terminal.

Mac / Linux / Git Bash, Cygwin on Windows:

```sh
$ cd /path/to/Android-ObservableScrollView
$ ./gradlew installDevDebug
```

Windows (Command prompt):

```sh
> cd C:\path\to\Android-ObservableScrollView
> gradlew installDevDebug
```


[Next: Build on Eclipse &raquo;](../../docs/example/eclipse.md)


================================================
FILE: docs/example/eclipse.md
================================================
# Build on Eclipse

This library and samples basically support Android Studio and Gradle.  
Because they have strong power to handle dependencies and ability to configure flexibly,  
and this library and sample app depend on them.

However, some of you might still want to build or debug the project on Eclipse.
If you'd like to do that, please try the following instructions.

Please note that with these instructions you could bulid project on Eclipse, but test codes, build types ('debug' or 'release') and product flavors are still not supported.

## Prerequisites

Please [check here](../../docs/reference/environment.md) to see if your enviroment satisfies the prerequisites for building the app.

## Instructions

### Get the source codes

Get the source code of the library and example app, by cloning git repository or downloading archives.

If you use git, execute the following command in your workspace directory.

```
$ git clone https://github.com/ksoichiro/Android-ObservableScrollView.git
```

If you are using Windows, try it on GitBash or Cygwin or something that supports git.

### Define ANDROID_HOME environment variable

If you haven't define the environment variable `ANDROID_HOME` yet, define it to indicate Android SDK root directory.

### Generate dependency codes for Eclipse

Before trying to import projects to Eclipse,
execute these command:

```
$ ./gradlew clean generateVersionInfoDebug generateEclipseDependencies
```

This will generate dependency codes from AAR files using Gradle wrapper and some metadata files (`.classpath`, `.project`, `project.properties`).

### Import projects to Eclipse and build app

1. Launch Eclipse.
1. Select `File` > `Import`.
1. Select `General` > `Existing Projects into Workspace` and click `Next`.
    * Warning: DO NOT `Android` > `Existing Android Code into Workspace`.
1. Click `Browse` and select project root directory (`Android-ObservableScrollView`).
1. Check `Search for nested projects`.
1. Select all projects and click next.
1. Some warning messages will be generated, but ignore them and wait until build finishes.

### Run the app

1. Confirm your device is connected.
1. Right click `observablescrollview-samples` and select `Run As` > `Android Application`.

That's all!
 
[Next: Basic techniques &raquo;](../../docs/basic/index.md)


================================================
FILE: docs/example/google-play.md
================================================
# Download from Google Play

Click the following link to download the example app from Google Play.

[![Get it on Google Play](https://developer.android.com/images/brand/en_generic_rgb_wo_45.png)](https://play.google.com/store/apps/details?id=com.github.ksoichiro.android.observablescrollview.samples2)

Please note that the app on the Play Store is not always the latest version.  
If you'd like to install the latest one,

* install it manually.
* or if you are a wercker user, you can download the latest build artifact from wercker.

[Next: Download from wercker &raquo;](../../docs/example/wercker.md)


================================================
FILE: docs/example/index.md
================================================
# Try the examples app

To understand how it works, let's see the existing example app
and check if there are some patterns you want to implement.

1. [Download from Google Play](../../docs/example/google-play.md)
1. [Download from wercker](../../docs/eaxmple/wercker.md)
1. [Build on Android Studio](../../docs/example/android-studio.md)
1. [Build on Eclipse](../../docs/example/eclipse.md)

[Next: Download from Google Play &raquo;](../../docs/example/google-play.md)


================================================
FILE: docs/example/wercker.md
================================================
# Download from wercker

[wercker](http://wercker.com/) is a CI service and this project uses wercker to provide the latest sample apk.
If you're not interested in this, go to the next topic.

## Login to wercker

At first, you need to be a member of [wercker](http://wercker.com/) and should login before download the app.

## Visit this repository

Click the badge below to show this repository's builds.

[![wercker status](https://app.wercker.com/status/8d1e27d9f4a662b25dbe70402733582b/m/master "wercker status")](https://app.wercker.com/project/bykey/8d1e27d9f4a662b25dbe70402733582b)

## Select the build

Then select the commit link that you want to download.  
Note that green check mark in front of the link means successful builds and red ones are failure,  
and you can only download the app from the green ones.

![](../images/wercker_1.png)

## Open the last section

Scroll the screen, and click anywhere in the "inspect build result" section to open it.

![](../images/wercker_2.png)

## Download the artifact

Finally, you can download the apk file by clicking the `artifact.tar.gz` link.

![](../images/wercker_3.png)

[Next: Build on Android Studio &raquo;](../../docs/example/android-studio.md)


================================================
FILE: docs/faq.md
================================================
# FAQ

These are frequently asked questions from GitHub issues, emails I received from users, etc.

## Q. When do you implement the new sample? I'm waiting for it so long.

### A. Sorry and please help me if you could.

First of all, I'm so grateful to all of you that you're interested in this project.  
And of course I'd like to respond to all of your request!  
But unfortunately, I don't have enough time to do that...  
If you're interested in implementing new samples or fixing bugs, please help me. (Pull requests are welcome!)

## Q. Does this library support Eclipse?

### A. Yes, it does partially.

Please see [here](../docs/example/eclipse.md) for details.

## Q. Doesn't work!

### A. Please describe your issue as much as possible.

As I wrote in [the contribution guideline](https://github.com/ksoichiro/Android-ObservableScrollView/blob/master/CONTRIBUTING.md),
the library itself only provides the scroll information,
and creating awesome scrolling effects depends deeply on how you use it: layout, offset calculation to animate views, etc.

Therefore, if you find an issue, please describe not only the issue itself but also the related information like Activity name that has problems, operation to produce the issue, modified code (if any), etc.

## Q. Paths are too long to build!

### A. Move your projects upper to shorten the paths.

On Windows environment, if you locate the project directory like `C:\Documents and Settings\user\workspace\Android-ObservableScrollView\`,
Android Studio causes errors and fail to build the project because some of the paths in the output files are too long.

If you see this kind of problem, please move the project directory to upper directory to shorten the paths.

## Q. Sample codes are too complex!

### A. Sorry, please help me refactor them...

Yes, I know they're too complex as samples.

I just aimed to show you that you can realize these kind of effects when you use this library.
I'd very appreciate it if you help me refactor them.

## Q. Updates of the library in master branch seems not be synced to Maven Central.

### A. Sorry, please wait for the next release.

I need to do following tasks to release the new version to the Maven Central, and it takes time, so please wait for the next release.  
If you're in a hurry, please send me an email. I'll release it as soon as possible.

1. Test the library, at least the tests on Travis CI should pass.
1. Check the compatibility for the past versions.
1. Release SNAPSHOT version to the Sonatype snapshot repository.
1. Release to the Sonatype repository. If it's successfully released, it will be synced to Maven Central in a couple of hours.
1. Update README to prompt to use the latest version.

## Q. Can I use this library with API level 8?

### A. It's not supported, but you can.

By adding `tools:overrideLibrary` to `<uses-sdk>` tag,
you can build this library with `android:minSdkVersion="8"`.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.app">

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="22"
        tools:overrideLibrary="com.github.ksoichiro.android.observablescrollview" />
```

If you have other libraries to override, separate them with comma.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.app">

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="22"
        tools:overrideLibrary="com.melnykov.fab,com.github.ksoichiro.android.observablescrollview" />
```



================================================
FILE: docs/overview.md
================================================
# Overview

Android-ObservableScrollView is a library to handle scroll position for Android apps, and contains lots of examples to demonstrate how this library works.

However, creating awesome scrolling effects depends deeply on how you use it: layout, offset calculation to animate views, etc.

This documentation describes how to install this library and apply to your application.

## Get started

See [quick start](../docs/quick-start/index.md) section.

## See the complete examples

You can try the example app, to see what this library can do.  
See [try the example app](../docs/example/index.md) section to know how to install the app.

## Learn from basics

Now you must have seen the examples and setup your environments, then let's learn how to use it in your app.  
See [basic techniques](../docs/basic/index.md) section.

## Challenge complex and awesome techniques

If you'd like to create complex, awesome scrolling animation using ViewPager or something,
please check out [advanced techniques](../docs/advanced/index.md) section.

## If you're interested in improving this library...

Please see the [contribution guideline](../CONTRIBUTING.md).  
Also, [for contributiors](../docs/contributor/index.md) section will be useful to understand / manage the entire project.


================================================
FILE: docs/quick-start/_data.json
================================================
{
  "index": {
    "title": "Quick start"
  },
  "dependencies": {
    "title": "Dependencies"
  },
  "layout": {
    "title": "Layout"
  },
  "animation": {
    "title": "Animation codes"
  }
}


================================================
FILE: docs/quick-start/animation.md
================================================
# Animation codes

This time, we implement ActionBar animation using `AppCompatActivity` in the support library.

## Apply layout to the activity

At first, let `Activity` extend the `AppCompatActivity` and set [the layout we wrote](../../docs/quick-start/layout.md) to it.

```java
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
```

## Initialize ObservableListView

Add some initialization codes to `onCreate()`:

```java
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ObservableListView listView = (ObservableListView) findViewById(R.id.list);
    listView.setScrollViewCallbacks(this);
  }
```

You will see an error around `setScrollViewCallbacks(this)` because the Activity does not implement the required interface yet.
So add `implements ObservableScrollViewCallbacks` to the Activity definition:

```java
public class MainActivity extends AppCompatActivity
  implements ObservableScrollViewCallbacks {
```

Then implement required methods:

```java
  @Override
  public void onScrollChanged(int scrollY, boolean firstScroll,
    boolean dragging) {
  }

  @Override
  public void onDownMotionEvent() {
  }

  @Override
  public void onUpOrCancelMotionEvent(ScrollState scrollState) {
  }
}
```

Now we can handle the scroll events.

## Populate list data

Before write codes to animate views, set data to ListView.

```java
    // Add these codes after ListView initialization
    ArrayList<String> items = new ArrayList<String>();
    for (int i = 1; i <= 100; i++) {
      items.add("Item " + i);
    }
    listView.setAdapter(new ArrayAdapter<String>(
      this, android.R.layout.simple_list_item_1, items));
```

## Animate with scroll events

Finally, we can write the main code now.
Add some code to show/hide the ActionBar in `onUpOrCancelMotionEvent` method for example.

```java
  @Override
  public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    ActionBar ab = getSupportActionBar();
    if (scrollState == ScrollState.UP) {
      if (ab.isShowing()) {
        ab.hide();
      }
    } else if (scrollState == ScrollState.DOWN) {
      if (!ab.isShowing()) {
        ab.show();
      }
    }
  }
```

`ScrollState` parameter indicates the direction of swiping, and this event will occur when you touch up (or cancel) the ListView.
This is just an introduction so we don't use other events like `onScrollChanged`.

Now let's build and launch the app.

You can see the ActionBar gets hidden or shown when you swipe the ListView.

As you can see, the most important codes are the animation codes in the callbacks.
You can learn how to write these code in this tutorial.

In the [next section](../../docs/example/index.md), we'll check the existing examples to see what we can do with this library.

## Program list

Following codes are the entire Activity, just for your reference.

```java
import android.support.v7.app.AppCompatActivity;
// other imports and package statement are omitted

public class MainActivity extends AppCompatActivity
  implements ObservableScrollViewCallbacks {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ObservableListView listView = (ObservableListView) findViewById(R.id.list);
    listView.setScrollViewCallbacks(this);

    // TODO These are dummy. Populate your data here.
    ArrayList<String> items = new ArrayList<String>();
    for (int i = 1; i <= 100; i++) {
      items.add("Item " + i);
    }
    listView.setAdapter(new ArrayAdapter<String>(
      this, android.R.layout.simple_list_item_1, items));
  }

  @Override
  public void onScrollChanged(int scrollY, boolean firstScroll,
    boolean dragging) {
  }

  @Override
  public void onDownMotionEvent() {
  }

  @Override
  public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    ActionBar ab = getSupportActionBar();
    if (scrollState == ScrollState.UP) {
      if (ab.isShowing()) {
        ab.hide();
      }
    } else if (scrollState == ScrollState.DOWN) {
      if (!ab.isShowing()) {
        ab.show();
      }
    }
  }
}
```

[Next: Try the example app &raquo;](../../docs/example/index.md)


================================================
FILE: docs/quick-start/dependencies.md
================================================
# Dependencies

This library is published to the Maven Central repository, so you can use it through Gradle/Maven.  
You can use it in Eclipse, but Android Studio (or Gradle) is recommended.  
In Quick start guide, we assume you're using Android Studio.

## build.gradle

Write the following dependency configuration to your `build.gradle`.

```gradle
repositories {
    mavenCentral()
}

dependencies {
    // Other dependencies are omitted
    compile 'com.github.ksoichiro:android-observablescrollview:VERSION'
}
```

You should replace `VERSION` to the appropriate version number like `1.5.0`.

Then, click "sync" button to get the library using the configuration above.

To confirm the available versions, search [the Maven Central Repository](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.ksoichiro%22%20AND%20a%3A%22android-observablescrollview%22).

[Next: Layout &raquo;](../../docs/quick-start/layout.md)


================================================
FILE: docs/quick-start/index.md
================================================
# Quick start

Thank you for having interest in this library!  
In this section, I'll show some quick instructions for introducing this library into your app.

1. [Dependencies](../../docs/quick-start/dependencies.md)
1. [Layout](../../docs/quick-start/layout.md)
1. [Animation codes](../../docs/quick-start/animation.md)

[Next: Dependencies &raquo;](../../docs/quick-start/dependencies.md)


================================================
FILE: docs/quick-start/layout.md
================================================
# Layout

After adding the dependency, let's write layout file such as `res/layout/activity_main.xml`.

This time, we'll use only one element `ObservableListView`.

```xml
<com.github.ksoichiro.android.observablescrollview.ObservableListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```

Android-ObservableScrollView provides several types of views that are scroll-able such as `ObservableScrollView`, `ObservableGridView`, etc.  
And they extend the standard widget (`ScrollView`, `GridView`, ...), and they provide some callbacks to get scroll events.

After writing the above layout, you can write animation codes using these callbacks.

[Next: Animation codes &raquo;](../../docs/quick-start/animation.md)


================================================
FILE: docs/reference/_data.json
================================================
{
  "index": {
    "title": "Rerefence"
  },
  "supported-widgets": {
    "title": "Supported widgets"
  },
  "environment": {
    "title": "Environment"
  },
  "release-notes": {
    "title": "Release notes"
  }
}


================================================
FILE: docs/reference/environment.md
================================================
# Environment

## Development

This project is built and tested under the following environment.

* OS: Mac OS X 10.10
* IDE: Android Studio 1.2
* JDK: 1.7

## Prerequisites for building on Android Studio

* Android Studio (1.0.0+)
* Oracle JDK 7
* Android SDK Tools (Rev.24.1.2)
* Android SDK Build-tools (Rev.22.0.1)
* Android 5.1.1 SDK Platform (Rev.2)
* Android Support Repository (Rev.14)
* Android Support Library (Rev.21.1.1)

## Prerequisites for building on Eclipse

* [Eclipse IDE for Java Developers 4.4 (Luna) SR1](https://eclipse.org/downloads/packages/eclipse-ide-java-developers/lunasr1a)
* [Eclipse ADT Plugin](http://developer.android.com/sdk/installing/installing-adt.html)
* Oracle JDK 7
* Android 5.0 SDK Platform (Rev.1+)
* Android Support Repository (Rev.9+)
* Android Support Library (Rev.21.0.2+)


================================================
FILE: docs/reference/index.md
================================================
# Reference

1. [Supported widgets](../../docs/basic/supported-widgets.md)
1. [Environment](../../docs/reference/environment.md)
1. [Release notes](../../docs/reference/release-notes.md)


================================================
FILE: docs/reference/release-notes.md
================================================
# Release notes

* v1.6.0
    * Added header view feature to `ObservableGridView` (#148).
    * Added footer view feature to `ObservableGridView` (#183).
    * Updated `recyclerview-v7` library version to 22.2.0.
    * Fixed ViewPager swiping bug in `ObservableListView` (#185).
    * Fixed NPE in `ObservableRecyclerView` (#149).
* v1.5.2
    * Fix `ObservableGridView` to use first child of line in height calculation.
* v1.5.1
    * Fix `scrollY` of `onScrollChanged` in `ObservableGridView` jumps
      when the first visible item changes.
* v1.5.0
    * Add a helper class `CacheFragmentStatePagerAdapter` to implement ViewPager pattern.
    * Fix that swipe down (over-scroll) causes item click.
* v1.4.0
    * Add a custom view named `TouchInterceptionFrameLayout` and a new API `setTouchInterceptionViewGroup()` for `Scrollable`.  
      With these class and API, you can move `Scrollable` itself using its scrolling events.
    * Add a helper class `ScrollUtils` for implementing scrolling effects.
* v1.3.2
    * Fix that `ObservableRecyclerView` causes `BadParcelableException` on `onRestoreInstanceState`.
* v1.3.1
    * Fix that `onDownMotionEvent` not called and parameters of `onScrollChanged` are incorrect
      when children views handle touch events.
* v1.3.0
    * Add new interface `Scrollable` to provide common API for scrollable widgets. 
* v1.2.1
    * Fix that the scroll states and other internal information are lost after `onSaveInstanceState()`.
    * Fix that the scrollY is incorrect if the ListView/RecyclerView don't scroll from the top.
      (It's just approximating the scroll offset and not the complete solution but better than before.)
* v1.2.0
    * Add GridView support.
    * Fix ObservableListView cannot detect onScrollChanged on Android 2.3.
    * Fix ObservableScrollView cannot detect UP and DOWN state in onUpOrCancelMotionEvent before Android 4.4.
* v1.1.0
    * Add RecyclerView support.
* v1.0.0
    * Initial release.


================================================
FILE: docs/reference/supported-widgets.md
================================================
# Supported widgets

Widgets are named with `Observable` prefix.  
(e.g. `ListView` → `ObservableListView`)  
You can handle these widgets with `Scrollable` interface.

| Widget | Since | Note |
|:------:|:-----:| ---- |
| ListView | v1.0.0 | - |
| ScrollView | v1.0.0 | - |
| WebView | v1.0.0 | - |
| RecyclerView | v1.1.0 | It's supported but RecyclerView provides scroll states and position with [OnScrollListener](https://developer.android.com/reference/android/support/v7/widget/RecyclerView.OnScrollListener.html). You should use it if you don't have any reason. |
| GridView | v1.2.0 | - |


================================================
FILE: gradle/gradle-mvn-push.gradle
================================================
/*
 * 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_NAME.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.groupId = GROUP
                pom.artifactId = POM_ARTIFACT_ID
                pom.version = VERSION_NAME

                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.java.srcDirs
        classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    }

    task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
        classifier = 'javadoc'
        from androidJavadocs.destinationDir
    }

    task androidSourcesJar(type: Jar) {
        classifier = 'sources'
        from android.sourceSets.main.java.sourceFiles
    }

    artifacts {
        archives androidSourcesJar
        archives androidJavadocsJar
    }
}


================================================
FILE: gradle/version.gradle
================================================
// Generate version information to show in the sample app.
// This can be achieved more easily when we use BuildConfig in Gradle and Android Studio,
// but we also support Eclipse so we don't use BuildConfig.

project.ext.versionInfo = new Expando()
project.ext.versionInfo.srcDir = 'version'

// Get git commit hash for naming the APK file if 'git' is available
try {
    project.ext.versionInfo.build = "git rev-parse --short HEAD".execute().text.trim()
} catch (ignored) {
    project.ext.versionInfo.build = "unknown"
}
project.ext.versionInfo.releaseVersionName = project.ext.versionInfo.build

android.sourceSets.findAll { it in android.buildTypes }.each {
    it.java.srcDirs += "src/${project.ext.versionInfo.srcDir}/${it.name}/java"
}

android.buildTypes.each { buildType ->
    task "generateVersionInfo${buildType.name.capitalize()}" << {
        def packageName = android.defaultConfig.applicationId
        def dir = project.file("src/${project.ext.versionInfo.srcDir}/${buildType.name}/java/${packageName.tr('.', '/')}")
        if (dir.exists()) {
            dir.listFiles().each {
                project.delete(it)
            }
        } else {
            project.mkdir(dir)
        }
        def libraryVersion = buildType.name == 'release' ? project.ext.versionInfo.releaseVersionName : project.ext.versionInfo.build
        def className = 'VersionInfo'
        new File(dir, "${className}.java").text = """\
package ${packageName};

// DO NOT EDIT: This file is automatically generated.
public class ${className} {
    public static final String LIBRARY_VERSION = "${libraryVersion}";
    public static final String BUILD = "${project.ext.versionInfo.build}";
}
"""
    }
}

task cleanVersionInfo << {
    def dir = project.file("src/${project.ext.versionInfo.srcDir}")
    if (dir.exists()) {
        dir.listFiles().findAll { it.isDirectory() }.each {
            project.delete(it)
        }
    }
}
clean.dependsOn(tasks['cleanVersionInfo'])

afterEvaluate {
    android.applicationVariants.all {
        tasks["generate${it.name.capitalize()}Sources"].dependsOn("generateVersionInfo${it.buildType.name.capitalize()}")
    }
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip


================================================
FILE: gradle.properties
================================================
VERSION_NAME=1.7.0-SNAPSHOT
SYNCED_VERSION_NAME=1.5.2
GROUP=com.github.ksoichiro

POM_DESCRIPTION=Android library to observe scroll events on scrollable views.
POM_URL=https://github.com/ksoichiro/Android-ObservableScrollView
POM_SCM_URL=https://github.com/ksoichiro/Android-ObservableScrollView
POM_SCM_CONNECTION=scm:git:git://github.com/ksoichiro/Android-ObservableScrollView.git
POM_SCM_DEV_CONNECTION=scm:git:git@github.com:ksoichiro/Android-ObservableScrollView.git
POM_LICENCE_NAME=Apache License 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=ksoichiro
POM_DEVELOPER_NAME=Soichiro Kashima


================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=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.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
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
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((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" ;;
    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=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@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


================================================
FILE: library/.gitignore
================================================
/build


================================================
FILE: library/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?><!--
  Copyright 2014 Soichiro Kashima

  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.
-->
<manifest package="com.github.ksoichiro.android.observablescrollview">
</manifest>


================================================
FILE: library/build.gradle
================================================
apply plugin: 'com.android.library'

dependencies {
    compile 'com.android.support:recyclerview-v7:23.1.1'
    androidTestCompile ('com.android.support:appcompat-v7:23.1.1') {
        exclude module: 'support-v4'
    }
    androidTestCompile ('com.nineoldandroids:library:2.4.0') {
        exclude module: 'support-v4'
    }
}

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 9
    }

    buildTypes {
        debug {
            testCoverageEnabled = true
        }
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            res.srcDirs = ['res']
        }
    }

    lintOptions {
        abortOnError false
    }
}

// When testing on Travis CI,
// connectedCheck task doesn't output logs for more than 10 minutes often,
// which causes build failure.
// To avoid this, we change the log level for test tasks.
// Test tasks for buildTypes will be defined on evaluation phase,
// so do it on afterEvaluate.
afterEvaluate { project ->
    tasks.withType(VerificationTask) {
        logging.level = LogLevel.INFO
    }
}

apply plugin: 'com.github.kt3k.coveralls'

coveralls.jacocoReportPath = 'build/reports/coverage/debug/report.xml'

// This is from 'https://github.com/chrisbanes/gradle-mvn-push'
apply from: "${rootDir}/gradle/gradle-mvn-push.gradle"


================================================
FILE: library/gradle.properties
================================================
POM_NAME=Android-ObservableScrollView
POM_ARTIFACT_ID=android-observablescrollview
POM_PACKAGING=aar


================================================
FILE: library/res/.gitkeep
================================================


================================================
FILE: library/src/androidTest/AndroidManifest.xml
================================================
<!--
  Copyright 2014 Soichiro Kashima

  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.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.github.ksoichiro.android.observablescrollview.test">

    <application>
        <uses-library android:name="android.test.runner" />
        <activity android:name=".GridViewActivity" />
        <activity android:name=".HeaderGridViewActivity" />
        <activity android:name=".ListViewActivity" />
        <activity android:name=".ListViewScrollFromBottomActivity" />
        <activity android:name=".RecyclerViewActivity" />
        <activity android:name=".RecyclerViewScrollFromBottomActivity" />
        <activity android:name=".ScrollViewActivity" />
        <activity android:name=".TouchInterceptionGridViewActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".TouchInterceptionListViewActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".TouchInterceptionRecyclerViewActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".TouchInterceptionScrollViewActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".TouchInterceptionWebViewActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".ViewPagerTabActivity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".ViewPagerTab2Activity" android:theme="@style/AppTheme.Toolbar" />
        <activity android:name=".WebViewActivity" />
    </application>

</manifest>


================================================
FILE: library/src/androidTest/assets/lipsum.html
================================================
<html>
<head>
<style type="text/css">
#container {
padding: 1em;
}
</style>
</head>
<body>
<div id="container">
<p>Lorem ipsum dolor sit amet, ut duis lorem provident sed felis blandit, condimentum donec lectus ipsum et mauris, morbi porttitor interdum feugiat nulla donec sodales, vestibulum nisl primis a molestie vestibulum quam, sapien mauris metus risus suspendisse magnis. Augue viverra nulla faucibus egestas eu, a etiam id congue rutrum ante, arcu tincidunt donec quam felis at ornare, iaculis ligula sodales venenatis commodo volutpat neque, suspendisse elit praesent tellus felis mi amet. Inceptos amet tempor lectus lorem est non, ac donec ac libero neque mauris, tellus ante metus eget leo consequat. Scelerisque dolor curabitur pretium blandit ut feugiat, amet lacus pulvinar justo convallis ut, sed natoque ipsum urna posuere nibh eu. Sed at sed vulputate sit orci, facilisis a aliquam tellus quam aliquam, eu aliquam donec at molestie ante, pellentesque mauris lorem ultrices libero faucibus porta, imperdiet adipiscing sit hac diam ut nulla. Lacus enim elit pulvinar donec vehicula dapibus, accumsan purus officia cursus dolor sapien, eu amet dis mauris mi nulla ut. Non accusamus etiam pede non urna tempus, vestibulum aliquam tortor eget pharetra sodales, in vestibulum ut justo orci nulla, lobortis purus sem semper consectetuer magni purus. Dolor a leo vestibulum amet ut sit, arcu ut eaque urna fusce aliquet turpis, sed fermentum sed vestibulum nisl pede, tristique enim lorem posuere in laborum ut. Vestibulum id id justo leo nulla, magna lobortis ullamcorper et dignissim pellentesque, duis suspendisse quis id lorem ante. Vivamus a nullam ante adipiscing amet, mi vel consectetuer nunc aenean pede quisque, eget rhoncus dis porttitor habitant nunc vivamus, duis cubilia blandit non donec justo dictumst, praesent vitae nulla nam pulvinar urna. Adipiscing adipiscing justo urna pulvinar imperdiet nullam, vitae fusce rhoncus proin nonummy suscipit, ullamcorper amet et non potenti platea ultrices, mauris nullam sapien nunc justo vel, eu semper pellentesque arcu fusce augue. Malesuada mauris nibh sit a a scelerisque, velit sem lectus tellus convallis consectetuer, ultricies auctor a ante eros amet sed.</p>
<p>Risus lacus duis leo platea wisi, felis maecenas rutrum in id in donec, non id a potenti libero eget, posuere elit ea sed pellentesque quis. Sunt lacus urna lorem elit duis, nibh donec purus quisque consectetuer dolor, neque vestibulum proin ornare eros nonummy phasellus. Iaculis cras eu at egestas dolor montes, viverra quisque malesuada consectetuer semper maecenas, a sed vitae donec tempor aliqua metus, ornare mollis suscipit et erat fusce, sit orci aut auctor elementum fames aliquam. Platea dui integer magnis non metus, minus dignissimos ante massa nostra et, rutrum sapien egestas quis sapien donec donec. Erat sit a eros aenean natoque, quam libero id lorem enim proin, lorem ipsum fermentum mattis metus et. Aliquam aliquet suscipit purus conubia at neque, platea vivamus vestibulum nulla quibusdam senectus, et morbi lectus malesuada gravida donec, elementum sit convallis pellentesque velit amet. Et eveniet viverra vehicula consectetuer justo, provident sed commodo non lacinia velit, tempor phasellus vel leo nisl cras, vivamus et arcu interdum dui eu amet. Volutpat wisi rhoncus vel turpis diam quibusdam, dapibus elit est quisque cubilia mauris, nulla elit magna tempor accumsan bibendum, lorem varius sed interdum eget mattis, scelerisque egestas feugiat donec dui molestie. Leo facilisis nisl sit montes ligula sed, enim commodo consectetuer nunc est et, ut sed vehicula dolor luctus elit. Fermentum cras donec eget nibh est vel, sed justo risus et pharetra diam, eu vivamus egestas ligula risus diam, sed justo eget hac ut mauris. Vestibulum diam nec vitae mi eget suspendisse, aenean arcu purus facilisis purus class in, id aliquam sit id scelerisque sapien etiam. Ut nullam sit sed at mauris lobortis, consequat dolor autem ipsum euismod nulla, elit quis proin eget conubia varius, erat arcu massa mus in mauris, scelerisque ut eu sollicitudin libero leo urna.</p>
<p>Consectetuer luctus tempor elit ut dolor ligula, quis dui per dui hendrerit ante sagittis, in quisque pretium in eleifend enim. Condimentum iaculis vitae feugiat dis tellus vel, lectus dolor nec dui nulla nascetur, et pellentesque curabitur lorem leo velit eget. Id nascetur arcu lobortis suspendisse imperdiet urna, natoque nascetur ante in porta a, interdum hendrerit mi bibendum platea tellus, urna in enim ornare vestibulum faucibus enim. Leo fusce egestas ante nec volutpat, in tempor vel facilisis potenti ut, pede at non lorem a commodo, nulla dolor orci interdum vestibulum nulla. Dui nulla vestibulum quisque a pharetra porta, integer nec ipsum nec sed dui pharetra, magna et dignissim ipsum sed dictum, litora eros vivamus scelerisque libero ipsum. Sed ac ac lorem molestie adipiscing morbi, pellentesque imperdiet nunc quis morbi amet ante, libero dui ligula nec risus neque et, velit nonummy phasellus et facilisi amet, ligula in elementum non sapien pulvinar faucibus. Eu leo ut posuere sed aliquet, tincidunt vel urna volutpat tempus sem, sit felis aliquet vestibulum condimentum sit, amet nibh vel tellus purus ullamcorper libero, nulla vestibulum pede ut vestibulum pretium. Eu nulla vestibulum a neque in metus, quisquam nam sed cursus eget luctus, pede ultrices nec sed dignissim pellentesque, sit class cursus metus nulla placerat mauris, consequat mollis neque vivamus amet pede. Mauris dolor nulla diam eros bibendum, quam ante vestibulum morbi non ligula vel, molestie curabitur rhoncus nulla euismod interdum non. Nulla fringilla lorem mollis ad massa, sit molestie nibh lorem arcu volutpat, accumsan commodo lectus eu et donec, sit tempor tempus rutrum in curabitur amet. Nec urna euismod a tincidunt commodo, eu pede turpis libero vitae viverra, ante vestibulum nam non habitasse potenti, mauris imperdiet in in nunc convallis. Et nostra wisi in est accumsan vehicula, quisque vitae felis mauris sed vulputate nec, ante imperdiet sollicitudin massa iaculis massa sit.</p>
<p>Quam libero nulla netus eu porta curae, ut nulla bibendum facilisis et urna sed, quis congue vestibulum aliquam interdum etiam. Nulla vel lobortis ullamcorper vitae excepturi, neque urna feugiat lectus vel lacinia, massa pretium orci eu metus neque vulputate. Imperdiet ac velit rhoncus nulla malesuada nullam, nec pulvinar justo gravida lorem rutrum magna, habitasse repudiandae mi eros vestibulum ante, nec euismod dui iaculis in turpis pretium, ac id metus egestas proin lacus lectus. Laoreet lorem nec vitae risus erat arcu, vitae quam ut in ante tristique, porta dolor pede quam et odio nam, arcu lacus sem congue ante cursus massa. Et mattis sagittis erat accumsan fusce quam, vehicula ligula beatae natoque fusce sodales conubia, habitasse metus cum magnis viverra nam cursus, egestas urna wisi primis blandit eu magna, eget libero elit lacus lorem dis aliquam. Ut mauris ante natoque lacus massa, justo a lectus sodales enim adipiscing id, accumsan ut ipsum vestibulum sed enim auctor, vitae congue tincidunt id phasellus lacinia scelerisque, tincidunt sapien nulla euismod volutpat iaculis. Platea sociis nec aliquet nec molestie, in mi et augue sapien in vivamus, integer fames proin vitae in ullamcorper et. Fringilla etiam sapiente rhoncus suspendisse nec id, lobortis cras eget egestas dui ac nec, justo lacus ut lorem bibendum quia eros, eget a gravida id donec nunc suscipit, porta sed in sodales non rutrum. Lectus vel dui elementum pellentesque magna aliquam, vitae non sit pede et fusce nibh, id id deserunt ornare dui sit condimentum, in adipiscing imperdiet turpis nam aliquet, facilisis metus magna lacus wisi facilisis tortor. Vulputate elit accumsan quam amet ligula, suspendisse lacus mi nonummy integer urna, libero nulla nunc varius in odio, laoreet nulla amet placerat amet nec. Consectetuer vel massa hendrerit vitae iaculis id, sed ut ut laudantium odio in, elit vestibulum duis ante maecenas interdum in, neque vehicula ultrices varius in quam, pede tellus pellentesque sed nullam quis.</p>
</div>
</body>
</html>

================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/SavedStateTest.java
================================================
package com.github.ksoichiro.android.observablescrollview;

import android.os.Parcel;
import android.test.InstrumentationTestCase;
import android.util.SparseIntArray;
import android.view.AbsSavedState;

public class SavedStateTest extends InstrumentationTestCase {

    public void testGridViewSavedState() throws Throwable {
        Parcel parcel = Parcel.obtain();
        ObservableGridView.SavedState state1 = new ObservableGridView.SavedState(AbsSavedState.EMPTY_STATE);
        state1.prevFirstVisiblePosition = 1;
        state1.prevFirstVisibleChildHeight = 2;
        state1.prevScrolledChildrenHeight = 3;
        state1.prevScrollY = 4;
        state1.scrollY = 5;
        state1.childrenHeights = new SparseIntArray();
        state1.childrenHeights.put(0, 10);
        state1.childrenHeights.put(1, 20);
        state1.childrenHeights.put(2, 30);
        state1.writeToParcel(parcel, 0);

        parcel.setDataPosition(0);

        ObservableGridView.SavedState state2 = ObservableGridView.SavedState.CREATOR.createFromParcel(parcel);
        assertNotNull(state2);
        assertEquals(state1.prevFirstVisiblePosition, state2.prevFirstVisiblePosition);
        assertEquals(state1.prevFirstVisibleChildHeight, state2.prevFirstVisibleChildHeight);
        assertEquals(state1.prevScrolledChildrenHeight, state2.prevScrolledChildrenHeight);
        assertEquals(state1.prevScrollY, state2.prevScrollY);
        assertEquals(state1.scrollY, state2.scrollY);
        assertNotNull(state1.childrenHeights);
        assertEquals(3, state1.childrenHeights.size());
        assertEquals(10, state1.childrenHeights.get(0));
        assertEquals(20, state1.childrenHeights.get(1));
        assertEquals(30, state1.childrenHeights.get(2));
    }

    public void testListViewSavedState() throws Throwable {
        Parcel parcel = Parcel.obtain();
        ObservableListView.SavedState state1 = new ObservableListView.SavedState(AbsSavedState.EMPTY_STATE);
        state1.prevFirstVisiblePosition = 1;
        state1.prevFirstVisibleChildHeight = 2;
        state1.prevScrolledChildrenHeight = 3;
        state1.prevScrollY = 4;
        state1.scrollY = 5;
        state1.childrenHeights = new SparseIntArray();
        state1.childrenHeights.put(0, 10);
        state1.childrenHeights.put(1, 20);
        state1.childrenHeights.put(2, 30);
        state1.writeToParcel(parcel, 0);

        parcel.setDataPosition(0);

        ObservableListView.SavedState state2 = ObservableListView.SavedState.CREATOR.createFromParcel(parcel);
        assertNotNull(state2);
        assertEquals(state1.prevFirstVisiblePosition, state2.prevFirstVisiblePosition);
        assertEquals(state1.prevFirstVisibleChildHeight, state2.prevFirstVisibleChildHeight);
        assertEquals(state1.prevScrolledChildrenHeight, state2.prevScrolledChildrenHeight);
        assertEquals(state1.prevScrollY, state2.prevScrollY);
        assertEquals(state1.scrollY, state2.scrollY);
        assertNotNull(state1.childrenHeights);
        assertEquals(3, state1.childrenHeights.size());
        assertEquals(10, state1.childrenHeights.get(0));
        assertEquals(20, state1.childrenHeights.get(1));
        assertEquals(30, state1.childrenHeights.get(2));
    }

    public void testRecyclerViewSavedState() throws Throwable {
        Parcel parcel = Parcel.obtain();
        ObservableRecyclerView.SavedState state1 = new ObservableRecyclerView.SavedState(AbsSavedState.EMPTY_STATE);
        state1.prevFirstVisiblePosition = 1;
        state1.prevFirstVisibleChildHeight = 2;
        state1.prevScrolledChildrenHeight = 3;
        state1.prevScrollY = 4;
        state1.scrollY = 5;
        state1.childrenHeights = new SparseIntArray();
        state1.childrenHeights.put(0, 10);
        state1.childrenHeights.put(1, 20);
        state1.childrenHeights.put(2, 30);
        state1.writeToParcel(parcel, 0);

        parcel.setDataPosition(0);

        ObservableRecyclerView.SavedState state2 = ObservableRecyclerView.SavedState.CREATOR.createFromParcel(parcel);
        assertNotNull(state2);
        assertEquals(state1.prevFirstVisiblePosition, state2.prevFirstVisiblePosition);
        assertEquals(state1.prevFirstVisibleChildHeight, state2.prevFirstVisibleChildHeight);
        assertEquals(state1.prevScrolledChildrenHeight, state2.prevScrolledChildrenHeight);
        assertEquals(state1.prevScrollY, state2.prevScrollY);
        assertEquals(state1.scrollY, state2.scrollY);
        assertNotNull(state1.childrenHeights);
        assertEquals(3, state1.childrenHeights.size());
        assertEquals(10, state1.childrenHeights.get(0));
        assertEquals(20, state1.childrenHeights.get(1));
        assertEquals(30, state1.childrenHeights.get(2));
    }

    public void testScrollViewSavedState() throws Throwable {
        Parcel parcel = Parcel.obtain();
        ObservableScrollView.SavedState state1 = new ObservableScrollView.SavedState(AbsSavedState.EMPTY_STATE);
        state1.prevScrollY = 1;
        state1.scrollY = 2;
        state1.writeToParcel(parcel, 0);

        parcel.setDataPosition(0);

        ObservableScrollView.SavedState state2 = ObservableScrollView.SavedState.CREATOR.createFromParcel(parcel);
        assertNotNull(state2);
        assertEquals(state1.prevScrollY, state2.prevScrollY);
        assertEquals(state1.scrollY, state2.scrollY);
    }

    public void testWebViewSavedState() throws Throwable {
        Parcel parcel = Parcel.obtain();
        ObservableWebView.SavedState state1 = new ObservableWebView.SavedState(AbsSavedState.EMPTY_STATE);
        state1.prevScrollY = 1;
        state1.scrollY = 2;
        state1.writeToParcel(parcel, 0);

        parcel.setDataPosition(0);

        ObservableWebView.SavedState state2 = ObservableWebView.SavedState.CREATOR.createFromParcel(parcel);
        assertNotNull(state2);
        assertEquals(state1.prevScrollY, state2.prevScrollY);
        assertEquals(state1.scrollY, state2.scrollY);
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.AbsListView;

import com.github.ksoichiro.android.observablescrollview.ObservableGridView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class GridViewActivity extends Activity implements ObservableScrollViewCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gridview);
        ObservableGridView scrollable = (ObservableGridView) findViewById(R.id.scrollable);
        scrollable.setScrollViewCallbacks(this);
        UiTestUtils.setDummyData(this, scrollable);
        scrollable.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });
    }

    @Override
    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    }

    @Override
    public void onDownMotionEvent() {
    }

    @Override
    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;

import com.github.ksoichiro.android.observablescrollview.ObservableGridView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class GridViewActivityTest extends ActivityInstrumentationTestCase2<GridViewActivity> {

    private Activity activity;
    private ObservableGridView scrollable;
    private int[] callbackCounter;

    public GridViewActivityTest() {
        super(GridViewActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableGridView) activity.findViewById(R.id.scrollable);
        callbackCounter = new int[2];
    }

    public void testInitialize() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                new ObservableGridView(activity);
                new ObservableGridView(activity, null, 0);
            }
        });
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();
    }

    public void testSaveAndRestoreInstanceState() throws Throwable {
        UiTestUtils.saveAndRestoreInstanceState(this, activity);
        testScroll();
    }

    public void testScrollVerticallyTo() throws Throwable {
        final DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, metrics));
            }
        });
        getInstrumentation().waitForIdleSync();

        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo(0);
            }
        });
        getInstrumentation().waitForIdleSync();
    }

    public void testNoCallbacks() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableGridView) activity.findViewById(R.id.scrollable);
                scrollable.setScrollViewCallbacks(null);
            }
        });
        testScroll();
    }

    public void testCallbacks() throws Throwable {
        final ObservableScrollViewCallbacks[] callbacks = new ObservableScrollViewCallbacks[2];
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableGridView) activity.findViewById(R.id.scrollable);
                callbacks[0] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[0]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[0]);
                callbacks[1] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[1]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[1]);
            }
        });
        testScroll();
        // Assert that all the callbacks are enabled and get called.
        assertTrue(0 < callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Remove one of the callbacks and scroll again to assert it's really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.removeScrollViewCallbacks(callbacks[0]);
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Clear all callbacks and assert they're really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.clearScrollViewCallbacks();
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 == callbackCounter[1]);
    }

    public void testCannotAddHeaderOrFooterWhenAdapterIsAlreadySet() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    View view = new View(activity);
                    final int flexibleSpaceImageHeight = activity.getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
                    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, flexibleSpaceImageHeight);
                    view.setLayoutParams(lp);
                    view.setClickable(true);
                    scrollable.addHeaderView(view);
                    fail();
                } catch (IllegalStateException ignore) {
                }

                try {
                    View view = new View(activity);
                    final int flexibleSpaceImageHeight = activity.getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
                    FrameLayout.LayoutParams lpf = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, flexibleSpaceImageHeight);
                    view.setLayoutParams(lpf);
                    scrollable.addFooterView(view);
                    fail();
                } catch (IllegalStateException ignore) {
                }
            }
        });
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AbsListView;
import android.widget.FrameLayout;

import com.github.ksoichiro.android.observablescrollview.ObservableGridView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class HeaderGridViewActivity extends Activity implements ObservableScrollViewCallbacks {

    public View headerView;
    public View footerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gridview);
        ObservableGridView scrollable = (ObservableGridView) findViewById(R.id.scrollable);
        // Set padding view for GridView. This is the flexible space.
        headerView = new View(this);
        final int flexibleSpaceImageHeight = getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                flexibleSpaceImageHeight);
        headerView.setLayoutParams(lp);

        // This is required to disable header's list selector effect
        headerView.setClickable(true);

        scrollable.addHeaderView(headerView);

        // Footer is also available.
        footerView = new View(this);
        FrameLayout.LayoutParams lpf = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
            flexibleSpaceImageHeight);
        footerView.setLayoutParams(lpf);
        scrollable.addFooterView(footerView);

        scrollable.setScrollViewCallbacks(this);
        UiTestUtils.setDummyData(this, scrollable);
        scrollable.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });
    }

    @Override
    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    }

    @Override
    public void onDownMotionEvent() {
    }

    @Override
    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.SimpleAdapter;

import com.github.ksoichiro.android.observablescrollview.ObservableGridView;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class HeaderGridViewActivityTest extends ActivityInstrumentationTestCase2<HeaderGridViewActivity> {

    private HeaderGridViewActivity activity;
    private ObservableGridView scrollable;

    public HeaderGridViewActivityTest() {
        super(HeaderGridViewActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableGridView) activity.findViewById(R.id.scrollable);
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();
    }

    public void testSaveAndRestoreInstanceState() throws Throwable {
        UiTestUtils.saveAndRestoreInstanceState(this, activity);
        testScroll();
    }

    public void testScrollVerticallyTo() throws Throwable {
        final DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, metrics));
            }
        });
        getInstrumentation().waitForIdleSync();

        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo(0);
            }
        });
        getInstrumentation().waitForIdleSync();
    }

    public void testHeaderViewFeatures() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                assertEquals(1, scrollable.getHeaderViewCount());
                assertEquals(1, scrollable.getFooterViewCount());
                ListAdapter adapter = scrollable.getAdapter();
                assertTrue(adapter instanceof ObservableGridView.HeaderViewGridAdapter);
                ObservableGridView.HeaderViewGridAdapter hvgAdapter = (ObservableGridView.HeaderViewGridAdapter) adapter;
                assertEquals(1, hvgAdapter.getHeadersCount());
                assertEquals(1, hvgAdapter.getFootersCount());
                assertNotNull(hvgAdapter.getWrappedAdapter());
                assertTrue(hvgAdapter.areAllItemsEnabled());
                assertFalse(hvgAdapter.isEmpty());
                Object data = hvgAdapter.getItem(0);
                assertNull(data);
                assertNotNull(hvgAdapter.getView(0, null, scrollable));
                assertNotNull(hvgAdapter.getView(1, null, scrollable));
                assertNotNull(hvgAdapter.getFilter());
                assertTrue(scrollable.removeHeaderView(activity.headerView));
                assertEquals(0, scrollable.getHeaderViewCount());
                assertEquals(0, hvgAdapter.getHeadersCount());
                assertFalse(scrollable.removeHeaderView(activity.headerView));

                activity.headerView = new View(activity);
                final int flexibleSpaceImageHeight = activity.getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
                FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    flexibleSpaceImageHeight);
                activity.headerView.setLayoutParams(lp);

                // This is required to disable header's list selector effect
                activity.headerView.setClickable(true);

                scrollable.addHeaderView(activity.headerView);

                assertEquals(100/* items */ + 2/* header */ + 2/* footer */, hvgAdapter.getCount());
                assertEquals(1, hvgAdapter.getHeadersCount());
                assertEquals(2, hvgAdapter.getNumColumns());
                // If the header is added by addHeader(View),
                // HeaderViewGridAdapter doesn't contain any associated data.
                // headerData does NOT mean the view.
                // If we want to get the view, we should use getView().
                assertNull(hvgAdapter.getItem(0));
                assertNull(hvgAdapter.getItem(1));

                assertEquals(1, hvgAdapter.getFootersCount());
                assertNull(hvgAdapter.getItem(100/* items */ + 2/* header */ + 2/* footer */ - 1 - 1));
                assertNull(hvgAdapter.getItem(100/* items */ + 2/* header */ + 2/* footer */ - 1));
            }
        });
        // Scroll to bottom and try removing re-adding the footer view.
        for (int i = 0; i < 10; i++) {
            UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        }
        getInstrumentation().waitForIdleSync();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                ListAdapter adapter = scrollable.getAdapter();
                ObservableGridView.HeaderViewGridAdapter hvgAdapter = (ObservableGridView.HeaderViewGridAdapter) adapter;

                assertTrue(scrollable.removeFooterView(activity.footerView));
                assertEquals(0, scrollable.getFooterViewCount());
                assertEquals(0, hvgAdapter.getFootersCount());
                assertFalse(scrollable.removeFooterView(activity.footerView));

                activity.footerView = new View(activity);
                final int flexibleSpaceImageHeight = activity.getResources().getDimensionPixelSize(R.dimen.flexible_space_image_height);
                FrameLayout.LayoutParams lpf = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    flexibleSpaceImageHeight);
                activity.footerView.setLayoutParams(lpf);
                scrollable.addFooterView(activity.footerView);
            }
        });
    }

    public void testHeaderViewGridExceptions() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    new ObservableGridView.HeaderViewGridAdapter(null, null, null);
                } catch (IllegalArgumentException e) {
                    fail();
                }
                ListAdapter adapter = scrollable.getAdapter();
                ObservableGridView.HeaderViewGridAdapter hvgAdapter = (ObservableGridView.HeaderViewGridAdapter) adapter;
                try {
                    hvgAdapter.setNumColumns(0);
                } catch (IllegalArgumentException e) {
                    fail();
                }
                ArrayList<ObservableGridView.FixedViewInfo> headerViewInfos = new ArrayList<>();
                ObservableGridView.HeaderViewGridAdapter adapter1 = new ObservableGridView.HeaderViewGridAdapter(headerViewInfos, null, null);
                assertTrue(adapter1.isEmpty());
                try {
                    adapter1.isEnabled(-1);
                    fail();
                } catch (ArrayIndexOutOfBoundsException ignore) {
                }
                try {
                    adapter1.getItem(-1);
                    fail();
                } catch (ArrayIndexOutOfBoundsException ignore) {
                }
                try {
                    adapter1.getView(0, null, null);
                    fail();
                } catch (ArrayIndexOutOfBoundsException ignore) {
                }
                try {
                    adapter1.getView(-1, null, scrollable);
                    fail();
                } catch (ArrayIndexOutOfBoundsException ignore) {
                }
            }
        });
    }

    public void testHeaderViewGridAdapter() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    new ObservableGridView.HeaderViewGridAdapter(null, null, null);
                } catch (IllegalArgumentException ignore) {
                    fail();
                }
            }
        });
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                ArrayList<ObservableGridView.FixedViewInfo> list = new ArrayList<>();
                Map<String, String> map = new LinkedHashMap<>();
                map.put("text", "A");
                List<Map<String, ?>> data = new ArrayList<>();
                data.add(map);
                ObservableGridView.HeaderViewGridAdapter adapter =
                    new ObservableGridView.HeaderViewGridAdapter(
                        list,
                        null,
                        new SimpleAdapter(
                            activity,
                            data,
                            android.R.layout.simple_list_item_1,
                            new String[]{"text"},
                            new int[]{android.R.id.text1}));
                assertFalse(adapter.removeHeader(null));
                assertEquals(1, adapter.getCount());
            }
        });
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                ArrayList<ObservableGridView.FixedViewInfo> list = new ArrayList<>();
                ObservableGridView.HeaderViewGridAdapter adapter =
                    new ObservableGridView.HeaderViewGridAdapter(
                        list,
                        null,
                        null);
                assertEquals(0, adapter.getCount());
                try {
                    adapter.isEnabled(1);
                    fail();
                } catch (IndexOutOfBoundsException ignore) {
                }
                try {
                    adapter.getItem(1);
                    fail();
                } catch (IndexOutOfBoundsException ignore) {
                }
            }
        });
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.AbsListView;

import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class ListViewActivity extends Activity implements ObservableScrollViewCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listview);
        ObservableListView scrollable = (ObservableListView) findViewById(R.id.scrollable);
        scrollable.setScrollViewCallbacks(this);
        UiTestUtils.setDummyData(this, scrollable);
        scrollable.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });
    }

    @Override
    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    }

    @Override
    public void onDownMotionEvent() {
    }

    @Override
    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
import android.util.TypedValue;

import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class ListViewActivityTest extends ActivityInstrumentationTestCase2<ListViewActivity> {

    private Activity activity;
    private ObservableListView scrollable;
    private int[] callbackCounter;

    public ListViewActivityTest() {
        super(ListViewActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableListView) activity.findViewById(R.id.scrollable);
        callbackCounter = new int[2];
    }

    public void testInitialize() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                new ObservableListView(activity);
                new ObservableListView(activity, null, 0);
            }
        });
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();
    }

    public void testSaveAndRestoreInstanceState() throws Throwable {
        UiTestUtils.saveAndRestoreInstanceState(this, activity);
        testScroll();
    }

    public void testScrollVerticallyTo() throws Throwable {
        final DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, metrics));
            }
        });
        getInstrumentation().waitForIdleSync();

        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo(0);
            }
        });
        getInstrumentation().waitForIdleSync();
    }

    public void testNoCallbacks() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableListView) activity.findViewById(R.id.scrollable);
                scrollable.setScrollViewCallbacks(null);
            }
        });
        testScroll();
    }

    public void testCallbacks() throws Throwable {
        final ObservableScrollViewCallbacks[] callbacks = new ObservableScrollViewCallbacks[2];
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableListView) activity.findViewById(R.id.scrollable);
                callbacks[0] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[0]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[0]);
                callbacks[1] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[1]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[1]);
            }
        });
        testScroll();
        // Assert that all the callbacks are enabled and get called.
        assertTrue(0 < callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Remove one of the callbacks and scroll again to assert it's really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.removeScrollViewCallbacks(callbacks[0]);
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Clear all callbacks and assert they're really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.clearScrollViewCallbacks();
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 == callbackCounter[1]);
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.os.Bundle;

import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.github.ksoichiro.android.observablescrollview.ScrollUtils;

public class ListViewScrollFromBottomActivity extends ListViewActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ObservableListView scrollable = (ObservableListView) findViewById(R.id.scrollable);
        ScrollUtils.addOnGlobalLayoutListener(scrollable, new Runnable() {
            @Override
            public void run() {
                int count = scrollable.getAdapter().getCount() - 1;
                int position = count == 0 ? 1 : count > 0 ? count : 0;
                scrollable.smoothScrollToPosition(position);
                scrollable.setSelection(position);
            }
        });
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;

import com.github.ksoichiro.android.observablescrollview.ObservableListView;

public class ListViewScrollFromBottomActivityTest extends ActivityInstrumentationTestCase2<ListViewScrollFromBottomActivity> {

    private Activity activity;
    private ObservableListView scrollable;

    public ListViewScrollFromBottomActivityTest() {
        super(ListViewScrollFromBottomActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableListView) activity.findViewById(R.id.scrollable);
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;

import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class RecyclerViewActivity extends Activity implements ObservableScrollViewCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);

        ObservableRecyclerView recyclerView = (ObservableRecyclerView) findViewById(R.id.scrollable);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setHasFixedSize(true);
        recyclerView.setScrollViewCallbacks(this);
        UiTestUtils.setDummyData(this, recyclerView);
    }

    @Override
    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    }

    @Override
    public void onDownMotionEvent() {
    }

    @Override
    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;
import android.util.DisplayMetrics;
import android.util.TypedValue;

import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class RecyclerViewActivityTest extends ActivityInstrumentationTestCase2<RecyclerViewActivity> {

    private Activity activity;
    private ObservableRecyclerView scrollable;
    private int[] callbackCounter;

    public RecyclerViewActivityTest() {
        super(RecyclerViewActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableRecyclerView) activity.findViewById(R.id.scrollable);
        callbackCounter = new int[2];
        getInstrumentation().waitForIdleSync();
    }

    public void testInitialize() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                new ObservableRecyclerView(activity);
                new ObservableRecyclerView(activity, null, 0);
            }
        });
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();
    }

    public void testSaveAndRestoreInstanceState() throws Throwable {
        UiTestUtils.saveAndRestoreInstanceState(this, activity);
        testScroll();
    }

    public void testScrollVerticallyTo() throws Throwable {
        final DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, metrics));
            }
        });
        getInstrumentation().waitForIdleSync();

        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.scrollVerticallyTo(0);
            }
        });
        getInstrumentation().waitForIdleSync();
    }

    public void testNoCallbacks() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableRecyclerView) activity.findViewById(R.id.scrollable);
                scrollable.setScrollViewCallbacks(null);
            }
        });
        testScroll();
    }

    public void testCallbacks() throws Throwable {
        final ObservableScrollViewCallbacks[] callbacks = new ObservableScrollViewCallbacks[2];
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableRecyclerView) activity.findViewById(R.id.scrollable);
                callbacks[0] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[0]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[0]);
                callbacks[1] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[1]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[1]);
            }
        });
        testScroll();
        // Assert that all the callbacks are enabled and get called.
        assertTrue(0 < callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Remove one of the callbacks and scroll again to assert it's really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.removeScrollViewCallbacks(callbacks[0]);
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Clear all callbacks and assert they're really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.clearScrollViewCallbacks();
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 == callbackCounter[1]);
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.os.Bundle;

import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;
import com.github.ksoichiro.android.observablescrollview.ScrollUtils;

public class RecyclerViewScrollFromBottomActivity extends RecyclerViewActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ObservableRecyclerView scrollable = (ObservableRecyclerView) findViewById(R.id.scrollable);
        ScrollUtils.addOnGlobalLayoutListener(scrollable, new Runnable() {
            @Override
            public void run() {
                int count = scrollable.getAdapter().getItemCount() - 1;
                int position = count == 0 ? 1 : count > 0 ? count : 0;
                scrollable.scrollToPosition(position);
            }
        });
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;

import com.github.ksoichiro.android.observablescrollview.ObservableListView;
import com.github.ksoichiro.android.observablescrollview.ObservableRecyclerView;

public class RecyclerViewScrollFromBottomActivityTest extends ActivityInstrumentationTestCase2<RecyclerViewScrollFromBottomActivity> {

    private Activity activity;
    private ObservableRecyclerView scrollable;

    public RecyclerViewScrollFromBottomActivityTest() {
        super(RecyclerViewScrollFromBottomActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableRecyclerView) activity.findViewById(R.id.scrollable);
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollUtilsTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.graphics.Color;
import android.test.InstrumentationTestCase;

import com.github.ksoichiro.android.observablescrollview.ScrollUtils;

import junit.framework.Assert;

public class ScrollUtilsTest extends InstrumentationTestCase {

    public void testGetFloat() {
        Assert.assertEquals(1.0f, ScrollUtils.getFloat(1, 0, 2));
        assertEquals(0.0f, ScrollUtils.getFloat(-1, 0, 2));
        assertEquals(2.0f, ScrollUtils.getFloat(3, 0, 2));
    }

    public void testGetColorWithAlpha() {
        assertEquals(Color.parseColor("#00123456"), ScrollUtils.getColorWithAlpha(0, Color.parseColor("#FF123456")));
        assertEquals(Color.parseColor("#FF123456"), ScrollUtils.getColorWithAlpha(1, Color.parseColor("#FF123456")));
    }

    public void testMixColors() {
        assertEquals(Color.parseColor("#000000"), ScrollUtils.mixColors(Color.parseColor("#000000"), Color.parseColor("#FFFFFF"), 0));
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivity.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.os.Bundle;

import com.github.ksoichiro.android.observablescrollview.ObservableScrollView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;
import com.github.ksoichiro.android.observablescrollview.Scrollable;

public class ScrollViewActivity extends Activity implements ObservableScrollViewCallbacks {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scrollview);
        ((Scrollable) findViewById(R.id.scrollable)).setScrollViewCallbacks(this);
    }

    @Override
    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    }

    @Override
    public void onDownMotionEvent() {
    }

    @Override
    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivityTest.java
================================================
package com.github.ksoichiro.android.observablescrollview.test;

import android.app.Activity;
import android.test.ActivityInstrumentationTestCase2;

import com.github.ksoichiro.android.observablescrollview.ObservableScrollView;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollViewCallbacks;
import com.github.ksoichiro.android.observablescrollview.ScrollState;

public class ScrollViewActivityTest extends ActivityInstrumentationTestCase2<ScrollViewActivity> {

    private Activity activity;
    private ObservableScrollView scrollable;
    private int[] callbackCounter;

    public ScrollViewActivityTest() {
        super(ScrollViewActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        setActivityInitialTouchMode(true);
        activity = getActivity();
        scrollable = (ObservableScrollView) activity.findViewById(R.id.scrollable);
        callbackCounter = new int[2];
    }

    public void testInitialize() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                new ObservableScrollView(activity);
                new ObservableScrollView(activity, null, 0);
            }
        });
    }

    public void testScroll() throws Throwable {
        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.UP);
        getInstrumentation().waitForIdleSync();

        UiTestUtils.swipeVertically(this, scrollable, UiTestUtils.Direction.DOWN);
        getInstrumentation().waitForIdleSync();
    }

    public void testSaveAndRestoreInstanceState() throws Throwable {
        UiTestUtils.saveAndRestoreInstanceState(this, activity);
        testScroll();
    }

    public void testNoCallbacks() throws Throwable {
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableScrollView) activity.findViewById(R.id.scrollable);
                scrollable.setScrollViewCallbacks(null);
            }
        });
        testScroll();
    }

    public void testCallbacks() throws Throwable {
        final ObservableScrollViewCallbacks[] callbacks = new ObservableScrollViewCallbacks[2];
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable = (ObservableScrollView) activity.findViewById(R.id.scrollable);
                callbacks[0] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[0]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[0]);
                callbacks[1] = new ObservableScrollViewCallbacks() {
                    @Override
                    public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
                        callbackCounter[1]++;
                    }

                    @Override
                    public void onDownMotionEvent() {
                    }

                    @Override
                    public void onUpOrCancelMotionEvent(ScrollState scrollState) {
                    }
                };
                scrollable.addScrollViewCallbacks(callbacks[1]);
            }
        });
        testScroll();
        // Assert that all the callbacks are enabled and get called.
        assertTrue(0 < callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Remove one of the callbacks and scroll again to assert it's really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.removeScrollViewCallbacks(callbacks[0]);
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 < callbackCounter[1]);

        // Clear all callbacks and assert they're really removed.
        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                scrollable.clearScrollViewCallbacks();
            }
        });
        callbackCounter[0] = 0;
        callbackCounter[1] = 0;
        testScroll();
        assertTrue(0 == callbackCounter[0]);
        assertTrue(0 == callbackCounter[1]);
    }
}


================================================
FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/SimpleHeaderRecyclerAdapter.java
================================================
/*
 * Copyright 2014 Soichiro Kashima
 *
 * 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 WARRANT
Download .txt
gitextract_qypqnipg/

├── .editorconfig
├── .gitignore
├── .travis-script.sh
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── build.gradle
├── docs/
│   ├── _data.json
│   ├── _layout.ejs
│   ├── advanced/
│   │   ├── _data.json
│   │   ├── index.md
│   │   ├── sliding-up.md
│   │   └── viewpager.md
│   ├── basic/
│   │   ├── _data.json
│   │   ├── filling-gap.md
│   │   ├── flexible-space-toolbar.md
│   │   ├── flexible-space-with-image.md
│   │   ├── index.md
│   │   ├── parallax-image.md
│   │   ├── show-hide-action-bar.md
│   │   ├── sticky-header.md
│   │   └── translating-toolbar.md
│   ├── contributor/
│   │   ├── _data.json
│   │   ├── ci.md
│   │   ├── index.md
│   │   ├── release.md
│   │   └── update-website.md
│   ├── example/
│   │   ├── _data.json
│   │   ├── android-studio.md
│   │   ├── eclipse.md
│   │   ├── google-play.md
│   │   ├── index.md
│   │   └── wercker.md
│   ├── faq.md
│   ├── overview.md
│   ├── quick-start/
│   │   ├── _data.json
│   │   ├── animation.md
│   │   ├── dependencies.md
│   │   ├── index.md
│   │   └── layout.md
│   └── reference/
│       ├── _data.json
│       ├── environment.md
│       ├── index.md
│       ├── release-notes.md
│       └── supported-widgets.md
├── gradle/
│   ├── gradle-mvn-push.gradle
│   ├── version.gradle
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── build.gradle
│   ├── gradle.properties
│   ├── res/
│   │   └── .gitkeep
│   └── src/
│       ├── androidTest/
│       │   ├── AndroidManifest.xml
│       │   ├── assets/
│       │   │   └── lipsum.html
│       │   ├── java/
│       │   │   └── com/
│       │   │       ├── github/
│       │   │       │   └── ksoichiro/
│       │   │       │       └── android/
│       │   │       │           └── observablescrollview/
│       │   │       │               ├── SavedStateTest.java
│       │   │       │               └── test/
│       │   │       │                   ├── GridViewActivity.java
│       │   │       │                   ├── GridViewActivityTest.java
│       │   │       │                   ├── HeaderGridViewActivity.java
│       │   │       │                   ├── HeaderGridViewActivityTest.java
│       │   │       │                   ├── ListViewActivity.java
│       │   │       │                   ├── ListViewActivityTest.java
│       │   │       │                   ├── ListViewScrollFromBottomActivity.java
│       │   │       │                   ├── ListViewScrollFromBottomActivityTest.java
│       │   │       │                   ├── RecyclerViewActivity.java
│       │   │       │                   ├── RecyclerViewActivityTest.java
│       │   │       │                   ├── RecyclerViewScrollFromBottomActivity.java
│       │   │       │                   ├── RecyclerViewScrollFromBottomActivityTest.java
│       │   │       │                   ├── ScrollUtilsTest.java
│       │   │       │                   ├── ScrollViewActivity.java
│       │   │       │                   ├── ScrollViewActivityTest.java
│       │   │       │                   ├── SimpleHeaderRecyclerAdapter.java
│       │   │       │                   ├── SimpleRecyclerAdapter.java
│       │   │       │                   ├── TouchInterceptionGridViewActivity.java
│       │   │       │                   ├── TouchInterceptionGridViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionListViewActivity.java
│       │   │       │                   ├── TouchInterceptionListViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionRecyclerViewActivity.java
│       │   │       │                   ├── TouchInterceptionRecyclerViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionScrollViewActivity.java
│       │   │       │                   ├── TouchInterceptionScrollViewActivityTest.java
│       │   │       │                   ├── TouchInterceptionWebViewActivity.java
│       │   │       │                   ├── TouchInterceptionWebViewActivityTest.java
│       │   │       │                   ├── UiTestUtils.java
│       │   │       │                   ├── ViewPagerTab2Activity.java
│       │   │       │                   ├── ViewPagerTab2ActivityTest.java
│       │   │       │                   ├── ViewPagerTab2GridViewFragment.java
│       │   │       │                   ├── ViewPagerTab2ListViewFragment.java
│       │   │       │                   ├── ViewPagerTab2RecyclerViewFragment.java
│       │   │       │                   ├── ViewPagerTab2ScrollViewFragment.java
│       │   │       │                   ├── ViewPagerTab2WebViewFragment.java
│       │   │       │                   ├── ViewPagerTabActivity.java
│       │   │       │                   ├── ViewPagerTabActivityTest.java
│       │   │       │                   ├── ViewPagerTabListViewFragment.java
│       │   │       │                   ├── ViewPagerTabRecyclerViewFragment.java
│       │   │       │                   ├── ViewPagerTabScrollViewFragment.java
│       │   │       │                   ├── WebViewActivity.java
│       │   │       │                   └── WebViewActivityTest.java
│       │   │       └── google/
│       │   │           └── samples/
│       │   │               └── apps/
│       │   │                   └── iosched/
│       │   │                       └── ui/
│       │   │                           └── widget/
│       │   │                               ├── SlidingTabLayout.java
│       │   │                               └── SlidingTabStrip.java
│       │   └── res/
│       │       ├── color/
│       │       │   └── tab_text_color.xml
│       │       ├── layout/
│       │       │   ├── activity_gridview.xml
│       │       │   ├── activity_listview.xml
│       │       │   ├── activity_recyclerview.xml
│       │       │   ├── activity_scrollview.xml
│       │       │   ├── activity_touchinterception_gridview.xml
│       │       │   ├── activity_touchinterception_listview.xml
│       │       │   ├── activity_touchinterception_recyclerview.xml
│       │       │   ├── activity_touchinterception_scrollview.xml
│       │       │   ├── activity_touchinterception_webview.xml
│       │       │   ├── activity_viewpagertab.xml
│       │       │   ├── activity_viewpagertab2.xml
│       │       │   ├── activity_webview.xml
│       │       │   ├── fragment_gridview.xml
│       │       │   ├── fragment_listview.xml
│       │       │   ├── fragment_recyclerview.xml
│       │       │   ├── fragment_scrollview.xml
│       │       │   ├── fragment_scrollview_noheader.xml
│       │       │   ├── fragment_webview.xml
│       │       │   ├── padding.xml
│       │       │   └── tab_indicator.xml
│       │       └── values/
│       │           ├── colors.xml
│       │           ├── dimens.xml
│       │           ├── strings.xml
│       │           └── styles.xml
│       └── main/
│           └── java/
│               └── com/
│                   └── github/
│                       └── ksoichiro/
│                           └── android/
│                               └── observablescrollview/
│                                   ├── CacheFragmentStatePagerAdapter.java
│                                   ├── ObservableGridView.java
│                                   ├── ObservableListView.java
│                                   ├── ObservableRecyclerView.java
│                                   ├── ObservableScrollView.java
│                                   ├── ObservableScrollViewCallbacks.java
│                                   ├── ObservableWebView.java
│                                   ├── ScrollState.java
│                                   ├── ScrollUtils.java
│                                   ├── Scrollable.java
│                                   └── TouchInterceptionFrameLayout.java
├── samples/
│   ├── .gitignore
│   ├── AndroidManifest.xml
│   ├── README.md
│   ├── assets/
│   │   ├── handletouch.html
│   │   └── lipsum.html
│   ├── build.gradle
│   ├── proguard-rules.pro
│   ├── res/
│   │   ├── color/
│   │   │   └── tab_text_color.xml
│   │   ├── drawable/
│   │   │   ├── gradient_header_background.xml
│   │   │   └── sliding_header_overlay.xml
│   │   ├── layout/
│   │   │   ├── activity_about.xml
│   │   │   ├── activity_actionbarcontrolgridview.xml
│   │   │   ├── activity_actionbarcontrollistview.xml
│   │   │   ├── activity_actionbarcontrolrecyclerview.xml
│   │   │   ├── activity_actionbarcontrolscrollview.xml
│   │   │   ├── activity_actionbarcontrolwebview.xml
│   │   │   ├── activity_fillgap3listview.xml
│   │   │   ├── activity_fillgap3recyclerview.xml
│   │   │   ├── activity_fillgap3scrollview.xml
│   │   │   ├── activity_fillgaplistview.xml
│   │   │   ├── activity_fillgaprecyclerview.xml
│   │   │   ├── activity_fillgapscrollview.xml
│   │   │   ├── activity_flexiblespacetoolbarscrollview.xml
│   │   │   ├── activity_flexiblespacetoolbarwebview.xml
│   │   │   ├── activity_flexiblespacewithimagegridview.xml
│   │   │   ├── activity_flexiblespacewithimagelistview.xml
│   │   │   ├── activity_flexiblespacewithimagerecyclerview.xml
│   │   │   ├── activity_flexiblespacewithimagescrollview.xml
│   │   │   ├── activity_flexiblespacewithimagewithviewpagertab.xml
│   │   │   ├── activity_flexiblespacewithimagewithviewpagertab2.xml
│   │   │   ├── activity_fragmentactionbarcontrol.xml
│   │   │   ├── activity_fragmenttransition.xml
│   │   │   ├── activity_handletouchgridview.xml
│   │   │   ├── activity_handletouchlistview.xml
│   │   │   ├── activity_handletouchrecyclerview.xml
│   │   │   ├── activity_handletouchscrollview.xml
│   │   │   ├── activity_handletouchwebview.xml
│   │   │   ├── activity_main.xml
│   │   │   ├── activity_parallaxtoolbargridview.xml
│   │   │   ├── activity_parallaxtoolbarlistview.xml
│   │   │   ├── activity_parallaxtoolbarscrollview.xml
│   │   │   ├── activity_slidingupgridview.xml
│   │   │   ├── activity_slidinguplistview.xml
│   │   │   ├── activity_slidinguprecyclerview.xml
│   │   │   ├── activity_slidingupscrollview.xml
│   │   │   ├── activity_slidingupwebview.xml
│   │   │   ├── activity_stickyheaderlistview.xml
│   │   │   ├── activity_stickyheaderrecyclerview.xml
│   │   │   ├── activity_stickyheaderscrollview.xml
│   │   │   ├── activity_stickyheaderwebview.xml
│   │   │   ├── activity_toolbarcontrolgridview.xml
│   │   │   ├── activity_toolbarcontrollistview.xml
│   │   │   ├── activity_toolbarcontrolrecyclerview.xml
│   │   │   ├── activity_toolbarcontrolscrollview.xml
│   │   │   ├── activity_toolbarcontrolwebview.xml
│   │   │   ├── activity_viewpagertab.xml
│   │   │   ├── activity_viewpagertab2.xml
│   │   │   ├── activity_viewpagertabfragment.xml
│   │   │   ├── divider.xml
│   │   │   ├── fragment_actionbarcontrollistview.xml
│   │   │   ├── fragment_flexiblespacewithimagegridview.xml
│   │   │   ├── fragment_flexiblespacewithimagelistview.xml
│   │   │   ├── fragment_flexiblespacewithimagerecyclerview.xml
│   │   │   ├── fragment_flexiblespacewithimagescrollview.xml
│   │   │   ├── fragment_fragmenttransition_default.xml
│   │   │   ├── fragment_fragmenttransition_second.xml
│   │   │   ├── fragment_gridview.xml
│   │   │   ├── fragment_listview.xml
│   │   │   ├── fragment_recyclerview.xml
│   │   │   ├── fragment_scrollview.xml
│   │   │   ├── fragment_scrollview_noheader.xml
│   │   │   ├── fragment_scrollviewwithfab.xml
│   │   │   ├── fragment_viewpagertabfragment_parent.xml
│   │   │   ├── fragment_webview.xml
│   │   │   ├── gradient_header.xml
│   │   │   ├── list_item_handletouch.xml
│   │   │   ├── list_item_main.xml
│   │   │   ├── padding.xml
│   │   │   ├── recycler_header.xml
│   │   │   └── tab_indicator.xml
│   │   ├── layout-v11/
│   │   │   └── tab_indicator.xml
│   │   ├── menu/
│   │   │   └── menu_main.xml
│   │   ├── values/
│   │   │   ├── colors.xml
│   │   │   ├── dimens.xml
│   │   │   ├── strings.xml
│   │   │   ├── strings_license.xml
│   │   │   └── styles.xml
│   │   ├── values-ar/
│   │   │   └── strings.xml
│   │   └── values-w820dp/
│   │       └── dimens.xml
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── github/
│       │               └── ksoichiro/
│       │                   └── app/
│       │                       └── ApplicationTest.java
│       └── main/
│           └── java/
│               └── com/
│                   ├── github/
│                   │   └── ksoichiro/
│                   │       └── android/
│                   │           └── observablescrollview/
│                   │               └── samples/
│                   │                   ├── AboutActivity.java
│                   │                   ├── ActionBarControlGridViewActivity.java
│                   │                   ├── ActionBarControlListViewActivity.java
│                   │                   ├── ActionBarControlRecyclerViewActivity.java
│                   │                   ├── ActionBarControlScrollViewActivity.java
│                   │                   ├── ActionBarControlWebViewActivity.java
│                   │                   ├── BaseActivity.java
│                   │                   ├── BaseFragment.java
│                   │                   ├── FillGap2BaseActivity.java
│                   │                   ├── FillGap2ListViewActivity.java
│                   │                   ├── FillGap2RecyclerViewActivity.java
│                   │                   ├── FillGap2ScrollViewActivity.java
│                   │                   ├── FillGap3BaseActivity.java
│                   │                   ├── FillGap3ListViewActivity.java
│                   │                   ├── FillGap3RecyclerViewActivity.java
│                   │                   ├── FillGap3ScrollViewActivity.java
│                   │                   ├── FillGapBaseActivity.java
│                   │                   ├── FillGapListViewActivity.java
│                   │                   ├── FillGapRecyclerViewActivity.java
│                   │                   ├── FillGapScrollViewActivity.java
│                   │                   ├── FlexibleSpaceToolbarScrollViewActivity.java
│                   │                   ├── FlexibleSpaceToolbarWebViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageBaseFragment.java
│                   │                   ├── FlexibleSpaceWithImageGridViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageGridViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageListViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageListViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageRecyclerViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageRecyclerViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageScrollViewActivity.java
│                   │                   ├── FlexibleSpaceWithImageScrollViewFragment.java
│                   │                   ├── FlexibleSpaceWithImageWithViewPagerTab2Activity.java
│                   │                   ├── FlexibleSpaceWithImageWithViewPagerTabActivity.java
│                   │                   ├── FragmentActionBarControlListViewActivity.java
│                   │                   ├── FragmentActionBarControlListViewFragment.java
│                   │                   ├── FragmentTransitionActivity.java
│                   │                   ├── FragmentTransitionDefaultFragment.java
│                   │                   ├── FragmentTransitionSecondFragment.java
│                   │                   ├── HandleTouchGridViewActivity.java
│                   │                   ├── HandleTouchListViewActivity.java
│                   │                   ├── HandleTouchRecyclerViewActivity.java
│                   │                   ├── HandleTouchScrollViewActivity.java
│                   │                   ├── HandleTouchWebViewActivity.java
│                   │                   ├── MainActivity.java
│                   │                   ├── ParallaxToolbarGridViewActivity.java
│                   │                   ├── ParallaxToolbarListViewActivity.java
│                   │                   ├── ParallaxToolbarScrollViewActivity.java
│                   │                   ├── ScrollFromBottomListViewActivity.java
│                   │                   ├── ScrollFromBottomRecyclerViewActivity.java
│                   │                   ├── SimpleHeaderRecyclerAdapter.java
│                   │                   ├── SimpleRecyclerAdapter.java
│                   │                   ├── SlidingUpBaseActivity.java
│                   │                   ├── SlidingUpGridViewActivity.java
│                   │                   ├── SlidingUpListViewActivity.java
│                   │                   ├── SlidingUpRecyclerViewActivity.java
│                   │                   ├── SlidingUpScrollViewActivity.java
│                   │                   ├── SlidingUpWebViewActivity.java
│                   │                   ├── StickyHeaderListViewActivity.java
│                   │                   ├── StickyHeaderRecyclerViewActivity.java
│                   │                   ├── StickyHeaderScrollViewActivity.java
│                   │                   ├── StickyHeaderWebViewActivity.java
│                   │                   ├── ToolbarControlBaseActivity.java
│                   │                   ├── ToolbarControlGridViewActivity.java
│                   │                   ├── ToolbarControlListViewActivity.java
│                   │                   ├── ToolbarControlRecyclerViewActivity.java
│                   │                   ├── ToolbarControlScrollViewActivity.java
│                   │                   ├── ToolbarControlWebViewActivity.java
│                   │                   ├── ViewPagerTab2Activity.java
│                   │                   ├── ViewPagerTab2GridViewFragment.java
│                   │                   ├── ViewPagerTab2ListViewFragment.java
│                   │                   ├── ViewPagerTab2RecyclerViewFragment.java
│                   │                   ├── ViewPagerTab2ScrollViewFragment.java
│                   │                   ├── ViewPagerTab2WebViewFragment.java
│                   │                   ├── ViewPagerTabActivity.java
│                   │                   ├── ViewPagerTabFragmentActivity.java
│                   │                   ├── ViewPagerTabFragmentGridViewFragment.java
│                   │                   ├── ViewPagerTabFragmentListViewFragment.java
│                   │                   ├── ViewPagerTabFragmentParentFragment.java
│                   │                   ├── ViewPagerTabFragmentRecyclerViewFragment.java
│                   │                   ├── ViewPagerTabFragmentScrollViewFragment.java
│                   │                   ├── ViewPagerTabFragmentWebViewFragment.java
│                   │                   ├── ViewPagerTabGridViewFragment.java
│                   │                   ├── ViewPagerTabListViewActivity.java
│                   │                   ├── ViewPagerTabListViewFragment.java
│                   │                   ├── ViewPagerTabRecyclerViewFragment.java
│                   │                   ├── ViewPagerTabScrollViewActivity.java
│                   │                   ├── ViewPagerTabScrollViewFragment.java
│                   │                   ├── ViewPagerTabScrollViewWithFabActivity.java
│                   │                   └── ViewPagerTabScrollViewWithFabFragment.java
│                   └── google/
│                       └── samples/
│                           └── apps/
│                               └── iosched/
│                                   └── ui/
│                                       └── widget/
│                                           ├── SlidingTabLayout.java
│                                           └── SlidingTabStrip.java
├── settings.gradle
├── website/
│   ├── .bowerrc
│   ├── .gitignore
│   ├── bower.json
│   ├── gulpfile.js
│   ├── harp.json
│   ├── package.json
│   └── public/
│       ├── 404.ejs
│       ├── _data.json
│       ├── _footer.ejs
│       ├── _head.ejs
│       ├── _layout.ejs
│       ├── _nav.ejs
│       ├── browserconfig.xml
│       ├── css/
│       │   ├── _code.less
│       │   ├── _colors.less
│       │   ├── _fonts.less
│       │   ├── _footer.less
│       │   ├── _layout.less
│       │   ├── _misc.less
│       │   ├── _mixins.less
│       │   ├── _navbar.less
│       │   ├── _roboto-fonts.less
│       │   ├── _sidebar.less
│       │   ├── _site-top.less
│       │   └── main.less
│       ├── index.ejs
│       ├── js/
│       │   └── main.coffee
│       └── manifest.json
└── wercker.yml
Download .txt
SYMBOL INDEX (1197 symbols across 148 files)

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/SavedStateTest.java
  class SavedStateTest (line 8) | public class SavedStateTest extends InstrumentationTestCase {
    method testGridViewSavedState (line 10) | public void testGridViewSavedState() throws Throwable {
    method testListViewSavedState (line 40) | public void testListViewSavedState() throws Throwable {
    method testRecyclerViewSavedState (line 70) | public void testRecyclerViewSavedState() throws Throwable {
    method testScrollViewSavedState (line 100) | public void testScrollViewSavedState() throws Throwable {
    method testWebViewSavedState (line 115) | public void testWebViewSavedState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivity.java
  class GridViewActivity (line 11) | public class GridViewActivity extends Activity implements ObservableScro...
    method onCreate (line 13) | @Override
    method onScrollChanged (line 31) | @Override
    method onDownMotionEvent (line 35) | @Override
    method onUpOrCancelMotionEvent (line 39) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivityTest.java
  class GridViewActivityTest (line 14) | public class GridViewActivityTest extends ActivityInstrumentationTestCas...
    method GridViewActivityTest (line 20) | public GridViewActivityTest() {
    method setUp (line 24) | @Override
    method testInitialize (line 33) | public void testInitialize() throws Throwable {
    method testScroll (line 43) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 51) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testScrollVerticallyTo (line 56) | public void testScrollVerticallyTo() throws Throwable {
    method testNoCallbacks (line 75) | public void testNoCallbacks() throws Throwable {
    method testCallbacks (line 86) | public void testCallbacks() throws Throwable {
    method testCannotAddHeaderOrFooterWhenAdapterIsAlreadySet (line 158) | public void testCannotAddHeaderOrFooterWhenAdapterIsAlreadySet() throw...

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivity.java
  class HeaderGridViewActivity (line 13) | public class HeaderGridViewActivity extends Activity implements Observab...
    method onCreate (line 18) | @Override
    method onScrollChanged (line 55) | @Override
    method onDownMotionEvent (line 59) | @Override
    method onUpOrCancelMotionEvent (line 63) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivityTest.java
  class HeaderGridViewActivityTest (line 18) | public class HeaderGridViewActivityTest extends ActivityInstrumentationT...
    method HeaderGridViewActivityTest (line 23) | public HeaderGridViewActivityTest() {
    method setUp (line 27) | @Override
    method testScroll (line 35) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 43) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testScrollVerticallyTo (line 48) | public void testScrollVerticallyTo() throws Throwable {
    method testHeaderViewFeatures (line 67) | public void testHeaderViewFeatures() throws Throwable {
    method testHeaderViewGridExceptions (line 143) | public void testHeaderViewGridExceptions() throws Throwable {
    method testHeaderViewGridAdapter (line 186) | public void testHeaderViewGridAdapter() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivity.java
  class ListViewActivity (line 11) | public class ListViewActivity extends Activity implements ObservableScro...
    method onCreate (line 13) | @Override
    method onScrollChanged (line 31) | @Override
    method onDownMotionEvent (line 35) | @Override
    method onUpOrCancelMotionEvent (line 39) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivityTest.java
  class ListViewActivityTest (line 12) | public class ListViewActivityTest extends ActivityInstrumentationTestCas...
    method ListViewActivityTest (line 18) | public ListViewActivityTest() {
    method setUp (line 22) | @Override
    method testInitialize (line 31) | public void testInitialize() throws Throwable {
    method testScroll (line 41) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 49) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testScrollVerticallyTo (line 54) | public void testScrollVerticallyTo() throws Throwable {
    method testNoCallbacks (line 73) | public void testNoCallbacks() throws Throwable {
    method testCallbacks (line 84) | public void testCallbacks() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivity.java
  class ListViewScrollFromBottomActivity (line 8) | public class ListViewScrollFromBottomActivity extends ListViewActivity {
    method onCreate (line 10) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivityTest.java
  class ListViewScrollFromBottomActivityTest (line 8) | public class ListViewScrollFromBottomActivityTest extends ActivityInstru...
    method ListViewScrollFromBottomActivityTest (line 13) | public ListViewScrollFromBottomActivityTest() {
    method setUp (line 17) | @Override
    method testScroll (line 25) | public void testScroll() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivity.java
  class RecyclerViewActivity (line 11) | public class RecyclerViewActivity extends Activity implements Observable...
    method onCreate (line 13) | @Override
    method onScrollChanged (line 25) | @Override
    method onDownMotionEvent (line 29) | @Override
    method onUpOrCancelMotionEvent (line 33) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivityTest.java
  class RecyclerViewActivityTest (line 12) | public class RecyclerViewActivityTest extends ActivityInstrumentationTes...
    method RecyclerViewActivityTest (line 18) | public RecyclerViewActivityTest() {
    method setUp (line 22) | @Override
    method testInitialize (line 32) | public void testInitialize() throws Throwable {
    method testScroll (line 42) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 50) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testScrollVerticallyTo (line 55) | public void testScrollVerticallyTo() throws Throwable {
    method testNoCallbacks (line 74) | public void testNoCallbacks() throws Throwable {
    method testCallbacks (line 85) | public void testCallbacks() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivity.java
  class RecyclerViewScrollFromBottomActivity (line 8) | public class RecyclerViewScrollFromBottomActivity extends RecyclerViewAc...
    method onCreate (line 10) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivityTest.java
  class RecyclerViewScrollFromBottomActivityTest (line 9) | public class RecyclerViewScrollFromBottomActivityTest extends ActivityIn...
    method RecyclerViewScrollFromBottomActivityTest (line 14) | public RecyclerViewScrollFromBottomActivityTest() {
    method setUp (line 18) | @Override
    method testScroll (line 26) | public void testScroll() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollUtilsTest.java
  class ScrollUtilsTest (line 10) | public class ScrollUtilsTest extends InstrumentationTestCase {
    method testGetFloat (line 12) | public void testGetFloat() {
    method testGetColorWithAlpha (line 18) | public void testGetColorWithAlpha() {
    method testMixColors (line 23) | public void testMixColors() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivity.java
  class ScrollViewActivity (line 11) | public class ScrollViewActivity extends Activity implements ObservableSc...
    method onCreate (line 13) | @Override
    method onScrollChanged (line 20) | @Override
    method onDownMotionEvent (line 24) | @Override
    method onUpOrCancelMotionEvent (line 28) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivityTest.java
  class ScrollViewActivityTest (line 10) | public class ScrollViewActivityTest extends ActivityInstrumentationTestC...
    method ScrollViewActivityTest (line 16) | public ScrollViewActivityTest() {
    method setUp (line 20) | @Override
    method testInitialize (line 29) | public void testInitialize() throws Throwable {
    method testScroll (line 39) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 47) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testNoCallbacks (line 52) | public void testNoCallbacks() throws Throwable {
    method testCallbacks (line 63) | public void testCallbacks() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/SimpleHeaderRecyclerAdapter.java
  class SimpleHeaderRecyclerAdapter (line 28) | public class SimpleHeaderRecyclerAdapter extends RecyclerView.Adapter<Re...
    method SimpleHeaderRecyclerAdapter (line 36) | public SimpleHeaderRecyclerAdapter(Context context, ArrayList<String> ...
    method getItemCount (line 42) | @Override
    method getItemViewType (line 51) | @Override
    method onCreateViewHolder (line 56) | @Override
    method onBindViewHolder (line 65) | @Override
    class HeaderViewHolder (line 72) | static class HeaderViewHolder extends RecyclerView.ViewHolder {
      method HeaderViewHolder (line 73) | public HeaderViewHolder(View view) {
    class ItemViewHolder (line 78) | static class ItemViewHolder extends RecyclerView.ViewHolder {
      method ItemViewHolder (line 81) | public ItemViewHolder(View view) {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/SimpleRecyclerAdapter.java
  class SimpleRecyclerAdapter (line 28) | public class SimpleRecyclerAdapter extends RecyclerView.Adapter<SimpleRe...
    method SimpleRecyclerAdapter (line 32) | public SimpleRecyclerAdapter(Context context, ArrayList<String> items) {
    method getItemCount (line 37) | @Override
    method onCreateViewHolder (line 42) | @Override
    method onBindViewHolder (line 47) | @Override
    class ViewHolder (line 52) | static class ViewHolder extends RecyclerView.ViewHolder {
      method ViewHolder (line 55) | public ViewHolder(View view) {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionGridViewActivity.java
  class TouchInterceptionGridViewActivity (line 16) | public class TouchInterceptionGridViewActivity extends Activity implemen...
    method onCreate (line 26) | @Override
    method onScrollChanged (line 42) | @Override
    method onDownMotionEvent (line 46) | @Override
    method onUpOrCancelMotionEvent (line 50) | @Override
    method shouldInterceptTouchEvent (line 55) | @Override
    method onDownMotionEvent (line 62) | @Override
    method onMoveMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 79) | @Override
    method slideTo (line 84) | private void slideTo(float translationY, final boolean animated) {
    method getScreenHeight (line 94) | private int getScreenHeight() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionGridViewActivityTest.java
  class TouchInterceptionGridViewActivityTest (line 9) | public class TouchInterceptionGridViewActivityTest extends ActivityInstr...
    method TouchInterceptionGridViewActivityTest (line 14) | public TouchInterceptionGridViewActivityTest() {
    method setUp (line 18) | @Override
    method testScroll (line 26) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 40) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionListViewActivity.java
  class TouchInterceptionListViewActivity (line 16) | public class TouchInterceptionListViewActivity extends Activity implemen...
    method onCreate (line 26) | @Override
    method onScrollChanged (line 42) | @Override
    method onDownMotionEvent (line 46) | @Override
    method onUpOrCancelMotionEvent (line 50) | @Override
    method shouldInterceptTouchEvent (line 55) | @Override
    method onDownMotionEvent (line 62) | @Override
    method onMoveMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 79) | @Override
    method slideTo (line 84) | private void slideTo(float translationY, final boolean animated) {
    method getScreenHeight (line 94) | private int getScreenHeight() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionListViewActivityTest.java
  class TouchInterceptionListViewActivityTest (line 9) | public class TouchInterceptionListViewActivityTest extends ActivityInstr...
    method TouchInterceptionListViewActivityTest (line 14) | public TouchInterceptionListViewActivityTest() {
    method setUp (line 18) | @Override
    method testScroll (line 26) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 40) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionRecyclerViewActivity.java
  class TouchInterceptionRecyclerViewActivity (line 17) | public class TouchInterceptionRecyclerViewActivity extends Activity impl...
    method onCreate (line 27) | @Override
    method onScrollChanged (line 47) | @Override
    method onDownMotionEvent (line 51) | @Override
    method onUpOrCancelMotionEvent (line 55) | @Override
    method shouldInterceptTouchEvent (line 60) | @Override
    method onDownMotionEvent (line 67) | @Override
    method onMoveMotionEvent (line 72) | @Override
    method onUpOrCancelMotionEvent (line 84) | @Override
    method slideTo (line 89) | private void slideTo(float translationY, final boolean animated) {
    method getScreenHeight (line 99) | private int getScreenHeight() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionRecyclerViewActivityTest.java
  class TouchInterceptionRecyclerViewActivityTest (line 10) | public class TouchInterceptionRecyclerViewActivityTest extends ActivityI...
    method TouchInterceptionRecyclerViewActivityTest (line 15) | public TouchInterceptionRecyclerViewActivityTest() {
    method setUp (line 19) | @Override
    method testScroll (line 27) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 41) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionScrollViewActivity.java
  class TouchInterceptionScrollViewActivity (line 15) | public class TouchInterceptionScrollViewActivity extends Activity implem...
    method onCreate (line 25) | @Override
    method onScrollChanged (line 40) | @Override
    method onDownMotionEvent (line 44) | @Override
    method onUpOrCancelMotionEvent (line 48) | @Override
    method shouldInterceptTouchEvent (line 53) | @Override
    method onDownMotionEvent (line 60) | @Override
    method onMoveMotionEvent (line 65) | @Override
    method onUpOrCancelMotionEvent (line 77) | @Override
    method slideTo (line 82) | private void slideTo(float translationY, final boolean animated) {
    method getScreenHeight (line 92) | private int getScreenHeight() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionScrollViewActivityTest.java
  class TouchInterceptionScrollViewActivityTest (line 11) | public class TouchInterceptionScrollViewActivityTest extends ActivityIns...
    method TouchInterceptionScrollViewActivityTest (line 16) | public TouchInterceptionScrollViewActivityTest() {
    method setUp (line 20) | @Override
    method testInitialize (line 28) | public void testInitialize() throws Throwable {
    method testScroll (line 41) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 55) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionWebViewActivity.java
  class TouchInterceptionWebViewActivity (line 16) | public class TouchInterceptionWebViewActivity extends Activity implement...
    method onCreate (line 26) | @Override
    method onScrollChanged (line 42) | @Override
    method onDownMotionEvent (line 46) | @Override
    method onUpOrCancelMotionEvent (line 50) | @Override
    method shouldInterceptTouchEvent (line 55) | @Override
    method onDownMotionEvent (line 62) | @Override
    method onMoveMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 79) | @Override
    method slideTo (line 84) | private void slideTo(float translationY, final boolean animated) {
    method getScreenHeight (line 94) | private int getScreenHeight() {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionWebViewActivityTest.java
  class TouchInterceptionWebViewActivityTest (line 9) | public class TouchInterceptionWebViewActivityTest extends ActivityInstru...
    method TouchInterceptionWebViewActivityTest (line 14) | public TouchInterceptionWebViewActivityTest() {
    method setUp (line 18) | @Override
    method testScroll (line 26) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 40) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/UiTestUtils.java
  class UiTestUtils (line 17) | public class UiTestUtils {
    type Direction (line 23) | public enum Direction {
    method UiTestUtils (line 27) | private UiTestUtils() {
    method saveAndRestoreInstanceState (line 30) | public static void saveAndRestoreInstanceState(final InstrumentationTe...
    method swipeHorizontally (line 44) | public static void swipeHorizontally(InstrumentationTestCase test, Vie...
    method swipeVertically (line 60) | public static void swipeVertically(InstrumentationTestCase test, View ...
    method getDummyData (line 76) | public static ArrayList<String> getDummyData() {
    method getDummyData (line 80) | public static ArrayList<String> getDummyData(int num) {
    method setDummyData (line 88) | public static void setDummyData(Context context, GridView gridView) {
    method setDummyData (line 92) | public static void setDummyData(Context context, ListView listView) {
    method setDummyDataFew (line 96) | public static void setDummyDataFew(Context context, ListView listView) {
    method setDummyData (line 100) | public static void setDummyData(Context context, ListView listView, in...
    method setDummyDataWithHeader (line 104) | public static void setDummyDataWithHeader(Context context, ListView li...
    method setDummyData (line 109) | public static void setDummyData(Context context, RecyclerView recycler...
    method setDummyDataFew (line 113) | public static void setDummyDataFew(Context context, RecyclerView recyc...
    method setDummyData (line 117) | public static void setDummyData(Context context, RecyclerView recycler...
    method setDummyDataWithHeader (line 121) | public static void setDummyDataWithHeader(Context context, RecyclerVie...

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2Activity.java
  class ViewPagerTab2Activity (line 42) | public class ViewPagerTab2Activity extends ActionBarActivity implements ...
    method onCreate (line 52) | @Override
    method onScrollChanged (line 80) | @Override
    method onDownMotionEvent (line 84) | @Override
    method onUpOrCancelMotionEvent (line 88) | @Override
    method shouldInterceptTouchEvent (line 98) | @Override
    method onDownMotionEvent (line 134) | @Override
    method onMoveMotionEvent (line 138) | @Override
    method onUpOrCancelMotionEvent (line 149) | @Override
    method getCurrentScrollable (line 156) | public Scrollable getCurrentScrollable() {
    method adjustToolbar (line 168) | private void adjustToolbar(ScrollState scrollState) {
    method getCurrentFragment (line 190) | private Fragment getCurrentFragment() {
    method toolbarIsShown (line 194) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 198) | private boolean toolbarIsHidden() {
    method showToolbar (line 202) | private void showToolbar() {
    method hideToolbar (line 206) | private void hideToolbar() {
    method animateToolbar (line 210) | private void animateToolbar(final float toY) {
    method getActionBarSize (line 230) | private int getActionBarSize() {
    method getScreenHeight (line 240) | private int getScreenHeight() {
    class NavigationAdapter (line 248) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 252) | public NavigationAdapter(FragmentManager fm) {
      method createItem (line 256) | @Override
      method getCount (line 281) | @Override
      method getPageTitle (line 286) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ActivityTest.java
  class ViewPagerTab2ActivityTest (line 6) | public class ViewPagerTab2ActivityTest extends ActivityInstrumentationTe...
    method ViewPagerTab2ActivityTest (line 10) | public ViewPagerTab2ActivityTest() {
    method setUp (line 14) | @Override
    method testScroll (line 21) | public void testScroll() throws Throwable {
    method scroll (line 34) | public void scroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 44) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2GridViewFragment.java
  class ViewPagerTab2GridViewFragment (line 29) | public class ViewPagerTab2GridViewFragment extends Fragment {
    method onCreateView (line 30) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ListViewFragment.java
  class ViewPagerTab2ListViewFragment (line 29) | public class ViewPagerTab2ListViewFragment extends Fragment {
    method onCreateView (line 30) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2RecyclerViewFragment.java
  class ViewPagerTab2RecyclerViewFragment (line 30) | public class ViewPagerTab2RecyclerViewFragment extends Fragment {
    method onCreateView (line 31) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ScrollViewFragment.java
  class ViewPagerTab2ScrollViewFragment (line 29) | public class ViewPagerTab2ScrollViewFragment extends Fragment {
    method onCreateView (line 30) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2WebViewFragment.java
  class ViewPagerTab2WebViewFragment (line 29) | public class ViewPagerTab2WebViewFragment extends Fragment {
    method onCreateView (line 30) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabActivity.java
  class ViewPagerTabActivity (line 20) | public class ViewPagerTabActivity extends ActionBarActivity implements O...
    method onCreate (line 28) | @Override
    method onScrollChanged (line 66) | @Override
    method onDownMotionEvent (line 82) | @Override
    method onUpOrCancelMotionEvent (line 86) | @Override
    method getCurrentScrollable (line 104) | public Scrollable getCurrentScrollable() {
    method adjustToolbar (line 116) | private void adjustToolbar(ScrollState scrollState, View view) {
    method getCurrentFragment (line 145) | public Fragment getCurrentFragment() {
    method propagateToolbarState (line 149) | private void propagateToolbarState(boolean isShown) {
    method propagateToolbarState (line 176) | private void propagateToolbarState(boolean isShown, View view, int too...
    method toolbarIsShown (line 194) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 198) | private boolean toolbarIsHidden() {
    method showToolbar (line 202) | private void showToolbar() {
    method hideToolbar (line 211) | private void hideToolbar() {
    class NavigationAdapter (line 225) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 231) | public NavigationAdapter(FragmentManager fm) {
      method setScrollY (line 235) | public void setScrollY(int scrollY) {
      method createItem (line 239) | @Override
      method getCount (line 278) | @Override
      method getPageTitle (line 283) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabActivityTest.java
  class ViewPagerTabActivityTest (line 6) | public class ViewPagerTabActivityTest extends ActivityInstrumentationTes...
    method ViewPagerTabActivityTest (line 10) | public ViewPagerTabActivityTest() {
    method setUp (line 14) | @Override
    method testScroll (line 21) | public void testScroll() throws Throwable {
    method scroll (line 34) | public void scroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 44) | public void testSaveAndRestoreInstanceState() throws Throwable {

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabListViewFragment.java
  class ViewPagerTabListViewFragment (line 30) | public class ViewPagerTabListViewFragment extends Fragment {
    method onCreateView (line 34) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabRecyclerViewFragment.java
  class ViewPagerTabRecyclerViewFragment (line 31) | public class ViewPagerTabRecyclerViewFragment extends Fragment {
    method onCreateView (line 35) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabScrollViewFragment.java
  class ViewPagerTabScrollViewFragment (line 30) | public class ViewPagerTabScrollViewFragment extends Fragment {
    method onCreateView (line 34) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/WebViewActivity.java
  class WebViewActivity (line 11) | public class WebViewActivity extends Activity implements ObservableScrol...
    method onCreate (line 13) | @Override
    method onScrollChanged (line 22) | @Override
    method onDownMotionEvent (line 26) | @Override
    method onUpOrCancelMotionEvent (line 30) | @Override

FILE: library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/WebViewActivityTest.java
  class WebViewActivityTest (line 12) | public class WebViewActivityTest extends ActivityInstrumentationTestCase...
    method WebViewActivityTest (line 18) | public WebViewActivityTest() {
    method setUp (line 22) | @Override
    method testInitialize (line 31) | public void testInitialize() throws Throwable {
    method testScroll (line 41) | public void testScroll() throws Throwable {
    method testSaveAndRestoreInstanceState (line 49) | public void testSaveAndRestoreInstanceState() throws Throwable {
    method testScrollVerticallyTo (line 54) | public void testScrollVerticallyTo() throws Throwable {
    method testNoCallbacks (line 73) | public void testNoCallbacks() throws Throwable {
    method testCallbacks (line 84) | public void testCallbacks() throws Throwable {

FILE: library/src/androidTest/java/com/google/samples/apps/iosched/ui/widget/SlidingTabLayout.java
  class SlidingTabLayout (line 50) | public class SlidingTabLayout extends HorizontalScrollView {
    type TabColorizer (line 55) | public interface TabColorizer {
      method getIndicatorColor (line 60) | int getIndicatorColor(int position);
    method SlidingTabLayout (line 80) | public SlidingTabLayout(Context context) {
    method SlidingTabLayout (line 84) | public SlidingTabLayout(Context context, AttributeSet attrs) {
    method SlidingTabLayout (line 88) | public SlidingTabLayout(Context context, AttributeSet attrs, int defSt...
    method setCustomTabColorizer (line 109) | public void setCustomTabColorizer(TabColorizer tabColorizer) {
    method setDistributeEvenly (line 113) | public void setDistributeEvenly(boolean distributeEvenly) {
    method setSelectedIndicatorColors (line 121) | public void setSelectedIndicatorColors(int... colors) {
    method setOnPageChangeListener (line 132) | public void setOnPageChangeListener(ViewPager.OnPageChangeListener lis...
    method setCustomTabView (line 142) | public void setCustomTabView(int layoutResId, int textViewId) {
    method setViewPager (line 151) | public void setViewPager(ViewPager viewPager) {
    method createDefaultTabView (line 165) | protected TextView createDefaultTabView(Context context) {
    method populateTabStrip (line 185) | private void populateTabStrip() {
    method setContentDescription (line 228) | public void setContentDescription(int i, String desc) {
    method onAttachedToWindow (line 232) | @Override
    method scrollToTab (line 241) | private void scrollToTab(int tabIndex, int positionOffset) {
    class InternalViewPagerListener (line 260) | private class InternalViewPagerListener implements ViewPager.OnPageCha...
      method onPageScrolled (line 263) | @Override
      method onPageScrollStateChanged (line 284) | @Override
      method onPageSelected (line 293) | @Override
    class TabClickListener (line 309) | private class TabClickListener implements OnClickListener {
      method onClick (line 310) | @Override

FILE: library/src/androidTest/java/com/google/samples/apps/iosched/ui/widget/SlidingTabStrip.java
  class SlidingTabStrip (line 29) | class SlidingTabStrip extends LinearLayout {
    method SlidingTabStrip (line 50) | SlidingTabStrip(Context context) {
    method SlidingTabStrip (line 54) | SlidingTabStrip(Context context, AttributeSet attrs) {
    method setCustomTabColorizer (line 78) | void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColo...
    method setSelectedIndicatorColors (line 83) | void setSelectedIndicatorColors(int... colors) {
    method onViewPagerPageChanged (line 90) | void onViewPagerPageChanged(int position, float positionOffset) {
    method onDraw (line 96) | @Override
    method setColorAlpha (line 138) | private static int setColorAlpha(int color, byte alpha) {
    method blendColors (line 148) | private static int blendColors(int color1, int color2, float ratio) {
    class SimpleTabColorizer (line 156) | private static class SimpleTabColorizer implements SlidingTabLayout.Ta...
      method getIndicatorColor (line 159) | @Override
      method setIndicatorColors (line 164) | void setIndicatorColors(int... colors) {

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/CacheFragmentStatePagerAdapter.java
  class CacheFragmentStatePagerAdapter (line 34) | public abstract class CacheFragmentStatePagerAdapter extends FragmentSta...
    method CacheFragmentStatePagerAdapter (line 44) | public CacheFragmentStatePagerAdapter(FragmentManager fm) {
    method saveState (line 50) | @Override
    method restoreState (line 68) | @Override
    method getItem (line 96) | @Override
    method destroyItem (line 104) | @Override
    method getItemAt (line 118) | public Fragment getItemAt(int position) {
    method createItem (line 129) | protected abstract Fragment createItem(int position);
    method createCacheIndex (line 137) | protected String createCacheIndex(int index) {
    method createCacheKey (line 147) | protected String createCacheKey(int position) {

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableGridView.java
  class ObservableGridView (line 46) | public class ObservableGridView extends GridView implements Scrollable {
    method onScrollStateChanged (line 70) | @Override
    method onScroll (line 77) | @Override
    method ObservableGridView (line 89) | public ObservableGridView(Context context) {
    method ObservableGridView (line 94) | public ObservableGridView(Context context, AttributeSet attrs) {
    method ObservableGridView (line 99) | public ObservableGridView(Context context, AttributeSet attrs, int def...
    method onRestoreInstanceState (line 104) | @Override
    method onSaveInstanceState (line 116) | @Override
    method onInterceptTouchEvent (line 129) | @Override
    method onTouchEvent (line 149) | @Override
    method addFooterView (line 222) | public void addFooterView(View v) {
    method addFooterView (line 226) | public void addFooterView(View v, Object data, boolean isSelectable) {
    method getFooterViewCount (line 254) | public int getFooterViewCount() {
    method removeFooterView (line 258) | public boolean removeFooterView(View v) {
    method setOnScrollListener (line 271) | @Override
    method setScrollViewCallbacks (line 278) | @Override
    method addScrollViewCallbacks (line 283) | @Override
    method removeScrollViewCallbacks (line 291) | @Override
    method clearScrollViewCallbacks (line 298) | @Override
    method setTouchInterceptionViewGroup (line 305) | @Override
    method scrollVerticallyTo (line 310) | @Override
    method getCurrentScrollY (line 315) | @Override
    method setClipChildren (line 320) | @Override
    method setAdapter (line 325) | @Override
    method addHeaderView (line 339) | public void addHeaderView(View v, Object data, boolean isSelectable) {
    method addHeaderView (line 359) | public void addHeaderView(View v) {
    method getHeaderViewCount (line 363) | public int getHeaderViewCount() {
    method removeHeaderView (line 367) | public boolean removeHeaderView(View v) {
    method onMeasure (line 380) | @Override
    method init (line 389) | private void init() {
    method getNumColumnsCompat (line 397) | private int getNumColumnsCompat() {
    method onScrollChanged (line 412) | private void onScrollChanged() {
    method removeFixedViewInfo (line 479) | private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> wher...
    method hasNoCallbacks (line 490) | private boolean hasNoCallbacks() {
    class FullWidthFixedViewLayout (line 494) | private class FullWidthFixedViewLayout extends FrameLayout {
      method FullWidthFixedViewLayout (line 495) | public FullWidthFixedViewLayout(Context context) {
      method onMeasure (line 499) | @Override
    class SavedState (line 510) | static class SavedState extends BaseSavedState {
      method SavedState (line 521) | SavedState(Parcelable superState) {
      method SavedState (line 528) | private SavedState(Parcel in) {
      method writeToParcel (line 546) | @Override
      method createFromParcel (line 566) | @Override
      method newArray (line 571) | @Override
    method dispatchOnDownMotionEvent (line 578) | private void dispatchOnDownMotionEvent() {
    method dispatchOnScrollChanged (line 590) | private void dispatchOnScrollChanged(int scrollY, boolean firstScroll,...
    method dispatchOnUpOrCancelMotionEvent (line 602) | private void dispatchOnUpOrCancelMotionEvent(ScrollState scrollState) {
    class FixedViewInfo (line 614) | public static class FixedViewInfo {
    class HeaderViewGridAdapter (line 621) | public static class HeaderViewGridAdapter implements WrapperListAdapte...
      method HeaderViewGridAdapter (line 637) | public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfo...
      method getNumColumns (line 655) | public int getNumColumns() {
      method setNumColumns (line 659) | public void setNumColumns(int numColumns) {
      method setRowHeight (line 669) | public void setRowHeight(int height) {
      method getHeadersCount (line 673) | public int getHeadersCount() {
      method getFootersCount (line 677) | public int getFootersCount() {
      method isEmpty (line 687) | @Override
      method areAllListInfosSelectable (line 692) | private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> i...
      method removeHeader (line 703) | public boolean removeHeader(View v) {
      method removeFooter (line 717) | public boolean removeFooter(View v) {
      method getCount (line 731) | @Override
      method areAllItemsEnabled (line 740) | @Override
      method getAdapterAndPlaceHolderCount (line 745) | private int getAdapterAndPlaceHolderCount() {
      method isEnabled (line 749) | @Override
      method getItem (line 774) | @Override
      method getItemId (line 808) | @Override
      method hasStableIds (line 821) | @Override
      method getView (line 826) | @Override
      method getItemViewType (line 886) | @Override
      method getViewTypeCount (line 936) | @Override
      method registerDataSetObserver (line 950) | @Override
      method unregisterDataSetObserver (line 958) | @Override
      method getFilter (line 966) | @Override
      method getWrappedAdapter (line 974) | @Override
      method notifyDataSetChanged (line 979) | public void notifyDataSetChanged() {

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableListView.java
  class ObservableListView (line 36) | public class ObservableListView extends ListView implements Scrollable {
    method onScrollStateChanged (line 58) | @Override
    method onScroll (line 65) | @Override
    method ObservableListView (line 77) | public ObservableListView(Context context) {
    method ObservableListView (line 82) | public ObservableListView(Context context, AttributeSet attrs) {
    method ObservableListView (line 87) | public ObservableListView(Context context, AttributeSet attrs, int def...
    method onRestoreInstanceState (line 92) | @Override
    method onSaveInstanceState (line 104) | @Override
    method onInterceptTouchEvent (line 117) | @Override
    method onTouchEvent (line 137) | @Override
    method setOnScrollListener (line 215) | @Override
    method setScrollViewCallbacks (line 222) | @Override
    method addScrollViewCallbacks (line 227) | @Override
    method removeScrollViewCallbacks (line 235) | @Override
    method clearScrollViewCallbacks (line 242) | @Override
    method setTouchInterceptionViewGroup (line 249) | @Override
    method scrollVerticallyTo (line 254) | @Override
    method getCurrentScrollY (line 264) | @Override
    method init (line 269) | private void init() {
    method onScrollChanged (line 274) | private void onScrollChanged() {
    method dispatchOnDownMotionEvent (line 350) | private void dispatchOnDownMotionEvent() {
    method dispatchOnScrollChanged (line 362) | private void dispatchOnScrollChanged(int scrollY, boolean firstScroll,...
    method dispatchOnUpOrCancelMotionEvent (line 374) | private void dispatchOnUpOrCancelMotionEvent(ScrollState scrollState) {
    method hasNoCallbacks (line 386) | private boolean hasNoCallbacks() {
    class SavedState (line 390) | static class SavedState extends BaseSavedState {
      method SavedState (line 401) | SavedState(Parcelable superState) {
      method SavedState (line 408) | private SavedState(Parcel in) {
      method writeToParcel (line 426) | @Override
      method createFromParcel (line 446) | @Override
      method newArray (line 451) | @Override

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableRecyclerView.java
  class ObservableRecyclerView (line 38) | public class ObservableRecyclerView extends RecyclerView implements Scro...
    method ObservableRecyclerView (line 60) | public ObservableRecyclerView(Context context) {
    method ObservableRecyclerView (line 65) | public ObservableRecyclerView(Context context, AttributeSet attrs) {
    method ObservableRecyclerView (line 70) | public ObservableRecyclerView(Context context, AttributeSet attrs, int...
    method onRestoreInstanceState (line 75) | @Override
    method onSaveInstanceState (line 87) | @Override
    method onScrollChanged (line 100) | @Override
    method onInterceptTouchEvent (line 185) | @Override
    method onTouchEvent (line 205) | @Override
    method setScrollViewCallbacks (line 278) | @Override
    method addScrollViewCallbacks (line 283) | @Override
    method removeScrollViewCallbacks (line 291) | @Override
    method clearScrollViewCallbacks (line 298) | @Override
    method setTouchInterceptionViewGroup (line 305) | @Override
    method scrollVerticallyTo (line 310) | @Override
    method scrollVerticallyToPosition (line 333) | public void scrollVerticallyToPosition(int position) {
    method getCurrentScrollY (line 343) | @Override
    method getChildAdapterPosition (line 348) | @SuppressWarnings("deprecation")
    method init (line 356) | private void init() {
    method checkLibraryVersion (line 361) | private void checkLibraryVersion() {
    method dispatchOnDownMotionEvent (line 369) | private void dispatchOnDownMotionEvent() {
    method dispatchOnScrollChanged (line 381) | private void dispatchOnScrollChanged(int scrollY, boolean firstScroll,...
    method dispatchOnUpOrCancelMotionEvent (line 393) | private void dispatchOnUpOrCancelMotionEvent(ScrollState scrollState) {
    method hasNoCallbacks (line 405) | private boolean hasNoCallbacks() {
    class SavedState (line 422) | static class SavedState implements Parcelable {
      method SavedState (line 439) | private SavedState() {
      method SavedState (line 446) | SavedState(Parcelable superState) {
      method SavedState (line 453) | private SavedState(Parcel in) {
      method describeContents (line 475) | @Override
      method writeToParcel (line 480) | @Override
      method getSuperState (line 499) | public Parcelable getSuperState() {
      method createFromParcel (line 505) | @Override
      method newArray (line 510) | @Override

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableScrollView.java
  class ObservableScrollView (line 34) | public class ObservableScrollView extends ScrollView implements Scrollab...
    method ObservableScrollView (line 50) | public ObservableScrollView(Context context) {
    method ObservableScrollView (line 54) | public ObservableScrollView(Context context, AttributeSet attrs) {
    method ObservableScrollView (line 58) | public ObservableScrollView(Context context, AttributeSet attrs, int d...
    method onRestoreInstanceState (line 62) | @Override
    method onSaveInstanceState (line 70) | @Override
    method onScrollChanged (line 79) | @Override
    method onInterceptTouchEvent (line 106) | @Override
    method onTouchEvent (line 126) | @Override
    method setScrollViewCallbacks (line 199) | @Override
    method addScrollViewCallbacks (line 204) | @Override
    method removeScrollViewCallbacks (line 212) | @Override
    method clearScrollViewCallbacks (line 219) | @Override
    method setTouchInterceptionViewGroup (line 226) | @Override
    method scrollVerticallyTo (line 231) | @Override
    method getCurrentScrollY (line 236) | @Override
    method dispatchOnDownMotionEvent (line 241) | private void dispatchOnDownMotionEvent() {
    method dispatchOnScrollChanged (line 253) | private void dispatchOnScrollChanged(int scrollY, boolean firstScroll,...
    method dispatchOnUpOrCancelMotionEvent (line 265) | private void dispatchOnUpOrCancelMotionEvent(ScrollState scrollState) {
    method hasNoCallbacks (line 277) | private boolean hasNoCallbacks() {
    class SavedState (line 281) | static class SavedState extends BaseSavedState {
      method SavedState (line 288) | SavedState(Parcelable superState) {
      method SavedState (line 295) | private SavedState(Parcel in) {
      method writeToParcel (line 301) | @Override
      method createFromParcel (line 310) | @Override
      method newArray (line 315) | @Override

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableScrollViewCallbacks.java
  type ObservableScrollViewCallbacks (line 22) | public interface ObservableScrollViewCallbacks {
    method onScrollChanged (line 33) | void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging);
    method onDownMotionEvent (line 38) | void onDownMotionEvent();
    method onUpOrCancelMotionEvent (line 45) | void onUpOrCancelMotionEvent(ScrollState scrollState);

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableWebView.java
  class ObservableWebView (line 34) | public class ObservableWebView extends WebView implements Scrollable {
    method ObservableWebView (line 50) | public ObservableWebView(Context context) {
    method ObservableWebView (line 54) | public ObservableWebView(Context context, AttributeSet attrs) {
    method ObservableWebView (line 58) | public ObservableWebView(Context context, AttributeSet attrs, int defS...
    method onRestoreInstanceState (line 62) | @Override
    method onSaveInstanceState (line 70) | @Override
    method onScrollChanged (line 79) | @Override
    method onInterceptTouchEvent (line 102) | @Override
    method onTouchEvent (line 122) | @Override
    method setScrollViewCallbacks (line 197) | @Override
    method addScrollViewCallbacks (line 202) | @Override
    method removeScrollViewCallbacks (line 210) | @Override
    method clearScrollViewCallbacks (line 217) | @Override
    method setTouchInterceptionViewGroup (line 224) | @Override
    method scrollVerticallyTo (line 229) | @Override
    method getCurrentScrollY (line 234) | @Override
    method dispatchOnDownMotionEvent (line 239) | private void dispatchOnDownMotionEvent() {
    method dispatchOnScrollChanged (line 251) | private void dispatchOnScrollChanged(int scrollY, boolean firstScroll,...
    method dispatchOnUpOrCancelMotionEvent (line 263) | private void dispatchOnUpOrCancelMotionEvent(ScrollState scrollState) {
    method hasNoCallbacks (line 275) | private boolean hasNoCallbacks() {
    class SavedState (line 279) | static class SavedState extends BaseSavedState {
      method SavedState (line 286) | SavedState(Parcelable superState) {
      method SavedState (line 293) | private SavedState(Parcel in) {
      method writeToParcel (line 299) | @Override
      method createFromParcel (line 308) | @Override
      method newArray (line 313) | @Override

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ScrollState.java
  type ScrollState (line 22) | public enum ScrollState {

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/ScrollUtils.java
  class ScrollUtils (line 26) | public final class ScrollUtils {
    method ScrollUtils (line 28) | private ScrollUtils() {
    method getFloat (line 41) | public static float getFloat(final float value, final float minValue, ...
    method getColorWithAlpha (line 53) | public static int getColorWithAlpha(float alpha, int baseColor) {
    method addOnGlobalLayoutListener (line 67) | public static void addOnGlobalLayoutListener(final View view, final Ru...
    method mixColors (line 93) | public static int mixColors(int fromColor, int toColor, float toAlpha) {
    method cmykFromRgb (line 109) | public static float[] cmykFromRgb(int rgbColor) {
    method rgbFromCmyk (line 134) | public static int rgbFromCmyk(float[] cmyk) {

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/Scrollable.java
  type Scrollable (line 24) | public interface Scrollable {
    method setScrollViewCallbacks (line 32) | @Deprecated
    method addScrollViewCallbacks (line 41) | void addScrollViewCallbacks(ObservableScrollViewCallbacks listener);
    method removeScrollViewCallbacks (line 49) | void removeScrollViewCallbacks(ObservableScrollViewCallbacks listener);
    method clearScrollViewCallbacks (line 56) | void clearScrollViewCallbacks();
    method scrollVerticallyTo (line 65) | void scrollVerticallyTo(int y);
    method getCurrentScrollY (line 72) | int getCurrentScrollY();
    method setTouchInterceptionViewGroup (line 81) | void setTouchInterceptionViewGroup(ViewGroup viewGroup);

FILE: library/src/main/java/com/github/ksoichiro/android/observablescrollview/TouchInterceptionFrameLayout.java
  class TouchInterceptionFrameLayout (line 36) | public class TouchInterceptionFrameLayout extends FrameLayout {
    type TouchInterceptionListener (line 41) | public interface TouchInterceptionListener {
      method shouldInterceptTouchEvent (line 51) | boolean shouldInterceptTouchEvent(MotionEvent ev, boolean moving, fl...
      method onDownMotionEvent (line 58) | void onDownMotionEvent(MotionEvent ev);
      method onMoveMotionEvent (line 67) | void onMoveMotionEvent(MotionEvent ev, float diffX, float diffY);
      method onUpOrCancelMotionEvent (line 74) | void onUpOrCancelMotionEvent(MotionEvent ev);
    method TouchInterceptionFrameLayout (line 85) | public TouchInterceptionFrameLayout(Context context) {
    method TouchInterceptionFrameLayout (line 89) | public TouchInterceptionFrameLayout(Context context, AttributeSet attr...
    method TouchInterceptionFrameLayout (line 93) | public TouchInterceptionFrameLayout(Context context, AttributeSet attr...
    method TouchInterceptionFrameLayout (line 97) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    method setScrollInterceptionListener (line 102) | public void setScrollInterceptionListener(TouchInterceptionListener li...
    method onInterceptTouchEvent (line 106) | @Override
    method onTouchEvent (line 140) | @Override
    method obtainMotionEvent (line 238) | private MotionEvent obtainMotionEvent(MotionEvent base, int action) {
    method duplicateTouchEventForChildren (line 253) | private void duplicateTouchEventForChildren(MotionEvent ev, MotionEven...

FILE: samples/src/androidTest/java/com/github/ksoichiro/app/ApplicationTest.java
  class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 10) | public ApplicationTest() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/AboutActivity.java
  class AboutActivity (line 34) | public class AboutActivity extends AppCompatActivity {
    method onCreate (line 36) | @Override
    method onOptionsItemSelected (line 51) | @Override
    method initLicenses (line 60) | private void initLicenses() {
    method createHeader (line 74) | private TextView createHeader(final String name) {
    method createItemsText (line 79) | private TextView createItemsText(final String... names) {
    method createHtmlText (line 91) | private TextView createHtmlText(final String s) {
    method createHtmlText (line 95) | private TextView createHtmlText(final String s, final int margin) {
    method createDivider (line 109) | private View createDivider(final LayoutInflater inflater, final ViewGr...
    method getVersionName (line 113) | private String getVersionName() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ActionBarControlGridViewActivity.java
  class ActionBarControlGridViewActivity (line 26) | public class ActionBarControlGridViewActivity extends BaseActivity imple...
    method onCreate (line 28) | @Override
    method onScrollChanged (line 38) | @Override
    method onDownMotionEvent (line 42) | @Override
    method onUpOrCancelMotionEvent (line 46) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ActionBarControlListViewActivity.java
  class ActionBarControlListViewActivity (line 28) | public class ActionBarControlListViewActivity extends BaseActivity imple...
    method onCreate (line 32) | @Override
    method onScrollChanged (line 55) | @Override
    method onDownMotionEvent (line 59) | @Override
    method onUpOrCancelMotionEvent (line 63) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ActionBarControlRecyclerViewActivity.java
  class ActionBarControlRecyclerViewActivity (line 27) | public class ActionBarControlRecyclerViewActivity extends BaseActivity i...
    method onCreate (line 29) | @Override
    method onScrollChanged (line 41) | @Override
    method onDownMotionEvent (line 45) | @Override
    method onUpOrCancelMotionEvent (line 49) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ActionBarControlScrollViewActivity.java
  class ActionBarControlScrollViewActivity (line 26) | public class ActionBarControlScrollViewActivity extends BaseActivity imp...
    method onCreate (line 28) | @Override
    method onScrollChanged (line 37) | @Override
    method onDownMotionEvent (line 41) | @Override
    method onUpOrCancelMotionEvent (line 45) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ActionBarControlWebViewActivity.java
  class ActionBarControlWebViewActivity (line 26) | public class ActionBarControlWebViewActivity extends BaseActivity implem...
    method onCreate (line 28) | @Override
    method onScrollChanged (line 38) | @Override
    method onDownMotionEvent (line 42) | @Override
    method onUpOrCancelMotionEvent (line 46) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/BaseActivity.java
  class BaseActivity (line 31) | public abstract class BaseActivity extends AppCompatActivity {
    method getActionBarSize (line 35) | protected int getActionBarSize() {
    method getScreenHeight (line 45) | protected int getScreenHeight() {
    method getDummyData (line 49) | public static ArrayList<String> getDummyData() {
    method getDummyData (line 53) | public static ArrayList<String> getDummyData(int num) {
    method setDummyData (line 61) | protected void setDummyData(ListView listView) {
    method setDummyDataFew (line 65) | protected void setDummyDataFew(ListView listView) {
    method setDummyData (line 69) | protected void setDummyData(ListView listView, int num) {
    method setDummyDataWithHeader (line 73) | protected void setDummyDataWithHeader(ListView listView, int headerHei...
    method setDummyDataWithHeader (line 77) | protected void setDummyDataWithHeader(ListView listView, int headerHei...
    method setDummyDataWithHeader (line 86) | protected void setDummyDataWithHeader(ListView listView, View headerVi...
    method setDummyData (line 91) | protected void setDummyData(GridView gridView) {
    method setDummyData (line 95) | protected void setDummyData(RecyclerView recyclerView) {
    method setDummyDataFew (line 99) | protected void setDummyDataFew(RecyclerView recyclerView) {
    method setDummyData (line 103) | protected void setDummyData(RecyclerView recyclerView, int num) {
    method setDummyDataWithHeader (line 107) | protected void setDummyDataWithHeader(RecyclerView recyclerView, int h...
    method setDummyDataWithHeader (line 116) | protected void setDummyDataWithHeader(RecyclerView recyclerView, View ...

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/BaseFragment.java
  class BaseFragment (line 33) | public abstract class BaseFragment extends Fragment {
    method getDummyData (line 34) | public static ArrayList<String> getDummyData() {
    method getActionBarSize (line 38) | protected int getActionBarSize() {
    method getScreenHeight (line 52) | protected int getScreenHeight() {
    method setDummyData (line 60) | protected void setDummyData(ListView listView) {
    method setDummyDataWithHeader (line 64) | protected void setDummyDataWithHeader(ListView listView, View headerVi...
    method setDummyData (line 69) | protected void setDummyData(GridView gridView) {
    method setDummyDataWithHeader (line 73) | protected void setDummyDataWithHeader(ObservableGridView gridView, Vie...
    method setDummyData (line 78) | protected void setDummyData(RecyclerView recyclerView) {
    method setDummyDataWithHeader (line 82) | protected void setDummyDataWithHeader(RecyclerView recyclerView, View ...

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap2BaseActivity.java
  class FillGap2BaseActivity (line 27) | public abstract class FillGap2BaseActivity<S extends Scrollable> extends...
    method getHeaderTranslationY (line 28) | protected float getHeaderTranslationY(int scrollY) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap2ListViewActivity.java
  class FillGap2ListViewActivity (line 26) | public class FillGap2ListViewActivity extends FillGap2BaseActivity<Obser...
    method createScrollable (line 28) | @Override
    method getLayoutResId (line 36) | @Override
    method updateViews (line 41) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap2RecyclerViewActivity.java
  class FillGap2RecyclerViewActivity (line 28) | public class FillGap2RecyclerViewActivity extends FillGap2BaseActivity<O...
    method createScrollable (line 30) | @Override
    method getLayoutResId (line 40) | @Override
    method updateViews (line 45) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap2ScrollViewActivity.java
  class FillGap2ScrollViewActivity (line 25) | public class FillGap2ScrollViewActivity extends FillGap2BaseActivity<Obs...
    method getLayoutResId (line 26) | @Override
    method createScrollable (line 31) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap3BaseActivity.java
  class FillGap3BaseActivity (line 46) | public abstract class FillGap3BaseActivity<S extends Scrollable> extends...
    method onCreate (line 75) | @Override
    method onRestoreInstanceState (line 117) | @Override
    method onSaveInstanceState (line 123) | @Override
    method getLayoutResId (line 129) | protected abstract int getLayoutResId();
    method createScrollable (line 130) | protected abstract S createScrollable();
    method onScrollChanged (line 132) | @Override
    method onDownMotionEvent (line 136) | @Override
    method onUpOrCancelMotionEvent (line 140) | @Override
    method shouldInterceptTouchEvent (line 145) | @Override
    method onDownMotionEvent (line 151) | @Override
    method onMoveMotionEvent (line 156) | @Override
    method onUpOrCancelMotionEvent (line 169) | @Override
    method updateViews (line 174) | protected void updateViews(float translationY, boolean animated) {
    method changeHeaderBackgroundHeightAnimated (line 203) | private void changeHeaderBackgroundHeightAnimated(boolean shouldShowGa...
    method changeHeaderBackgroundHeight (line 242) | private void changeHeaderBackgroundHeight(float height, float to, floa...
    method getMinInterceptionLayoutY (line 253) | private float getMinInterceptionLayoutY() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap3ListViewActivity.java
  class FillGap3ListViewActivity (line 25) | public class FillGap3ListViewActivity extends FillGap3BaseActivity<Obser...
    method createScrollable (line 27) | @Override
    method getLayoutResId (line 35) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap3RecyclerViewActivity.java
  class FillGap3RecyclerViewActivity (line 27) | public class FillGap3RecyclerViewActivity extends FillGap3BaseActivity<O...
    method createScrollable (line 29) | @Override
    method getLayoutResId (line 39) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGap3ScrollViewActivity.java
  class FillGap3ScrollViewActivity (line 25) | public class FillGap3ScrollViewActivity extends FillGap3BaseActivity<Obs...
    method getLayoutResId (line 26) | @Override
    method createScrollable (line 31) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGapBaseActivity.java
  class FillGapBaseActivity (line 38) | public abstract class FillGapBaseActivity<S extends Scrollable> extends ...
    method onCreate (line 54) | @Override
    method getLayoutResId (line 86) | protected abstract int getLayoutResId();
    method createScrollable (line 87) | protected abstract S createScrollable();
    method onScrollChanged (line 89) | @Override
    method onDownMotionEvent (line 94) | @Override
    method onUpOrCancelMotionEvent (line 98) | @Override
    method updateViews (line 102) | protected void updateViews(int scrollY, boolean animated) {
    method getHeaderTranslationY (line 130) | protected float getHeaderTranslationY(int scrollY) {
    method changeHeaderBackgroundHeightAnimated (line 139) | private void changeHeaderBackgroundHeightAnimated(boolean shouldShowGa...
    method changeHeaderBackgroundHeight (line 178) | private void changeHeaderBackgroundHeight(float height, float to, floa...

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGapListViewActivity.java
  class FillGapListViewActivity (line 26) | public class FillGapListViewActivity extends FillGapBaseActivity<Observa...
    method createScrollable (line 28) | @Override
    method getLayoutResId (line 36) | @Override
    method updateViews (line 41) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGapRecyclerViewActivity.java
  class FillGapRecyclerViewActivity (line 28) | public class FillGapRecyclerViewActivity extends FillGapBaseActivity<Obs...
    method createScrollable (line 30) | @Override
    method getLayoutResId (line 40) | @Override
    method updateViews (line 45) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FillGapScrollViewActivity.java
  class FillGapScrollViewActivity (line 25) | public class FillGapScrollViewActivity extends FillGapBaseActivity<Obser...
    method getLayoutResId (line 26) | @Override
    method createScrollable (line 31) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceToolbarScrollViewActivity.java
  class FlexibleSpaceToolbarScrollViewActivity (line 31) | public class FlexibleSpaceToolbarScrollViewActivity extends BaseActivity...
    method onCreate (line 38) | @Override
    method onScrollChanged (line 72) | @Override
    method onDownMotionEvent (line 77) | @Override
    method onUpOrCancelMotionEvent (line 81) | @Override
    method updateFlexibleSpaceText (line 85) | private void updateFlexibleSpaceText(final int scrollY) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceToolbarWebViewActivity.java
  class FlexibleSpaceToolbarWebViewActivity (line 33) | public class FlexibleSpaceToolbarWebViewActivity extends BaseActivity im...
    method onCreate (line 41) | @Override
    method onScrollChanged (line 83) | @Override
    method onDownMotionEvent (line 88) | @Override
    method onUpOrCancelMotionEvent (line 92) | @Override
    method updateFlexibleSpaceText (line 96) | private void updateFlexibleSpaceText(final int scrollY) {
    method adjustTopMargin (line 115) | private void adjustTopMargin(View view, int topMargin) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageBaseFragment.java
  class FlexibleSpaceWithImageBaseFragment (line 26) | public abstract class FlexibleSpaceWithImageBaseFragment<S extends Scrol...
    method setArguments (line 31) | public void setArguments(int scrollY) {
    method setScrollY (line 39) | public void setScrollY(int scrollY, int threshold) {
    method updateFlexibleSpace (line 51) | protected void updateFlexibleSpace(int scrollY) {
    method updateFlexibleSpace (line 55) | protected abstract void updateFlexibleSpace(int scrollY, View view);
    method onScrollChanged (line 57) | @Override
    method onDownMotionEvent (line 65) | @Override
    method onUpOrCancelMotionEvent (line 70) | @Override
    method getScrollable (line 75) | protected S getScrollable() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageGridViewActivity.java
  class FlexibleSpaceWithImageGridViewActivity (line 39) | public class FlexibleSpaceWithImageGridViewActivity extends BaseActivity...
    method onCreate (line 54) | @Override
    method onScrollChanged (line 96) | @Override
    method onDownMotionEvent (line 148) | @Override
    method onUpOrCancelMotionEvent (line 152) | @Override
    method setPivotXToTitle (line 156) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    method showFab (line 167) | private void showFab() {
    method hideFab (line 175) | private void hideFab() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageGridViewFragment.java
  class FlexibleSpaceWithImageGridViewFragment (line 32) | public class FlexibleSpaceWithImageGridViewFragment extends FlexibleSpac...
    method onCreateView (line 34) | @Override
    method setScrollY (line 80) | @SuppressWarnings("NewApi")
    method updateFlexibleSpace (line 104) | @Override
    method setSelectionFromTop (line 127) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageListViewActivity.java
  class FlexibleSpaceWithImageListViewActivity (line 36) | public class FlexibleSpaceWithImageListViewActivity extends BaseActivity...
    method onCreate (line 51) | @Override
    method onScrollChanged (line 93) | @Override
    method onDownMotionEvent (line 145) | @Override
    method onUpOrCancelMotionEvent (line 149) | @Override
    method setPivotXToTitle (line 153) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    method showFab (line 164) | private void showFab() {
    method hideFab (line 172) | private void hideFab() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageListViewFragment.java
  class FlexibleSpaceWithImageListViewFragment (line 30) | public class FlexibleSpaceWithImageListViewFragment extends FlexibleSpac...
    method onCreateView (line 32) | @Override
    method setScrollY (line 78) | @SuppressWarnings("NewApi")
    method updateFlexibleSpace (line 102) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageRecyclerViewActivity.java
  class FlexibleSpaceWithImageRecyclerViewActivity (line 18) | public class FlexibleSpaceWithImageRecyclerViewActivity extends BaseActi...
    method onCreate (line 29) | @Override
    method onScrollChanged (line 83) | @Override
    method onDownMotionEvent (line 110) | @Override
    method onUpOrCancelMotionEvent (line 114) | @Override
    method setPivotXToTitle (line 118) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageRecyclerViewFragment.java
  class FlexibleSpaceWithImageRecyclerViewFragment (line 31) | public class FlexibleSpaceWithImageRecyclerViewFragment extends Flexible...
    method onCreateView (line 33) | @Override
    method setScrollY (line 74) | @Override
    method updateFlexibleSpace (line 100) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageScrollViewActivity.java
  class FlexibleSpaceWithImageScrollViewActivity (line 33) | public class FlexibleSpaceWithImageScrollViewActivity extends BaseActivi...
    method onCreate (line 48) | @Override
    method onScrollChanged (line 94) | @Override
    method onDownMotionEvent (line 143) | @Override
    method onUpOrCancelMotionEvent (line 147) | @Override
    method showFab (line 151) | private void showFab() {
    method hideFab (line 159) | private void hideFab() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageScrollViewFragment.java
  class FlexibleSpaceWithImageScrollViewFragment (line 28) | public class FlexibleSpaceWithImageScrollViewFragment extends FlexibleSp...
    method onCreateView (line 30) | @Override
    method updateFlexibleSpace (line 60) | @Override
    method updateFlexibleSpace (line 73) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageWithViewPagerTab2Activity.java
  class FlexibleSpaceWithImageWithViewPagerTab2Activity (line 57) | public class FlexibleSpaceWithImageWithViewPagerTab2Activity extends Bas...
    method onCreate (line 78) | @Override
    method onScrollChanged (line 130) | @Override
    method onDownMotionEvent (line 134) | @Override
    method onUpOrCancelMotionEvent (line 138) | @Override
    method shouldInterceptTouchEvent (line 143) | @Override
    method onDownMotionEvent (line 177) | @Override
    method onMoveMotionEvent (line 190) | @Override
    method onUpOrCancelMotionEvent (line 200) | @Override
    method updateLayout (line 221) | private void updateLayout() {
    method getCurrentScrollable (line 250) | private Scrollable getCurrentScrollable() {
    method updateFlexibleSpace (line 262) | private void updateFlexibleSpace() {
    method updateFlexibleSpace (line 266) | private void updateFlexibleSpace(float translationY) {
    method getCurrentFragment (line 283) | private Fragment getCurrentFragment() {
    method setPivotXToTitle (line 287) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    class NavigationAdapter (line 302) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 306) | public NavigationAdapter(FragmentManager fm) {
      method createItem (line 310) | @Override
      method getCount (line 335) | @Override
      method getPageTitle (line 340) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FlexibleSpaceWithImageWithViewPagerTabActivity.java
  class FlexibleSpaceWithImageWithViewPagerTabActivity (line 56) | public class FlexibleSpaceWithImageWithViewPagerTabActivity extends Base...
    method onCreate (line 66) | @Override
    method onScrollChanged (line 104) | public void onScrollChanged(int scrollY, Scrollable s) {
    method translateTab (line 128) | private void translateTab(int scrollY, boolean animated) {
    method setPivotXToTitle (line 172) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    method propagateScroll (line 184) | private void propagateScroll(int scrollY) {
    class NavigationAdapter (line 215) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 221) | public NavigationAdapter(FragmentManager fm) {
      method setScrollY (line 225) | public void setScrollY(int scrollY) {
      method createItem (line 229) | @Override
      method getCount (line 256) | @Override
      method getPageTitle (line 261) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FragmentActionBarControlListViewActivity.java
  class FragmentActionBarControlListViewActivity (line 23) | public class FragmentActionBarControlListViewActivity extends BaseActivi...
    method onCreate (line 25) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FragmentActionBarControlListViewFragment.java
  class FragmentActionBarControlListViewFragment (line 33) | public class FragmentActionBarControlListViewFragment extends BaseFragme...
    method onCreateView (line 37) | @Override
    method onScrollChanged (line 48) | @Override
    method onDownMotionEvent (line 52) | @Override
    method onUpOrCancelMotionEvent (line 56) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FragmentTransitionActivity.java
  class FragmentTransitionActivity (line 29) | public class FragmentTransitionActivity extends BaseActivity {
    method onCreate (line 31) | @Override
    method initFragment (line 46) | private void initFragment() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FragmentTransitionDefaultFragment.java
  class FragmentTransitionDefaultFragment (line 32) | public class FragmentTransitionDefaultFragment extends BaseFragment {
    method onCreateView (line 36) | @Override
    method showNextFragment (line 51) | private void showNextFragment() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/FragmentTransitionSecondFragment.java
  class FragmentTransitionSecondFragment (line 29) | public class FragmentTransitionSecondFragment extends BaseFragment {
    method onCreateView (line 33) | @Override
    method onDestroyView (line 39) | @Override
    method showToolbar (line 45) | private void showToolbar() {
    method hideToolbar (line 55) | private void hideToolbar() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/HandleTouchGridViewActivity.java
  class HandleTouchGridViewActivity (line 44) | public class HandleTouchGridViewActivity extends BaseActivity implements...
    method onCreate (line 47) | @Override
    method onScrollChanged (line 57) | @Override
    method onDownMotionEvent (line 62) | @Override
    method onUpOrCancelMotionEvent (line 67) | @Override
    class CustomAdapter (line 72) | public static class CustomAdapter extends ArrayAdapter<String> {
      method CustomAdapter (line 73) | public CustomAdapter(Context context, List<String> objects) {
      method getView (line 77) | @Override
      method click (line 89) | private void click(int i) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/HandleTouchListViewActivity.java
  class HandleTouchListViewActivity (line 44) | public class HandleTouchListViewActivity extends BaseActivity implements...
    method onCreate (line 47) | @Override
    method onScrollChanged (line 57) | @Override
    method onDownMotionEvent (line 62) | @Override
    method onUpOrCancelMotionEvent (line 67) | @Override
    class CustomAdapter (line 72) | public static class CustomAdapter extends ArrayAdapter<String> {
      method CustomAdapter (line 73) | public CustomAdapter(Context context, List<String> objects) {
      method getView (line 77) | @Override
      method click (line 89) | private void click(int i) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/HandleTouchRecyclerViewActivity.java
  class HandleTouchRecyclerViewActivity (line 47) | public class HandleTouchRecyclerViewActivity extends BaseActivity implem...
    method onCreate (line 50) | @Override
    method onScrollChanged (line 62) | @Override
    method onDownMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 72) | @Override
    class CustomAdapter (line 77) | public static class CustomAdapter extends RecyclerView.Adapter<CustomA...
      method CustomAdapter (line 82) | public CustomAdapter(Context context, ArrayList<String> items) {
      method getItemCount (line 88) | @Override
      method onCreateViewHolder (line 93) | @Override
      method onBindViewHolder (line 98) | @Override
      class ViewHolder (line 103) | static class ViewHolder extends RecyclerView.ViewHolder {
        method ViewHolder (line 107) | public ViewHolder(Context context, View view) {
        method click (line 119) | private void click(int i) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/HandleTouchScrollViewActivity.java
  class HandleTouchScrollViewActivity (line 39) | public class HandleTouchScrollViewActivity extends BaseActivity implemen...
    method onCreate (line 42) | @Override
    method onScrollChanged (line 62) | @Override
    method onDownMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 72) | @Override
    method click (line 77) | private void click(int i) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/HandleTouchWebViewActivity.java
  class HandleTouchWebViewActivity (line 37) | public class HandleTouchWebViewActivity extends BaseActivity implements ...
    method onCreate (line 40) | @Override
    method onScrollChanged (line 50) | @Override
    method onDownMotionEvent (line 55) | @Override
    method onUpOrCancelMotionEvent (line 60) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/MainActivity.java
  class MainActivity (line 44) | public class MainActivity extends AppCompatActivity implements AdapterVi...
    method compare (line 53) | @Override
    type Filter (line 61) | enum Filter {
    method onCreate (line 77) | @Override
    method refreshData (line 103) | private void refreshData() {
    method onCreateOptionsMenu (line 110) | @Override
    method onOptionsItemSelected (line 116) | @Override
    method getData (line 126) | private List<Map<String, Object>> getData() {
    method activityIntent (line 174) | protected Intent activityIntent(String pkg, String componentName) {
    method addItem (line 180) | protected void addItem(List<Map<String, Object>> data, String classNam...
    method onItemClick (line 189) | @SuppressWarnings("unchecked")
    class FilterAdapter (line 198) | private class FilterAdapter extends ArrayAdapter<Filter> {
      method FilterAdapter (line 199) | public FilterAdapter(Context context) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ParallaxToolbarGridViewActivity.java
  class ParallaxToolbarGridViewActivity (line 33) | public class ParallaxToolbarGridViewActivity extends BaseActivity implem...
    method onCreate (line 41) | @Override
    method onRestoreInstanceState (line 72) | @Override
    method onScrollChanged (line 78) | @Override
    method onDownMotionEvent (line 89) | @Override
    method onUpOrCancelMotionEvent (line 93) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ParallaxToolbarListViewActivity.java
  class ParallaxToolbarListViewActivity (line 30) | public class ParallaxToolbarListViewActivity extends BaseActivity implem...
    method onCreate (line 38) | @Override
    method onRestoreInstanceState (line 69) | @Override
    method onScrollChanged (line 75) | @Override
    method onDownMotionEvent (line 86) | @Override
    method onUpOrCancelMotionEvent (line 90) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ParallaxToolbarScrollViewActivity.java
  class ParallaxToolbarScrollViewActivity (line 29) | public class ParallaxToolbarScrollViewActivity extends BaseActivity impl...
    method onCreate (line 36) | @Override
    method onRestoreInstanceState (line 53) | @Override
    method onScrollChanged (line 59) | @Override
    method onDownMotionEvent (line 67) | @Override
    method onUpOrCancelMotionEvent (line 71) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ScrollFromBottomListViewActivity.java
  class ScrollFromBottomListViewActivity (line 41) | public class ScrollFromBottomListViewActivity extends BaseActivity imple...
    method onCreate (line 48) | @Override
    method onScrollChanged (line 78) | @Override
    method onDownMotionEvent (line 94) | @Override
    method onUpOrCancelMotionEvent (line 98) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ScrollFromBottomRecyclerViewActivity.java
  class ScrollFromBottomRecyclerViewActivity (line 41) | public class ScrollFromBottomRecyclerViewActivity extends BaseActivity i...
    method onCreate (line 48) | @Override
    method onScrollChanged (line 76) | @Override
    method onDownMotionEvent (line 92) | @Override
    method onUpOrCancelMotionEvent (line 96) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SimpleHeaderRecyclerAdapter.java
  class SimpleHeaderRecyclerAdapter (line 28) | public class SimpleHeaderRecyclerAdapter extends RecyclerView.Adapter<Re...
    method SimpleHeaderRecyclerAdapter (line 36) | public SimpleHeaderRecyclerAdapter(Context context, ArrayList<String> ...
    method getItemCount (line 42) | @Override
    method getItemViewType (line 51) | @Override
    method onCreateViewHolder (line 56) | @Override
    method onBindViewHolder (line 65) | @Override
    class HeaderViewHolder (line 72) | static class HeaderViewHolder extends RecyclerView.ViewHolder {
      method HeaderViewHolder (line 73) | public HeaderViewHolder(View view) {
    class ItemViewHolder (line 78) | static class ItemViewHolder extends RecyclerView.ViewHolder {
      method ItemViewHolder (line 81) | public ItemViewHolder(View view) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SimpleRecyclerAdapter.java
  class SimpleRecyclerAdapter (line 28) | public class SimpleRecyclerAdapter extends RecyclerView.Adapter<SimpleRe...
    method SimpleRecyclerAdapter (line 32) | public SimpleRecyclerAdapter(Context context, ArrayList<String> items) {
    method getItemCount (line 37) | @Override
    method onCreateViewHolder (line 42) | @Override
    method onBindViewHolder (line 47) | @Override
    class ViewHolder (line 52) | static class ViewHolder extends RecyclerView.ViewHolder {
      method ViewHolder (line 55) | public ViewHolder(View view) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpBaseActivity.java
  class SlidingUpBaseActivity (line 39) | public abstract class SlidingUpBaseActivity<S extends Scrollable> extend...
    method onClick (line 85) | @Override
    method onCreate (line 91) | @Override
    method onRestoreInstanceState (line 161) | @Override
    method onSaveInstanceState (line 168) | @Override
    method getLayoutResId (line 174) | protected abstract int getLayoutResId();
    method createScrollable (line 176) | protected abstract S createScrollable();
    method onScrollChanged (line 178) | @Override
    method onDownMotionEvent (line 182) | @Override
    method onUpOrCancelMotionEvent (line 186) | @Override
    method shouldInterceptTouchEvent (line 191) | @Override
    method onDownMotionEvent (line 207) | @Override
    method onMoveMotionEvent (line 213) | @Override
    method onUpOrCancelMotionEvent (line 228) | @Override
    method changeSlidingState (line 244) | private void changeSlidingState(final int slidingState, boolean animat...
    method slideOnClick (line 265) | private void slideOnClick() {
    method stickToAnchors (line 274) | private void stickToAnchors() {
    method slideTo (line 313) | private void slideTo(float translationY, final boolean animated) {
    method slideWithAnimation (line 357) | private void slideWithAnimation(float toY) {
    method changeToolbarTitleVisibility (line 371) | private void changeToolbarTitleVisibility() {
    method changeHeaderBarColorAnimated (line 385) | private void changeHeaderBarColorAnimated(boolean animated) {
    method changeHeaderBarColor (line 427) | private void changeHeaderBarColor(float alpha) {
    method changeHeaderOverlay (line 433) | private void changeHeaderOverlay() {
    method showFab (line 445) | private void showFab(boolean animated) {
    method hideFab (line 465) | private void hideFab(boolean animated) {
    method getAnchorYBottom (line 485) | private float getAnchorYBottom() {
    method getAnchorYImage (line 489) | private float getAnchorYImage() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpGridViewActivity.java
  class SlidingUpGridViewActivity (line 26) | public class SlidingUpGridViewActivity extends SlidingUpBaseActivity<Obs...
    method getLayoutResId (line 28) | @Override
    method createScrollable (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpListViewActivity.java
  class SlidingUpListViewActivity (line 26) | public class SlidingUpListViewActivity extends SlidingUpBaseActivity<Obs...
    method getLayoutResId (line 28) | @Override
    method createScrollable (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpRecyclerViewActivity.java
  class SlidingUpRecyclerViewActivity (line 33) | public class SlidingUpRecyclerViewActivity extends SlidingUpBaseActivity...
    method getLayoutResId (line 35) | @Override
    method createScrollable (line 40) | @Override
    class CustomAdapter (line 50) | public static class CustomAdapter extends RecyclerView.Adapter<CustomA...
      method CustomAdapter (line 55) | public CustomAdapter(Context context, ArrayList<String> items) {
      method getItemCount (line 61) | @Override
      method onCreateViewHolder (line 66) | @Override
      method onBindViewHolder (line 71) | @Override
      class ViewHolder (line 76) | static class ViewHolder extends RecyclerView.ViewHolder {
        method ViewHolder (line 80) | public ViewHolder(Context context, View view) {
        method click (line 92) | private void click(int i) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpScrollViewActivity.java
  class SlidingUpScrollViewActivity (line 22) | public class SlidingUpScrollViewActivity extends SlidingUpBaseActivity<O...
    method getLayoutResId (line 24) | @Override
    method createScrollable (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/SlidingUpWebViewActivity.java
  class SlidingUpWebViewActivity (line 22) | public class SlidingUpWebViewActivity extends SlidingUpBaseActivity<Obse...
    method getLayoutResId (line 24) | @Override
    method createScrollable (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/StickyHeaderListViewActivity.java
  class StickyHeaderListViewActivity (line 34) | public class StickyHeaderListViewActivity extends BaseActivity implement...
    method onCreate (line 42) | @Override
    method onScrollChanged (line 75) | @Override
    method onDownMotionEvent (line 91) | @Override
    method onUpOrCancelMotionEvent (line 95) | @Override
    method toolbarIsShown (line 119) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 123) | private boolean toolbarIsHidden() {
    method showToolbar (line 127) | private void showToolbar() {
    method hideToolbar (line 135) | private void hideToolbar() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/StickyHeaderRecyclerViewActivity.java
  class StickyHeaderRecyclerViewActivity (line 33) | public class StickyHeaderRecyclerViewActivity extends BaseActivity imple...
    method onCreate (line 40) | @Override
    method onScrollChanged (line 59) | @Override
    method onDownMotionEvent (line 75) | @Override
    method onUpOrCancelMotionEvent (line 79) | @Override
    method toolbarIsShown (line 103) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 107) | private boolean toolbarIsHidden() {
    method showToolbar (line 111) | private void showToolbar() {
    method hideToolbar (line 119) | private void hideToolbar() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/StickyHeaderScrollViewActivity.java
  class StickyHeaderScrollViewActivity (line 31) | public class StickyHeaderScrollViewActivity extends BaseActivity impleme...
    method onCreate (line 38) | @Override
    method onScrollChanged (line 53) | @Override
    method onDownMotionEvent (line 69) | @Override
    method onUpOrCancelMotionEvent (line 73) | @Override
    method toolbarIsShown (line 97) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 101) | private boolean toolbarIsHidden() {
    method showToolbar (line 105) | private void showToolbar() {
    method hideToolbar (line 113) | private void hideToolbar() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/StickyHeaderWebViewActivity.java
  class StickyHeaderWebViewActivity (line 32) | public class StickyHeaderWebViewActivity extends BaseActivity {
    method onCreate (line 41) | @Override
    method onScrollChanged (line 61) | @Override
    method onDownMotionEvent (line 78) | @Override
    method onUpOrCancelMotionEvent (line 82) | @Override
    method onScrollChanged (line 109) | @Override
    method onDownMotionEvent (line 113) | @Override
    method onUpOrCancelMotionEvent (line 120) | @Override
    method toolbarIsShown (line 125) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 129) | private boolean toolbarIsHidden() {
    method showToolbar (line 133) | private void showToolbar() {
    method hideToolbar (line 141) | private void hideToolbar() {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlBaseActivity.java
  class ToolbarControlBaseActivity (line 31) | public abstract class ToolbarControlBaseActivity<S extends Scrollable> e...
    method onCreate (line 36) | @Override
    method getLayoutResId (line 48) | protected abstract int getLayoutResId();
    method createScrollable (line 50) | protected abstract S createScrollable();
    method onScrollChanged (line 52) | @Override
    method onDownMotionEvent (line 56) | @Override
    method onUpOrCancelMotionEvent (line 60) | @Override
    method toolbarIsShown (line 74) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 78) | private boolean toolbarIsHidden() {
    method showToolbar (line 82) | private void showToolbar() {
    method hideToolbar (line 86) | private void hideToolbar() {
    method moveToolbar (line 90) | private void moveToolbar(float toTranslationY) {

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlGridViewActivity.java
  class ToolbarControlGridViewActivity (line 21) | public class ToolbarControlGridViewActivity extends ToolbarControlBaseAc...
    method getLayoutResId (line 23) | @Override
    method createScrollable (line 28) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlListViewActivity.java
  class ToolbarControlListViewActivity (line 24) | public class ToolbarControlListViewActivity extends ToolbarControlBaseAc...
    method getLayoutResId (line 28) | @Override
    method createScrollable (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlRecyclerViewActivity.java
  class ToolbarControlRecyclerViewActivity (line 23) | public class ToolbarControlRecyclerViewActivity extends ToolbarControlBa...
    method getLayoutResId (line 25) | @Override
    method createScrollable (line 30) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlScrollViewActivity.java
  class ToolbarControlScrollViewActivity (line 21) | public class ToolbarControlScrollViewActivity extends ToolbarControlBase...
    method getLayoutResId (line 23) | @Override
    method createScrollable (line 28) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ToolbarControlWebViewActivity.java
  class ToolbarControlWebViewActivity (line 21) | public class ToolbarControlWebViewActivity extends ToolbarControlBaseAct...
    method getLayoutResId (line 23) | @Override
    method createScrollable (line 28) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2Activity.java
  class ViewPagerTab2Activity (line 47) | public class ViewPagerTab2Activity extends BaseActivity implements Obser...
    method onCreate (line 57) | @Override
    method onScrollChanged (line 86) | @Override
    method onDownMotionEvent (line 90) | @Override
    method onUpOrCancelMotionEvent (line 94) | @Override
    method shouldInterceptTouchEvent (line 104) | @Override
    method onDownMotionEvent (line 140) | @Override
    method onMoveMotionEvent (line 144) | @Override
    method onUpOrCancelMotionEvent (line 155) | @Override
    method getCurrentScrollable (line 162) | private Scrollable getCurrentScrollable() {
    method adjustToolbar (line 174) | private void adjustToolbar(ScrollState scrollState) {
    method getCurrentFragment (line 196) | private Fragment getCurrentFragment() {
    method toolbarIsShown (line 200) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 204) | private boolean toolbarIsHidden() {
    method showToolbar (line 208) | private void showToolbar() {
    method hideToolbar (line 212) | private void hideToolbar() {
    method animateToolbar (line 216) | private void animateToolbar(final float toY) {
    class NavigationAdapter (line 240) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 244) | public NavigationAdapter(FragmentManager fm) {
      method createItem (line 248) | @Override
      method getCount (line 273) | @Override
      method getPageTitle (line 278) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2GridViewFragment.java
  class ViewPagerTab2GridViewFragment (line 28) | public class ViewPagerTab2GridViewFragment extends BaseFragment {
    method onCreateView (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2ListViewFragment.java
  class ViewPagerTab2ListViewFragment (line 28) | public class ViewPagerTab2ListViewFragment extends BaseFragment {
    method onCreateView (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2RecyclerViewFragment.java
  class ViewPagerTab2RecyclerViewFragment (line 29) | public class ViewPagerTab2RecyclerViewFragment extends BaseFragment {
    method onCreateView (line 30) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2ScrollViewFragment.java
  class ViewPagerTab2ScrollViewFragment (line 28) | public class ViewPagerTab2ScrollViewFragment extends BaseFragment {
    method onCreateView (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTab2WebViewFragment.java
  class ViewPagerTab2WebViewFragment (line 28) | public class ViewPagerTab2WebViewFragment extends BaseFragment {
    method onCreateView (line 29) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabActivity.java
  class ViewPagerTabActivity (line 43) | public class ViewPagerTabActivity extends BaseActivity implements Observ...
    method onCreate (line 51) | @Override
    method onScrollChanged (line 91) | @Override
    method onDownMotionEvent (line 107) | @Override
    method onUpOrCancelMotionEvent (line 111) | @Override
    method adjustToolbar (line 129) | private void adjustToolbar(ScrollState scrollState, View view) {
    method getCurrentFragment (line 158) | private Fragment getCurrentFragment() {
    method propagateToolbarState (line 162) | private void propagateToolbarState(boolean isShown) {
    method propagateToolbarState (line 189) | private void propagateToolbarState(boolean isShown, View view, int too...
    method toolbarIsShown (line 207) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 211) | private boolean toolbarIsHidden() {
    method showToolbar (line 215) | private void showToolbar() {
    method hideToolbar (line 224) | private void hideToolbar() {
    class NavigationAdapter (line 238) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 244) | public NavigationAdapter(FragmentManager fm) {
      method setScrollY (line 248) | public void setScrollY(int scrollY) {
      method createItem (line 252) | @Override
      method getCount (line 300) | @Override
      method getPageTitle (line 305) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentActivity.java
  class ViewPagerTabFragmentActivity (line 28) | public class ViewPagerTabFragmentActivity extends BaseActivity {
    method onCreate (line 30) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentGridViewFragment.java
  class ViewPagerTabFragmentGridViewFragment (line 32) | public class ViewPagerTabFragmentGridViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentListViewFragment.java
  class ViewPagerTabFragmentListViewFragment (line 32) | public class ViewPagerTabFragmentListViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentParentFragment.java
  class ViewPagerTabFragmentParentFragment (line 45) | public class ViewPagerTabFragmentParentFragment extends BaseFragment imp...
    method onCreateView (line 55) | @Override
    method onScrollChanged (line 78) | @Override
    method onDownMotionEvent (line 82) | @Override
    method onUpOrCancelMotionEvent (line 86) | @Override
    method shouldInterceptTouchEvent (line 96) | @Override
    method onDownMotionEvent (line 133) | @Override
    method onMoveMotionEvent (line 137) | @Override
    method onUpOrCancelMotionEvent (line 150) | @Override
    method getCurrentScrollable (line 157) | private Scrollable getCurrentScrollable() {
    method adjustToolbar (line 169) | private void adjustToolbar(ScrollState scrollState) {
    method getCurrentFragment (line 192) | private Fragment getCurrentFragment() {
    method toolbarIsShown (line 196) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 200) | private boolean toolbarIsHidden() {
    method showToolbar (line 209) | private void showToolbar() {
    method hideToolbar (line 213) | private void hideToolbar() {
    method animateToolbar (line 218) | private void animateToolbar(final float toY) {
    class NavigationAdapter (line 244) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 248) | public NavigationAdapter(FragmentManager fm) {
      method createItem (line 252) | @Override
      method getCount (line 277) | @Override
      method getPageTitle (line 282) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentRecyclerViewFragment.java
  class ViewPagerTabFragmentRecyclerViewFragment (line 33) | public class ViewPagerTabFragmentRecyclerViewFragment extends BaseFragme...
    method onCreateView (line 34) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentScrollViewFragment.java
  class ViewPagerTabFragmentScrollViewFragment (line 32) | public class ViewPagerTabFragmentScrollViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabFragmentWebViewFragment.java
  class ViewPagerTabFragmentWebViewFragment (line 32) | public class ViewPagerTabFragmentWebViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabGridViewFragment.java
  class ViewPagerTabGridViewFragment (line 29) | public class ViewPagerTabGridViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabListViewActivity.java
  class ViewPagerTabListViewActivity (line 40) | public class ViewPagerTabListViewActivity extends BaseActivity implement...
    method onCreate (line 48) | @Override
    method onScrollChanged (line 88) | @Override
    method onDownMotionEvent (line 104) | @Override
    method onUpOrCancelMotionEvent (line 108) | @Override
    method getCurrentFragment (line 149) | private Fragment getCurrentFragment() {
    method propagateToolbarState (line 153) | private void propagateToolbarState(boolean isShown) {
    method toolbarIsShown (line 191) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 195) | private boolean toolbarIsHidden() {
    method showToolbar (line 199) | private void showToolbar() {
    method hideToolbar (line 208) | private void hideToolbar() {
    class NavigationAdapter (line 218) | private static class NavigationAdapter extends CacheFragmentStatePager...
      method NavigationAdapter (line 224) | public NavigationAdapter(FragmentManager fm) {
      method setScrollY (line 228) | public void setScrollY(int scrollY) {
      method createItem (line 232) | @Override
      method getCount (line 243) | @Override
      method getPageTitle (line 248) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabListViewFragment.java
  class ViewPagerTabListViewFragment (line 29) | public class ViewPagerTabListViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabRecyclerViewFragment.java
  class ViewPagerTabRecyclerViewFragment (line 30) | public class ViewPagerTabRecyclerViewFragment extends BaseFragment {
    method onCreateView (line 34) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabScrollViewActivity.java
  class ViewPagerTabScrollViewActivity (line 40) | public class ViewPagerTabScrollViewActivity extends BaseActivity impleme...
    method onCreate (line 48) | @Override
    method onScrollChanged (line 88) | @Override
    method onDownMotionEvent (line 104) | @Override
    method onUpOrCancelMotionEvent (line 108) | @Override
    method getCurrentFragment (line 149) | private Fragment getCurrentFragment() {
    method propagateToolbarState (line 153) | private void propagateToolbarState(boolean isShown) {
    method newViewPagerAdapter (line 191) | protected NavigationAdapter newViewPagerAdapter() {
    method toolbarIsShown (line 195) | private boolean toolbarIsShown() {
    method toolbarIsHidden (line 198) | private boolean toolbarIsHidden() {
    method showToolbar (line 202) | private void showToolbar() {
    method hideToolbar (line 211) | private void hideToolbar() {
    class NavigationAdapter (line 221) | protected static class NavigationAdapter extends CacheFragmentStatePag...
      method NavigationAdapter (line 227) | public NavigationAdapter(FragmentManager fm) {
      method setScrollY (line 231) | public void setScrollY(int scrollY) {
      method newFragment (line 235) | protected Fragment newFragment() {
      method createItem (line 239) | @Override
      method getCount (line 250) | @Override
      method getPageTitle (line 255) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabScrollViewFragment.java
  class ViewPagerTabScrollViewFragment (line 29) | public class ViewPagerTabScrollViewFragment extends BaseFragment {
    method onCreateView (line 33) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabScrollViewWithFabActivity.java
  class ViewPagerTabScrollViewWithFabActivity (line 29) | public class ViewPagerTabScrollViewWithFabActivity extends ViewPagerTabS...
    method newViewPagerAdapter (line 31) | @Override
    class NavigationAdapter (line 36) | private static class NavigationAdapter extends ViewPagerTabScrollViewA...
      method NavigationAdapter (line 37) | public NavigationAdapter(FragmentManager fm) {
      method newFragment (line 41) | @Override

FILE: samples/src/main/java/com/github/ksoichiro/android/observablescrollview/samples/ViewPagerTabScrollViewWithFabFragment.java
  class ViewPagerTabScrollViewWithFabFragment (line 38) | public class ViewPagerTabScrollViewWithFabFragment extends BaseFragment ...
    method onCreateView (line 45) | @Override
    method onScrollChanged (line 96) | @Override
    method onDownMotionEvent (line 103) | @Override
    method onUpOrCancelMotionEvent (line 110) | @Override
    method showFab (line 123) | private void showFab() {
    method hideFab (line 131) | private void hideFab() {

FILE: samples/src/main/java/com/google/samples/apps/iosched/ui/widget/SlidingTabLayout.java
  class SlidingTabLayout (line 50) | public class SlidingTabLayout extends HorizontalScrollView {
    type TabColorizer (line 55) | public interface TabColorizer {
      method getIndicatorColor (line 60) | int getIndicatorColor(int position);
    method SlidingTabLayout (line 80) | public SlidingTabLayout(Context context) {
    method SlidingTabLayout (line 84) | public SlidingTabLayout(Context context, AttributeSet attrs) {
    method SlidingTabLayout (line 88) | public SlidingTabLayout(Context context, AttributeSet attrs, int defSt...
    method setCustomTabColorizer (line 109) | public void setCustomTabColorizer(TabColorizer tabColorizer) {
    method setDistributeEvenly (line 113) | public void setDistributeEvenly(boolean distributeEvenly) {
    method setSelectedIndicatorColors (line 121) | public void setSelectedIndicatorColors(int... colors) {
    method setOnPageChangeListener (line 132) | public void setOnPageChangeListener(ViewPager.OnPageChangeListener lis...
    method setCustomTabView (line 142) | public void setCustomTabView(int layoutResId, int textViewId) {
    method setViewPager (line 151) | public void setViewPager(ViewPager viewPager) {
    method createDefaultTabView (line 165) | protected TextView createDefaultTabView(Context context) {
    method populateTabStrip (line 185) | private void populateTabStrip() {
    method setContentDescription (line 228) | public void setContentDescription(int i, String desc) {
    method onAttachedToWindow (line 232) | @Override
    method scrollToTab (line 241) | private void scrollToTab(int tabIndex, int positionOffset) {
    class InternalViewPagerListener (line 260) | private class InternalViewPagerListener implements ViewPager.OnPageCha...
      method onPageScrolled (line 263) | @Override
      method onPageScrollStateChanged (line 284) | @Override
      method onPageSelected (line 293) | @Override
    class TabClickListener (line 309) | private class TabClickListener implements OnClickListener {
      method onClick (line 310) | @Override

FILE: samples/src/main/java/com/google/samples/apps/iosched/ui/widget/SlidingTabStrip.java
  class SlidingTabStrip (line 29) | class SlidingTabStrip extends LinearLayout {
    method SlidingTabStrip (line 50) | SlidingTabStrip(Context context) {
    method SlidingTabStrip (line 54) | SlidingTabStrip(Context context, AttributeSet attrs) {
    method setCustomTabColorizer (line 78) | void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColo...
    method setSelectedIndicatorColors (line 83) | void setSelectedIndicatorColors(int... colors) {
    method onViewPagerPageChanged (line 90) | void onViewPagerPageChanged(int position, float positionOffset) {
    method onDraw (line 96) | @Override
    method setColorAlpha (line 138) | private static int setColorAlpha(int color, byte alpha) {
    method blendColors (line 148) | private static int blendColors(int color1, int color2, float ratio) {
    class SimpleTabColorizer (line 156) | private static class SimpleTabColorizer implements SlidingTabLayout.Ta...
      method getIndicatorColor (line 159) | @Override
      method setIndicatorColors (line 164) | void setIndicatorColors(int... colors) {
Condensed preview — 352 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,170K chars).
[
  {
    "path": ".editorconfig",
    "chars": 262,
    "preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ni"
  },
  {
    "path": ".gitignore",
    "chars": 165,
    "preview": ".gradle\n*.iml\n*.keystore\n/local.properties\nprivate.properties\n/.idea/\n.DS_Store\n/build\nbin/\ngen/\nlibs/\naarDependencies/\n"
  },
  {
    "path": ".travis-script.sh",
    "chars": 713,
    "preview": "#!/bin/bash\n\necho \"TEST_TARGET=${TEST_TARGET}\"\necho \"TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST}\"\necho \"TRAVIS_BRANCH=${T"
  },
  {
    "path": ".travis.yml",
    "chars": 2317,
    "preview": "language: android\nsudo: false\nenv:\n  global:\n  - GIT_COMMITTER_NAME=ksoichiro\n  - GIT_COMMITTER_EMAIL=soichiro.kashima@g"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1261,
    "preview": "# Thank you for your contribution!\n\nAny contributions will be greatly appreciated.\n\nBefore submitting a new issue, pleas"
  },
  {
    "path": "LICENSE.txt",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 5755,
    "preview": "# Android-ObservableScrollView\n\n[![Build Status](http://img.shields.io/travis/ksoichiro/Android-ObservableScrollView.svg"
  },
  {
    "path": "build.gradle",
    "chars": 845,
    "preview": "buildscript {\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.github.ksoichiro"
  },
  {
    "path": "docs/_data.json",
    "chars": 83,
    "preview": "{\n  \"overview\": {\n    \"title\": \"Overview\"\n  },\n  \"faq\": {\n    \"title\": \"FAQ\"\n  }\n}\n"
  },
  {
    "path": "docs/_layout.ejs",
    "chars": 1317,
    "preview": "<!DOCTYPE html>\n<html prefix=\"og: http://ogp.me/ns#\">\n<head>\n<%- partial(\"../_head\", { title: title, ogType: \"article\" }"
  },
  {
    "path": "docs/advanced/_data.json",
    "chars": 168,
    "preview": "{\n  \"index\": {\n    \"title\": \"Advanced techniques\"\n  },\n  \"sliding-up\": {\n    \"title\": \"Sliding up pattern\"\n  },\n  \"viewp"
  },
  {
    "path": "docs/advanced/index.md",
    "chars": 429,
    "preview": "# Advanced techniques\n\nThis section describes advanced scrolling techniques.  \nWhen you've done this topic, you could be"
  },
  {
    "path": "docs/advanced/sliding-up.md",
    "chars": 414,
    "preview": "# Sliding up pattern\n\nThis topic describes how to slide a panel from the bottom like Google's \"Map\" app,\nwhich are imple"
  },
  {
    "path": "docs/advanced/viewpager.md",
    "chars": 305,
    "preview": "# ViewPager pattern\n\nThis topic describes how to integrate scrollable views with ViewPager,\nwhich are implemented in the"
  },
  {
    "path": "docs/basic/_data.json",
    "chars": 544,
    "preview": "{\n  \"index\": {\n    \"title\": \"Basic techniques\"\n  },\n  \"show-hide-action-bar\": {\n    \"title\": \"Show and hide the ActionBa"
  },
  {
    "path": "docs/basic/filling-gap.md",
    "chars": 2384,
    "preview": "# Filling gap on top of the Toolbar\n\nThis topic describes how to fill the gap on top of the Toolbar,\nwhich are implement"
  },
  {
    "path": "docs/basic/flexible-space-toolbar.md",
    "chars": 9699,
    "preview": "# Flexible space on the Toolbar\n\nThis topic describes how to create flexible space on the Toolbar,\nwhich are implemented"
  },
  {
    "path": "docs/basic/flexible-space-with-image.md",
    "chars": 8844,
    "preview": "# Flexible space with image\n\nThis topic describes how to create flexible space with image,\nwhich are implemented in the "
  },
  {
    "path": "docs/basic/index.md",
    "chars": 648,
    "preview": "# Basic techniques\n\nThis section explains the basic scrolling techniques.  \n\n1. [Show and hide the ActionBar](../../docs"
  },
  {
    "path": "docs/basic/parallax-image.md",
    "chars": 14442,
    "preview": "# Parallax image\n\nThis topic describes how to create parallax effect,\nwhich are implemented in the following examples.\n\n"
  },
  {
    "path": "docs/basic/show-hide-action-bar.md",
    "chars": 4151,
    "preview": "# Show and hide the ActionBar\n\nThis topic describes how to show and hide the ActionBar,\nwhich are implemented in the fol"
  },
  {
    "path": "docs/basic/sticky-header.md",
    "chars": 10884,
    "preview": "# Sticky header\n\nThis topic describes how to keep header on top of the screen,\nwhich are implemented in the following ex"
  },
  {
    "path": "docs/basic/translating-toolbar.md",
    "chars": 7715,
    "preview": "# Translating the Toolbar\n\nThis topic describes how to translate the Toolbar,\nwhich are implemented in the following exa"
  },
  {
    "path": "docs/contributor/_data.json",
    "chars": 186,
    "preview": "{\n  \"index\": {\n    \"title\": \"For contributors\"\n  },\n  \"ci\": {\n    \"title\": \"CI\"\n  },\n  \"update-website\": {\n    \"title\": "
  },
  {
    "path": "docs/contributor/ci.md",
    "chars": 21,
    "preview": "# CI\n\nComing soon...\n"
  },
  {
    "path": "docs/contributor/index.md",
    "chars": 234,
    "preview": "# For contributors\n\nThis section explains some operations for managing the project.\n\n1. [CI](../../docs/contributor/ci.m"
  },
  {
    "path": "docs/contributor/release.md",
    "chars": 1987,
    "preview": "# Release\n\nThis is just a memo for me.\n\n## Bump up the version\n\nEdit `gradle.properties` and commit.\n\n```\nVERSION_NAME=x"
  },
  {
    "path": "docs/contributor/update-website.md",
    "chars": 33,
    "preview": "# Update website\n\nComing soon...\n"
  },
  {
    "path": "docs/example/_data.json",
    "chars": 296,
    "preview": "{\n  \"index\": {\n    \"title\": \"Try the example app\"\n  },\n  \"google-play\": {\n    \"title\": \"Download from Google Play\"\n  },\n"
  },
  {
    "path": "docs/example/android-studio.md",
    "chars": 1842,
    "preview": "# Build on Android Studio\n\nThis library and samples basically support Android Studio and Gradle.  \n(Actually, I'm using "
  },
  {
    "path": "docs/example/eclipse.md",
    "chars": 2319,
    "preview": "# Build on Eclipse\n\nThis library and samples basically support Android Studio and Gradle.  \nBecause they have strong pow"
  },
  {
    "path": "docs/example/google-play.md",
    "chars": 607,
    "preview": "# Download from Google Play\n\nClick the following link to download the example app from Google Play.\n\n[![Get it on Google"
  },
  {
    "path": "docs/example/index.md",
    "chars": 470,
    "preview": "# Try the examples app\n\nTo understand how it works, let's see the existing example app\nand check if there are some patte"
  },
  {
    "path": "docs/example/wercker.md",
    "chars": 1215,
    "preview": "# Download from wercker\n\n[wercker](http://wercker.com/) is a CI service and this project uses wercker to provide the lat"
  },
  {
    "path": "docs/faq.md",
    "chars": 3684,
    "preview": "# FAQ\n\nThese are frequently asked questions from GitHub issues, emails I received from users, etc.\n\n## Q. When do you im"
  },
  {
    "path": "docs/overview.md",
    "chars": 1288,
    "preview": "# Overview\n\nAndroid-ObservableScrollView is a library to handle scroll position for Android apps, and contains lots of e"
  },
  {
    "path": "docs/quick-start/_data.json",
    "chars": 195,
    "preview": "{\n  \"index\": {\n    \"title\": \"Quick start\"\n  },\n  \"dependencies\": {\n    \"title\": \"Dependencies\"\n  },\n  \"layout\": {\n    \"t"
  },
  {
    "path": "docs/quick-start/animation.md",
    "chars": 4386,
    "preview": "# Animation codes\n\nThis time, we implement ActionBar animation using `AppCompatActivity` in the support library.\n\n## App"
  },
  {
    "path": "docs/quick-start/dependencies.md",
    "chars": 931,
    "preview": "# Dependencies\n\nThis library is published to the Maven Central repository, so you can use it through Gradle/Maven.  \nYou"
  },
  {
    "path": "docs/quick-start/index.md",
    "chars": 392,
    "preview": "# Quick start\n\nThank you for having interest in this library!  \nIn this section, I'll show some quick instructions for i"
  },
  {
    "path": "docs/quick-start/layout.md",
    "chars": 843,
    "preview": "# Layout\n\nAfter adding the dependency, let's write layout file such as `res/layout/activity_main.xml`.\n\nThis time, we'll"
  },
  {
    "path": "docs/reference/_data.json",
    "chars": 215,
    "preview": "{\n  \"index\": {\n    \"title\": \"Rerefence\"\n  },\n  \"supported-widgets\": {\n    \"title\": \"Supported widgets\"\n  },\n  \"environme"
  },
  {
    "path": "docs/reference/environment.md",
    "chars": 821,
    "preview": "# Environment\n\n## Development\n\nThis project is built and tested under the following environment.\n\n* OS: Mac OS X 10.10\n*"
  },
  {
    "path": "docs/reference/index.md",
    "chars": 187,
    "preview": "# Reference\n\n1. [Supported widgets](../../docs/basic/supported-widgets.md)\n1. [Environment](../../docs/reference/environ"
  },
  {
    "path": "docs/reference/release-notes.md",
    "chars": 1971,
    "preview": "# Release notes\n\n* v1.6.0\n    * Added header view feature to `ObservableGridView` (#148).\n    * Added footer view featur"
  },
  {
    "path": "docs/reference/supported-widgets.md",
    "chars": 597,
    "preview": "# Supported widgets\n\nWidgets are named with `Observable` prefix.  \n(e.g. `ListView` → `ObservableListView`)  \nYou can ha"
  },
  {
    "path": "gradle/gradle-mvn-push.gradle",
    "chars": 3635,
    "preview": "/*\n * Copyright 2013 Chris Banes\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "gradle/version.gradle",
    "chars": 2155,
    "preview": "// Generate version information to show in the sample app.\n// This can be achieved more easily when we use BuildConfig i"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 652,
    "preview": "VERSION_NAME=1.7.0-SNAPSHOT\nSYNCED_VERSION_NAME=1.5.2\nGROUP=com.github.ksoichiro\n\nPOM_DESCRIPTION=Android library to obs"
  },
  {
    "path": "gradlew",
    "chars": 5080,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2404,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@r"
  },
  {
    "path": "library/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "library/AndroidManifest.xml",
    "chars": 707,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Versi"
  },
  {
    "path": "library/build.gradle",
    "chars": 1362,
    "preview": "apply plugin: 'com.android.library'\n\ndependencies {\n    compile 'com.android.support:recyclerview-v7:23.1.1'\n    android"
  },
  {
    "path": "library/gradle.properties",
    "chars": 101,
    "preview": "POM_NAME=Android-ObservableScrollView\nPOM_ARTIFACT_ID=android-observablescrollview\nPOM_PACKAGING=aar\n"
  },
  {
    "path": "library/res/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "library/src/androidTest/AndroidManifest.xml",
    "chars": 2073,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/assets/lipsum.html",
    "chars": 8171,
    "preview": "<html>\n<head>\n<style type=\"text/css\">\n#container {\npadding: 1em;\n}\n</style>\n</head>\n<body>\n<div id=\"container\">\n<p>Lorem"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/SavedStateTest.java",
    "chars": 5973,
    "preview": "package com.github.ksoichiro.android.observablescrollview;\n\nimport android.os.Parcel;\nimport android.test.Instrumentatio"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivity.java",
    "chars": 1465,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/GridViewActivityTest.java",
    "chars": 6943,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivity.java",
    "chars": 2470,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/HeaderGridViewActivityTest.java",
    "chars": 10476,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.test.ActivityInstrumentationTestCase2;\ni"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivity.java",
    "chars": 1465,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewActivityTest.java",
    "chars": 5494,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivity.java",
    "chars": 941,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.os.Bundle;\n\nimport com.github.ksoichiro."
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ListViewScrollFromBottomActivityTest.java",
    "chars": 1110,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivity.java",
    "chars": 1265,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewActivityTest.java",
    "chars": 5586,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivity.java",
    "chars": 908,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.os.Bundle;\n\nimport com.github.ksoichiro."
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/RecyclerViewScrollFromBottomActivityTest.java",
    "chars": 1215,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollUtilsTest.java",
    "chars": 996,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.graphics.Color;\nimport android.test.Inst"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivity.java",
    "chars": 1035,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ScrollViewActivityTest.java",
    "chars": 4782,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/SimpleHeaderRecyclerAdapter.java",
    "chars": 2749,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/SimpleRecyclerAdapter.java",
    "chars": 1913,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionGridViewActivity.java",
    "chars": 3900,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionGridViewActivityTest.java",
    "chars": 1547,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionListViewActivity.java",
    "chars": 3900,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionListViewActivityTest.java",
    "chars": 1547,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionRecyclerViewActivity.java",
    "chars": 4195,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionRecyclerViewActivityTest.java",
    "chars": 1652,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionScrollViewActivity.java",
    "chars": 3753,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionScrollViewActivityTest.java",
    "chars": 2155,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Build;\ni"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionWebViewActivity.java",
    "chars": 3856,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/TouchInterceptionWebViewActivityTest.java",
    "chars": 1540,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/UiTestUtils.java",
    "chars": 4891,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.content.Con"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2Activity.java",
    "chars": 11316,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ActivityTest.java",
    "chars": 1868,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.test.ActivityInstrumentationTestCase2;\ni"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2GridViewFragment.java",
    "chars": 1800,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ListViewFragment.java",
    "chars": 1800,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2RecyclerViewFragment.java",
    "chars": 2015,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2ScrollViewFragment.java",
    "chars": 1765,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTab2WebViewFragment.java",
    "chars": 1794,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabActivity.java",
    "chars": 10485,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.os.Bundle;\nimport android.support.v4.app"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabActivityTest.java",
    "chars": 1863,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.test.ActivityInstrumentationTestCase2;\ni"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabListViewFragment.java",
    "chars": 2504,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabRecyclerViewFragment.java",
    "chars": 2722,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/ViewPagerTabScrollViewFragment.java",
    "chars": 2281,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/WebViewActivity.java",
    "chars": 1147,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n"
  },
  {
    "path": "library/src/androidTest/java/com/github/ksoichiro/android/observablescrollview/test/WebViewActivityTest.java",
    "chars": 5483,
    "preview": "package com.github.ksoichiro.android.observablescrollview.test;\n\nimport android.app.Activity;\nimport android.test.Activi"
  },
  {
    "path": "library/src/androidTest/java/com/google/samples/apps/iosched/ui/widget/SlidingTabLayout.java",
    "chars": 12013,
    "preview": "/*\n * Copyright 2014 Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
  },
  {
    "path": "library/src/androidTest/java/com/google/samples/apps/iosched/ui/widget/SlidingTabStrip.java",
    "chars": 6426,
    "preview": "/*\n * Copyright 2014 Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License"
  },
  {
    "path": "library/src/androidTest/res/color/tab_text_color.xml",
    "chars": 768,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_gridview.xml",
    "chars": 859,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_listview.xml",
    "chars": 832,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_recyclerview.xml",
    "chars": 836,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_scrollview.xml",
    "chars": 1084,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_touchinterception_gridview.xml",
    "chars": 2738,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_touchinterception_listview.xml",
    "chars": 2746,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_touchinterception_recyclerview.xml",
    "chars": 2707,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_touchinterception_scrollview.xml",
    "chars": 3100,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_touchinterception_webview.xml",
    "chars": 2702,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_viewpagertab.xml",
    "chars": 2227,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_viewpagertab2.xml",
    "chars": 2235,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/activity_webview.xml",
    "chars": 831,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_gridview.xml",
    "chars": 855,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_listview.xml",
    "chars": 828,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_recyclerview.xml",
    "chars": 866,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_scrollview.xml",
    "chars": 1444,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_scrollview_noheader.xml",
    "chars": 1398,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/fragment_webview.xml",
    "chars": 827,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/padding.xml",
    "chars": 786,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/layout/tab_indicator.xml",
    "chars": 979,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/values/colors.xml",
    "chars": 742,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/values/dimens.xml",
    "chars": 860,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/values/strings.xml",
    "chars": 8669,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/androidTest/res/values/styles.xml",
    "chars": 1380,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/CacheFragmentStatePagerAdapter.java",
    "chars": 5025,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableGridView.java",
    "chars": 37699,
    "preview": "/*\n * Copyright (C) 2013 The Android Open Source Project\n * Copyright (C) 2014 Soichiro Kashima\n *\n * Licensed under the"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableListView.java",
    "chars": 18024,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableRecyclerView.java",
    "chars": 20447,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableScrollView.java",
    "chars": 11181,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableScrollViewCallbacks.java",
    "chars": 1696,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ObservableWebView.java",
    "chars": 10907,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ScrollState.java",
    "chars": 1053,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/ScrollUtils.java",
    "chars": 5824,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/Scrollable.java",
    "chars": 2441,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "library/src/main/java/com/github/ksoichiro/android/observablescrollview/TouchInterceptionFrameLayout.java",
    "chars": 12531,
    "preview": "/*\n * Copyright 2014 Soichiro Kashima\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may n"
  },
  {
    "path": "samples/.gitignore",
    "chars": 21,
    "preview": "/build\n/src/version/\n"
  },
  {
    "path": "samples/AndroidManifest.xml",
    "chars": 25998,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Versi"
  },
  {
    "path": "samples/README.md",
    "chars": 701,
    "preview": "# Samples\n\nThis sample project demonstrates how the Android-ObservableScrollView works.\n\nThis document's goal is to lead"
  },
  {
    "path": "samples/assets/handletouch.html",
    "chars": 8577,
    "preview": "<html>\n<head>\n<style type=\"text/css\">\n#container {\npadding: 1em;\n}\n.btn {\nmargin-top: 4px;\nmargin-bottom: 4px;\n}\n</style"
  },
  {
    "path": "samples/assets/lipsum.html",
    "chars": 8171,
    "preview": "<html>\n<head>\n<style type=\"text/css\">\n#container {\npadding: 1em;\n}\n</style>\n</head>\n<body>\n<div id=\"container\">\n<p>Lorem"
  },
  {
    "path": "samples/build.gradle",
    "chars": 3183,
    "preview": "apply plugin: 'com.android.application'\n\n// for using SNAPSHOT\n//repositories {\n//    maven {\n//        url uri('https:/"
  },
  {
    "path": "samples/proguard-rules.pro",
    "chars": 679,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /A"
  },
  {
    "path": "samples/res/color/tab_text_color.xml",
    "chars": 768,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/drawable/gradient_header_background.xml",
    "chars": 785,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/drawable/sliding_header_overlay.xml",
    "chars": 785,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_about.xml",
    "chars": 4962,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_actionbarcontrolgridview.xml",
    "chars": 852,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_actionbarcontrollistview.xml",
    "chars": 826,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_actionbarcontrolrecyclerview.xml",
    "chars": 868,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_actionbarcontrolscrollview.xml",
    "chars": 1358,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_actionbarcontrolwebview.xml",
    "chars": 824,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgap3listview.xml",
    "chars": 3532,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgap3recyclerview.xml",
    "chars": 3536,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgap3scrollview.xml",
    "chars": 4165,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgaplistview.xml",
    "chars": 2659,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgaprecyclerview.xml",
    "chars": 2663,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fillgapscrollview.xml",
    "chars": 3246,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacetoolbarscrollview.xml",
    "chars": 3815,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacetoolbarwebview.xml",
    "chars": 3525,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagegridview.xml",
    "chars": 2955,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagelistview.xml",
    "chars": 2924,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagerecyclerview.xml",
    "chars": 2064,
    "preview": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/re"
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagescrollview.xml",
    "chars": 3698,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagewithviewpagertab.xml",
    "chars": 2769,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_flexiblespacewithimagewithviewpagertab2.xml",
    "chars": 3832,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fragmentactionbarcontrol.xml",
    "chars": 774,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_fragmenttransition.xml",
    "chars": 1433,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_handletouchgridview.xml",
    "chars": 855,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_handletouchlistview.xml",
    "chars": 828,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_handletouchrecyclerview.xml",
    "chars": 832,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_handletouchscrollview.xml",
    "chars": 2719,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_handletouchwebview.xml",
    "chars": 827,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_main.xml",
    "chars": 2467,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_parallaxtoolbargridview.xml",
    "chars": 1891,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_parallaxtoolbarlistview.xml",
    "chars": 1860,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_parallaxtoolbarscrollview.xml",
    "chars": 2832,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_slidingupgridview.xml",
    "chars": 6779,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_slidinguplistview.xml",
    "chars": 6744,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_slidinguprecyclerview.xml",
    "chars": 6705,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_slidingupscrollview.xml",
    "chars": 7330,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_slidingupwebview.xml",
    "chars": 6743,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_stickyheaderlistview.xml",
    "chars": 2149,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_stickyheaderrecyclerview.xml",
    "chars": 2195,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_stickyheaderscrollview.xml",
    "chars": 3321,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_stickyheaderwebview.xml",
    "chars": 3052,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_toolbarcontrolgridview.xml",
    "chars": 1466,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_toolbarcontrollistview.xml",
    "chars": 1435,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_toolbarcontrolrecyclerview.xml",
    "chars": 1439,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_toolbarcontrolscrollview.xml",
    "chars": 2004,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_toolbarcontrolwebview.xml",
    "chars": 1434,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_viewpagertab.xml",
    "chars": 2254,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_viewpagertab2.xml",
    "chars": 2235,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/activity_viewpagertabfragment.xml",
    "chars": 1321,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/divider.xml",
    "chars": 798,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  },
  {
    "path": "samples/res/layout/fragment_actionbarcontrollistview.xml",
    "chars": 826,
    "preview": "<!--\n  Copyright 2014 Soichiro Kashima\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not "
  }
]

// ... and 152 more files (download for full content)

About this extraction

This page contains the full source code of the ksoichiro/Android-ObservableScrollView GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 352 files (1.0 MB), approximately 250.9k tokens, and a symbol index with 1197 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!