├── .gitignore
├── .idea
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── RELEASE-NOTES.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── h6ah4i
│ │ └── android
│ │ └── example
│ │ └── scrollableviewpagercontent
│ │ ├── MainActivity.java
│ │ └── contents
│ │ ├── ListViewContentFragment.java
│ │ ├── NestedScrollViewContentFragment.java
│ │ └── RecyclerViewContentFragment.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ ├── activity_main.xml
│ ├── include_view_pager.xml
│ ├── page_fragment_list_view.xml
│ ├── page_fragment_nested_scroll_view.xml
│ ├── page_fragment_normal_list_view.xml
│ ├── page_fragment_normal_nested_scroll_view.xml
│ └── page_fragment_recycler_view.xml
│ ├── menu
│ └── appmenu.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
└── capture.gif
├── library-listview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── h6ah4i
│ └── android
│ └── scrollableviewpagercontent
│ └── listview
│ └── ViewPagerContentListView.java
├── library-nestedscrollview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── h6ah4i
│ └── android
│ └── scrollableviewpagercontent
│ └── nestedscrollview
│ └── ViewPagerContentNestedScrollView.java
├── library-recyclerview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── h6ah4i
│ └── android
│ └── scrollableviewpagercontent
│ └── recyclerview
│ └── ViewPagerContentRecyclerViewTouchEventInterceptor.java
├── library
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── h6ah4i
│ └── android
│ └── scrollableviewpagercontent
│ └── ScrollableViewPagerContentTouchEventDelegator.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ScrollableViewPagerContent
2 | ===============
3 |
4 | [](https://maven-badges.herokuapp.com/maven-central/com.h6ah4i.android.scrollableviewpagercontent/scrollableviewpagercontent)
5 |
6 |
7 | A tiny library which improves UX with ViewPager. This library prioritizes ViewPager's horizontal swipe action over vertical scroll of inner pager contents.
8 |
9 | In the standard behavior of Android's ViewPager, paging swipe action of ViewPager has less priority than inner views' vertical scroll. When inner content is in scrolling state, horizontal swipe is completely ignored. However the behavior is considered bad for UX, and that's why I created this library.
10 |
11 | Also, I noticed that some major apps implemented the same behavior. (*NOTE: These are not using this library.*)
12 |
13 | - Play Store app
14 | - Official Twitter client
15 | - Mercari
16 |
17 |
18 | 
19 |
20 | Usage
21 | ---
22 |
23 | ### 1. Add the following line(s) to `build.gradle`
24 |
25 | ```gradle
26 | // the core module
27 | implementation 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent:1.0.0'
28 |
29 | // if you are using RecyclerView, add this too
30 | implementation 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-recyclerview:1.0.0'
31 |
32 | // if you are using NestedScrollView, add this too
33 | implementation 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-nestedscrollview:1.0.0'
34 |
35 | // if you are using ListView, add this too
36 | implementation 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-listview:1.0.0'
37 |
38 | ```
39 |
40 | ### 2-A. If using a `RecyclerView` for the `ViewPager` content
41 |
42 | ```java
43 | RecyclerView rv = ...;
44 | rv.addOnItemTouchListener(new ViewPagerContentRecyclerViewTouchEventInterceptor());
45 | ```
46 |
47 |
48 | ### 2-B. If using a `NestedScrollView` for the `ViewPager` content
49 |
50 | ```diff
51 | - ...
52 | + ...
53 |
54 | ```
55 |
56 |
57 | ### 2-C. If using a `ListView` for the `ViewPager` content
58 |
59 | ```diff
60 | - ...
61 | + ...
62 |
63 | ```
64 |
65 |
66 | License
67 | ---
68 |
69 | This library is licensed under the [Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
70 |
71 | See [`LICENSE`](LICENSE) for full of the license text.
72 |
73 | Copyright (C) 2018 Haruki Hasegawa
74 |
75 | Licensed under the Apache License, Version 2.0 (the "License");
76 | you may not use this file except in compliance with the License.
77 | You may obtain a copy of the License at
78 |
79 | http://www.apache.org/licenses/LICENSE-2.0
80 |
81 | Unless required by applicable law or agreed to in writing, software
82 | distributed under the License is distributed on an "AS IS" BASIS,
83 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
84 | See the License for the specific language governing permissions and
85 | limitations under the License.
86 |
--------------------------------------------------------------------------------
/RELEASE-NOTES.md:
--------------------------------------------------------------------------------
1 | ## 1.0.0
2 |
3 | - Migrate to AndroidX
4 |
5 | ## 0.1.2
6 |
7 | - Fix uploadName to correct multi-module library publishing
8 |
9 | ## 0.1.1
10 |
11 | - Changed package group ID
12 |
13 | ## 0.1.0
14 |
15 | - Initial release
16 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.ext.COMPILE_SDK_VERSION
5 | defaultConfig {
6 | applicationId "com.h6ah4i.android.example.scrollableviewpagercontent"
7 | minSdkVersion rootProject.ext.MIN_SDK_VERSION
8 | targetSdkVersion rootProject.ext.TARGET_SDK_VERSION
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'androidx.appcompat:appcompat:1.0.0'
24 | implementation 'com.google.android.material:material:1.0.0'
25 | implementation 'androidx.recyclerview:recyclerview:1.0.0'
26 | implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
27 | implementation project(':scrollableviewpagercontent')
28 | implementation project(':scrollableviewpagercontent-recyclerview')
29 | implementation project(':scrollableviewpagercontent-listview')
30 | implementation project(':scrollableviewpagercontent-nestedscrollview')
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/h6ah4i/android/example/scrollableviewpagercontent/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.example.scrollableviewpagercontent;
2 |
3 | import android.os.Bundle;
4 | import android.view.Menu;
5 | import android.view.MenuItem;
6 | import android.widget.CompoundButton;
7 |
8 | import com.google.android.material.tabs.TabLayout;
9 | import com.h6ah4i.android.example.scrollableviewpagercontent.contents.ListViewContentFragment;
10 | import com.h6ah4i.android.example.scrollableviewpagercontent.contents.NestedScrollViewContentFragment;
11 | import com.h6ah4i.android.example.scrollableviewpagercontent.contents.RecyclerViewContentFragment;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import androidx.annotation.Nullable;
17 | import androidx.appcompat.app.AppCompatActivity;
18 | import androidx.appcompat.widget.SwitchCompat;
19 | import androidx.appcompat.widget.Toolbar;
20 | import androidx.core.util.Pair;
21 | import androidx.fragment.app.Fragment;
22 | import androidx.fragment.app.FragmentManager;
23 | import androidx.fragment.app.FragmentStatePagerAdapter;
24 | import androidx.viewpager.widget.ViewPager;
25 |
26 | public class MainActivity extends AppCompatActivity {
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_main);
32 | setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
33 |
34 | setupPager(true);
35 | }
36 |
37 | private void setupPager(boolean enabled) {
38 | MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), enabled);
39 |
40 | TabLayout tabs = findViewById(R.id.tabs);
41 | ViewPager pager = findViewById(R.id.viewpager);
42 | pager.setAdapter(null);
43 | pager.setAdapter(pagerAdapter);
44 | tabs.setupWithViewPager(pager);
45 | }
46 |
47 | @Override
48 | public boolean onCreateOptionsMenu(Menu menu) {
49 | getMenuInflater().inflate(R.menu.appmenu, menu);
50 |
51 | SwitchCompat sw = ((SwitchCompat) menu.findItem(R.id.itemSwitch).getActionView());
52 | sw.setChecked(true);
53 | sw.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
54 | @Override
55 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
56 | setupPager(isChecked);
57 | }
58 | });
59 |
60 | return true;
61 | }
62 |
63 | @Override
64 | public boolean onOptionsItemSelected(MenuItem item) {
65 | return super.onOptionsItemSelected(item);
66 | }
67 |
68 | public class MyPagerAdapter extends FragmentStatePagerAdapter {
69 | List> fragments;
70 |
71 | public MyPagerAdapter(FragmentManager fm, boolean enabled) {
72 | super(fm);
73 | fragments = new ArrayList<>();
74 | fragments.add(new Pair(RecyclerViewContentFragment.newInstance(enabled), "RecyclerView"));
75 | fragments.add(new Pair(NestedScrollViewContentFragment.newInstance(enabled), "ScrollView"));
76 | fragments.add(new Pair(ListViewContentFragment.newInstance(enabled), "ListView"));
77 | }
78 |
79 | @Override
80 | public int getCount() {
81 | return fragments.size();
82 | }
83 |
84 | @Override
85 | public Fragment getItem(int position) {
86 | return fragments.get(position).first;
87 | }
88 |
89 | @Nullable
90 | @Override
91 | public CharSequence getPageTitle(int position) {
92 | return fragments.get(position).second;
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/h6ah4i/android/example/scrollableviewpagercontent/contents/ListViewContentFragment.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.example.scrollableviewpagercontent.contents;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.NonNull;
5 | import androidx.annotation.Nullable;
6 | import androidx.fragment.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.ArrayAdapter;
11 | import android.widget.ListView;
12 |
13 | import com.h6ah4i.android.example.scrollableviewpagercontent.R;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class ListViewContentFragment extends Fragment {
19 | public static ListViewContentFragment newInstance(boolean enabled) {
20 | Bundle args = new Bundle();
21 | args.putBoolean("SVPC_ENABLED", enabled);
22 |
23 | ListViewContentFragment fragment = new ListViewContentFragment();
24 | fragment.setArguments(args);
25 | return fragment;
26 | }
27 |
28 | @Nullable
29 | @Override
30 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | int resId = getArguments().getBoolean("SVPC_ENABLED")
32 | ? R.layout.page_fragment_list_view
33 | : R.layout.page_fragment_normal_list_view;
34 |
35 | return inflater.inflate(resId, container, false);
36 | }
37 |
38 | @Override
39 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
40 | super.onViewCreated(view, savedInstanceState);
41 |
42 | ListView listView = view.findViewById(R.id.list_view);
43 |
44 | List items = new ArrayList<>();
45 | for (int i = 0; i < 100; i++) {
46 | items.add(Integer.toString(i));
47 | }
48 | listView.setAdapter(new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, android.R.id.text1, items));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/h6ah4i/android/example/scrollableviewpagercontent/contents/NestedScrollViewContentFragment.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.example.scrollableviewpagercontent.contents;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.h6ah4i.android.example.scrollableviewpagercontent.R;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.annotation.Nullable;
12 | import androidx.fragment.app.Fragment;
13 |
14 | public class NestedScrollViewContentFragment extends Fragment {
15 | public static NestedScrollViewContentFragment newInstance(boolean enabled) {
16 | Bundle args = new Bundle();
17 | args.putBoolean("SVPC_ENABLED", enabled);
18 |
19 | NestedScrollViewContentFragment fragment = new NestedScrollViewContentFragment();
20 | fragment.setArguments(args);
21 | return fragment;
22 | }
23 |
24 | @Nullable
25 | @Override
26 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
27 | int resId = getArguments().getBoolean("SVPC_ENABLED")
28 | ? R.layout.page_fragment_nested_scroll_view
29 | : R.layout.page_fragment_normal_nested_scroll_view;
30 |
31 | return inflater.inflate(resId, container, false);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/h6ah4i/android/example/scrollableviewpagercontent/contents/RecyclerViewContentFragment.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.example.scrollableviewpagercontent.contents;
2 |
3 | import android.os.Bundle;
4 | import androidx.annotation.NonNull;
5 | import androidx.annotation.Nullable;
6 | import androidx.fragment.app.Fragment;
7 | import androidx.recyclerview.widget.LinearLayoutManager;
8 | import androidx.recyclerview.widget.RecyclerView;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 |
14 | import com.h6ah4i.android.example.scrollableviewpagercontent.R;
15 | import com.h6ah4i.android.scrollableviewpagercontent.recyclerview.ViewPagerContentRecyclerViewTouchEventInterceptor;
16 |
17 | public class RecyclerViewContentFragment extends Fragment {
18 | public static RecyclerViewContentFragment newInstance(boolean enabled) {
19 | Bundle args = new Bundle();
20 | args.putBoolean("SVPC_ENABLED", enabled);
21 |
22 | RecyclerViewContentFragment fragment = new RecyclerViewContentFragment();
23 | fragment.setArguments(args);
24 | return fragment;
25 | }
26 |
27 | @Nullable
28 | @Override
29 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | return inflater.inflate(R.layout.page_fragment_recycler_view, container, false);
31 | }
32 |
33 | @Override
34 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
35 | super.onViewCreated(view, savedInstanceState);
36 | RecyclerView recyclerView = view.findViewById(R.id.recycler_view);
37 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
38 | if (getArguments().getBoolean("SVPC_ENABLED")) {
39 | recyclerView.addOnItemTouchListener(new ViewPagerContentRecyclerViewTouchEventInterceptor());
40 | }
41 | recyclerView.setAdapter(new MyRecyclerViewAdapter());
42 | }
43 |
44 | private static class MyRecyclerViewAdapter extends RecyclerView.Adapter {
45 | @NonNull
46 | @Override
47 | public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
48 | final View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
49 | return new MyViewHolder(view);
50 | }
51 |
52 | @Override
53 | public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
54 | holder.textView.setText(Integer.toString(position));
55 | }
56 |
57 | @Override
58 | public int getItemCount() {
59 | return 100;
60 | }
61 | }
62 |
63 | private static class MyViewHolder extends RecyclerView.ViewHolder {
64 | private TextView textView;
65 |
66 | public MyViewHolder(View itemView) {
67 | super(itemView);
68 | textView = itemView.findViewById(android.R.id.text1);
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_view_pager.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
26 |
27 |
28 |
29 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_fragment_list_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_fragment_nested_scroll_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
49 |
50 |
55 |
56 |
61 |
62 |
67 |
68 |
69 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_fragment_normal_list_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_fragment_normal_nested_scroll_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
49 |
50 |
55 |
56 |
61 |
62 |
67 |
68 |
69 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/page_fragment_recycler_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/appmenu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 8dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ScrollableViewPagerContent
3 | Settings
4 | Hello World from section: %1$d
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.0-rc03'
11 | classpath 'guru.stefma.bintrayrelease:bintrayrelease:1.0.0'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
29 | ext {
30 | COMPILE_SDK_VERSION = 28
31 | TARGET_SDK_VERSION = 28
32 | MIN_SDK_VERSION = 14
33 |
34 | LIBRARY_CORE_VERSION = '1.0.0'
35 | LIBRARY_RECYCLERVIEW_VERSION = '1.0.0'
36 | LIBRARY_NESTEDSCROLLVIEW_VERSION = '1.0.0'
37 | LIBRARY_LISTVIEW_VERSION = '1.0.0'
38 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | android.enableJetifier=true
13 | android.useAndroidX=true
14 | org.gradle.jvmargs=-Xmx1536m
15 |
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Sep 24 16:59:21 JST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/capture.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h6ah4i/android-scrollableviewpagercontent/2fab922907852c97a8f82023dc9e6e2ae5191ec4/images/capture.gif
--------------------------------------------------------------------------------
/library-listview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library-listview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'guru.stefma.bintrayrelease'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.COMPILE_SDK_VERSION
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.MIN_SDK_VERSION
9 | targetSdkVersion rootProject.ext.TARGET_SDK_VERSION
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation project(':scrollableviewpagercontent')
28 | implementation 'androidx.appcompat:appcompat:1.0.0'
29 | }
30 |
31 | group = 'com.h6ah4i.android.scrollableviewpagercontent'
32 | version = rootProject.ext.LIBRARY_LISTVIEW_VERSION
33 | publish {
34 | userOrg = 'h6ah4i'
35 | artifactId = 'scrollableviewpagercontent-listview'
36 | uploadName = 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-listview'
37 | desc = 'ListView binding of ScrollableViewPagerContent library'
38 | website = 'https://github.com/h6ah4i/android-scrollableviewpagercontent'
39 | }
40 |
--------------------------------------------------------------------------------
/library-listview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library-listview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library-listview/src/main/java/com/h6ah4i/android/scrollableviewpagercontent/listview/ViewPagerContentListView.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.scrollableviewpagercontent.listview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.util.AttributeSet;
6 | import android.view.MotionEvent;
7 | import android.widget.ListView;
8 |
9 | import com.h6ah4i.android.scrollableviewpagercontent.ScrollableViewPagerContentTouchEventDelegator;
10 |
11 | /**
12 | * Created by hasegawa on 2018/03/04.
13 | */
14 |
15 | public class ViewPagerContentListView extends ListView {
16 | ScrollableViewPagerContentTouchEventDelegator mPagerContentTouchEventDelegator;
17 |
18 | public ViewPagerContentListView(Context context) {
19 | super(context);
20 | }
21 |
22 | public ViewPagerContentListView(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | }
25 |
26 | public ViewPagerContentListView(Context context, AttributeSet attrs, int defStyleAttr) {
27 | super(context, attrs, defStyleAttr);
28 | }
29 |
30 | private ScrollableViewPagerContentTouchEventDelegator ensureDelegator() {
31 | if (mPagerContentTouchEventDelegator == null) {
32 | mPagerContentTouchEventDelegator = new ScrollableViewPagerContentTouchEventDelegator(getContext());
33 | }
34 | return mPagerContentTouchEventDelegator;
35 | }
36 |
37 | @Override
38 | public boolean onInterceptTouchEvent(MotionEvent ev) {
39 | if (ensureDelegator().onInterceptTouchEvent(this, ev)) {
40 | return true;
41 | }
42 |
43 | return super.onInterceptTouchEvent(ev);
44 | }
45 |
46 | @Override
47 | @SuppressLint("ClickableViewAccessibility")
48 | public boolean onTouchEvent(MotionEvent ev) {
49 | if (ensureDelegator().onTouchEvent(this, ev)) {
50 | return true;
51 | }
52 |
53 | return super.onTouchEvent(ev);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/library-nestedscrollview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library-nestedscrollview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'guru.stefma.bintrayrelease'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.COMPILE_SDK_VERSION
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.MIN_SDK_VERSION
9 | targetSdkVersion rootProject.ext.TARGET_SDK_VERSION
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation project(':scrollableviewpagercontent')
28 | implementation 'androidx.appcompat:appcompat:1.0.0'
29 | }
30 |
31 | group = 'com.h6ah4i.android.scrollableviewpagercontent'
32 | version = rootProject.ext.LIBRARY_NESTEDSCROLLVIEW_VERSION
33 | publish {
34 | userOrg = 'h6ah4i'
35 | artifactId = 'scrollableviewpagercontent-nestedscrollview'
36 | uploadName = 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-nestedscrollview'
37 | desc = 'NestedScrollView binding of ScrollableViewPagerContent library'
38 | website = 'https://github.com/h6ah4i/android-scrollableviewpagercontent'
39 | }
--------------------------------------------------------------------------------
/library-nestedscrollview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library-nestedscrollview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library-nestedscrollview/src/main/java/com/h6ah4i/android/scrollableviewpagercontent/nestedscrollview/ViewPagerContentNestedScrollView.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.scrollableviewpagercontent.nestedscrollview;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import androidx.annotation.NonNull;
6 | import androidx.annotation.Nullable;
7 | import androidx.core.widget.NestedScrollView;
8 | import android.util.AttributeSet;
9 | import android.view.MotionEvent;
10 |
11 | import com.h6ah4i.android.scrollableviewpagercontent.ScrollableViewPagerContentTouchEventDelegator;
12 |
13 | public class ViewPagerContentNestedScrollView extends NestedScrollView {
14 | private ScrollableViewPagerContentTouchEventDelegator mPagerContentTouchEventDelegator;
15 |
16 | public ViewPagerContentNestedScrollView(@NonNull Context context) {
17 | super(context);
18 | }
19 |
20 | public ViewPagerContentNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 |
24 | public ViewPagerContentNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
25 | super(context, attrs, defStyleAttr);
26 | }
27 |
28 | private ScrollableViewPagerContentTouchEventDelegator ensureDelegator() {
29 | if (mPagerContentTouchEventDelegator == null) {
30 | mPagerContentTouchEventDelegator = new ScrollableViewPagerContentTouchEventDelegator(getContext());
31 | }
32 | return mPagerContentTouchEventDelegator;
33 | }
34 |
35 | @Override
36 | public boolean onInterceptTouchEvent(MotionEvent ev) {
37 | if (ensureDelegator().onInterceptTouchEvent(this, ev)) {
38 | return true;
39 | }
40 |
41 | return super.onInterceptTouchEvent(ev);
42 | }
43 |
44 | @Override
45 | @SuppressLint("ClickableViewAccessibility")
46 | public boolean onTouchEvent(MotionEvent ev) {
47 | if (ensureDelegator().onTouchEvent(this, ev)) {
48 | return true;
49 | }
50 |
51 | return super.onTouchEvent(ev);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/library-recyclerview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library-recyclerview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'guru.stefma.bintrayrelease'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.COMPILE_SDK_VERSION
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.MIN_SDK_VERSION
9 | targetSdkVersion rootProject.ext.TARGET_SDK_VERSION
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation project(':scrollableviewpagercontent')
28 | implementation 'androidx.appcompat:appcompat:1.0.0'
29 | implementation 'androidx.recyclerview:recyclerview:1.0.0'
30 | }
31 |
32 | version = rootProject.ext.LIBRARY_RECYCLERVIEW_VERSION
33 | group = 'com.h6ah4i.android.scrollableviewpagercontent'
34 | publish {
35 | userOrg = 'h6ah4i'
36 | artifactId = 'scrollableviewpagercontent-recyclerview'
37 | uploadName = 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent-recyclerview'
38 | desc = 'RecyclerView binding of ScrollableViewPagerContent library'
39 | website = 'https://github.com/h6ah4i/android-scrollableviewpagercontent'
40 | }
--------------------------------------------------------------------------------
/library-recyclerview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library-recyclerview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library-recyclerview/src/main/java/com/h6ah4i/android/scrollableviewpagercontent/recyclerview/ViewPagerContentRecyclerViewTouchEventInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.scrollableviewpagercontent.recyclerview;
2 |
3 | import androidx.recyclerview.widget.RecyclerView;
4 | import android.view.MotionEvent;
5 |
6 | import com.h6ah4i.android.scrollableviewpagercontent.ScrollableViewPagerContentTouchEventDelegator;
7 |
8 | public class ViewPagerContentRecyclerViewTouchEventInterceptor implements RecyclerView.OnItemTouchListener {
9 | private ScrollableViewPagerContentTouchEventDelegator mPagerContentTouchEventDelegator;
10 |
11 | private ScrollableViewPagerContentTouchEventDelegator ensureDelegator(RecyclerView recyclerView) {
12 | if (mPagerContentTouchEventDelegator == null) {
13 | mPagerContentTouchEventDelegator = new ScrollableViewPagerContentTouchEventDelegator(recyclerView.getContext());
14 | }
15 | return mPagerContentTouchEventDelegator;
16 | }
17 |
18 | @Override
19 | public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
20 | return ensureDelegator(rv).onInterceptTouchEvent(rv, e);
21 | }
22 |
23 | @Override
24 | public void onTouchEvent(RecyclerView rv, MotionEvent e) {
25 | ensureDelegator(rv).onTouchEvent(rv, e);
26 | }
27 |
28 | @Override
29 | public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'guru.stefma.bintrayrelease'
3 |
4 | android {
5 | compileSdkVersion rootProject.ext.COMPILE_SDK_VERSION
6 |
7 | defaultConfig {
8 | minSdkVersion rootProject.ext.MIN_SDK_VERSION
9 | targetSdkVersion rootProject.ext.TARGET_SDK_VERSION
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | }
25 |
26 | dependencies {
27 | implementation 'androidx.annotation:annotation:1.0.0'
28 | }
29 |
30 | group = 'com.h6ah4i.android.scrollableviewpagercontent'
31 | version = rootProject.ext.LIBRARY_CORE_VERSION
32 | publish {
33 | userOrg = 'h6ah4i'
34 | artifactId = 'scrollableviewpagercontent'
35 | uploadName = 'com.h6ah4i.android.scrollableviewpagercontent:scrollableviewpagercontent'
36 | desc = 'The core module of ScrollableViewPagerContent library'
37 | website = 'https://github.com/h6ah4i/android-scrollableviewpagercontent'
38 | }
39 |
--------------------------------------------------------------------------------
/library/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/library/src/main/java/com/h6ah4i/android/scrollableviewpagercontent/ScrollableViewPagerContentTouchEventDelegator.java:
--------------------------------------------------------------------------------
1 | package com.h6ah4i.android.scrollableviewpagercontent;
2 |
3 | import android.content.Context;
4 | import androidx.annotation.NonNull;
5 | import android.view.MotionEvent;
6 | import android.view.View;
7 | import android.view.ViewConfiguration;
8 |
9 | public class ScrollableViewPagerContentTouchEventDelegator {
10 | final int mPagingTouchSlop;
11 | final int mTouchSlop;
12 | float mInitialMotionX;
13 | float mInitialMotionY;
14 | float mLastMotionX;
15 | float mLastMotionY;
16 | boolean mCheck;
17 |
18 | public ScrollableViewPagerContentTouchEventDelegator(@NonNull Context context) {
19 | ViewConfiguration vc = ViewConfiguration.get(context);
20 | mPagingTouchSlop = vc.getScaledPagingTouchSlop();
21 | mTouchSlop = vc.getScaledTouchSlop();
22 | }
23 |
24 | public boolean onInterceptTouchEvent(@NonNull View scrollableView, @NonNull MotionEvent ev) {
25 | return onHandleTouchEvent(scrollableView, ev, true);
26 | }
27 |
28 | public boolean onTouchEvent(@NonNull View scrollableView, @NonNull MotionEvent ev) {
29 | return onHandleTouchEvent(scrollableView, ev, false);
30 | }
31 |
32 | protected boolean onHandleTouchEvent(View scrollableView, MotionEvent ev, boolean intercept) {
33 | final int action = ev.getActionMasked();
34 | boolean handled = false;
35 |
36 | if (action == MotionEvent.ACTION_DOWN) {
37 | mCheck = true;
38 | mInitialMotionX = ev.getX();
39 | mInitialMotionY = ev.getY();
40 | } else if (action == MotionEvent.ACTION_MOVE && mCheck) {
41 | final float xDiff = Math.abs(ev.getX() - mLastMotionX);
42 | final float yDiff = Math.abs(ev.getY() - mLastMotionY);
43 |
44 | if (Math.abs(ev.getY() - mInitialMotionY) > mTouchSlop) {
45 | mCheck = false;
46 | } else if ((Math.abs(ev.getX() - mInitialMotionX) > mPagingTouchSlop) && (xDiff > yDiff)) {
47 | scrollableView.getParent().requestDisallowInterceptTouchEvent(false);
48 | handled = true;
49 | }
50 | } else {
51 | mCheck = false;
52 | }
53 |
54 | mLastMotionX = ev.getX();
55 | mLastMotionY = ev.getY();
56 |
57 | return handled;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library', ':library-recyclerview', ':library-nestedscrollview', ':library-listview'
2 |
3 | project(":library").name = "scrollableviewpagercontent"
4 | project(":library-recyclerview").name = "scrollableviewpagercontent-recyclerview"
5 | project(":library-nestedscrollview").name = "scrollableviewpagercontent-nestedscrollview"
6 | project(":library-listview").name = "scrollableviewpagercontent-listview"
7 |
--------------------------------------------------------------------------------