├── README.md
├── build.gradle
└── src
├── androidTest
└── java
│ └── com
│ └── mkishan
│ └── nestedScrollCompat
│ └── view
│ └── ApplicationTest.java
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── mkishan
│ └── nestedScrollCompat
│ └── view
│ ├── CompatListView.java
│ ├── MainActivity.java
│ └── ViewFragment.java
└── res
├── layout
├── activity_main.xml
└── tab_fragment.xml
├── menu
└── menu_main.xml
├── mipmap-hdpi
└── ic_launcher.png
├── mipmap-mdpi
└── ic_launcher.png
├── mipmap-xhdpi
└── ic_launcher.png
├── mipmap-xxhdpi
└── ic_launcher.png
├── values-w820dp
└── dimens.xml
└── values
├── dimens.xml
├── strings.xml
└── styles.xml
/README.md:
--------------------------------------------------------------------------------
1 | # nestedScrollCompat-listview
2 | This is Android's good old List View with Material Design properties, i.e it has nested scroll enabled, so that the Views/toolbars collapse on scrolling.
3 |
4 | **Very Important & Quick Setup Guidelines**
5 | As per Android's guidelines, the scrolling content which collapses the toolBar or View, i.e the view with the tag **app:layout_behavior="@string/appbar_scrolling_view_behavior"** should always be declared **above** & outside the **AppBar Layout** To use this feature, just copy the **CompatlistView** class in your project and use it in your Layout xmls or in Java classes accordingly
6 |
7 | In the example project above, the fragment has a listview which collapses the toolbar, hence the fragment is declared above appbarlayout. Fragment is declared with the property, **app:layout_behavior="@string/appbar_scrolling_view_behavior"**.
8 |
9 | **Directions for use**
10 |
11 | 1) Replace all your **listview** tags with **com.mkishan.nestedScrollCompat.view.CompatListView** tag and add the **app:layout_behavior="@string/appbar_scrolling_view_behavior"** to the parent layout.
12 |
13 | 2) All default listview properties are applicable to this custom list view in XML as well as Java.
14 |
15 | 
16 | 
17 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.0"
6 | defaultConfig {
7 | applicationId 'com.mkishan.nestedScrollCompat.view'
8 | minSdkVersion 15
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | dependencies {
20 | compile fileTree(dir: 'libs', include: ['*.jar'])
21 | compile 'com.android.support:appcompat-v7:23.0.0'
22 | compile 'com.android.support:design:23.0.0'
23 | }
24 | productFlavors {
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | compile 'com.android.support:appcompat-v7:23.0.0'
31 | }
32 |
--------------------------------------------------------------------------------
/src/androidTest/java/com/mkishan/nestedScrollCompat/view/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.mkishan.nestedScrollCompat.view;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/com/mkishan/nestedScrollCompat/view/CompatListView.java:
--------------------------------------------------------------------------------
1 | package com.mkishan.nestedScrollCompat.view;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.support.v4.view.MotionEventCompat;
7 | import android.support.v4.view.NestedScrollingChild;
8 | import android.support.v4.view.NestedScrollingChildHelper;
9 | import android.support.v4.view.ViewCompat;
10 | import android.util.AttributeSet;
11 | import android.util.Log;
12 | import android.view.MotionEvent;
13 | import android.widget.ListView;
14 |
15 | /**
16 | * Created by mkishan on 9/27/2015.
17 | */
18 | public class CompatListView extends ListView implements NestedScrollingChild {
19 | private NestedScrollingChildHelper helper;
20 | private int mLastY;
21 | private final int[] mScrollOffset = new int[2];
22 | private final int[] mScrollConsumed = new int[2];
23 | private int mNestedOffsetY;
24 | public CompatListView(Context context) {
25 | super(context);
26 | helper = new NestedScrollingChildHelper(this);
27 | setNestedScrollingEnabled(true);
28 | }
29 |
30 | public CompatListView(Context context, AttributeSet attrs) {
31 | super(context, attrs);
32 | helper = new NestedScrollingChildHelper(this);
33 | setNestedScrollingEnabled(true);
34 | }
35 |
36 | public CompatListView(Context context, AttributeSet attrs, int defStyleAttr) {
37 | super(context, attrs, defStyleAttr);
38 | helper = new NestedScrollingChildHelper(this);
39 | setNestedScrollingEnabled(true);
40 | }
41 |
42 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
43 | public CompatListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
44 | super(context, attrs, defStyleAttr, defStyleRes);
45 | helper = new NestedScrollingChildHelper(this);
46 | setNestedScrollingEnabled(true);
47 | }
48 |
49 | @Override
50 | public void setNestedScrollingEnabled(boolean enabled) {
51 | helper.setNestedScrollingEnabled(enabled);
52 | }
53 |
54 | @Override
55 | public boolean startNestedScroll(int axes) {
56 | return helper.startNestedScroll(axes);
57 | }
58 |
59 | @Override
60 | public void stopNestedScroll() {
61 | helper.stopNestedScroll();
62 | }
63 |
64 | @Override
65 | public boolean hasNestedScrollingParent() {
66 | return helper.hasNestedScrollingParent();
67 | }
68 |
69 | @Override
70 | public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) {
71 | return helper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
72 | }
73 |
74 | @Override
75 | public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
76 | return helper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
77 | }
78 |
79 | @Override
80 | public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
81 | return helper.dispatchNestedFling(velocityX, velocityY, consumed);
82 | }
83 |
84 | @Override
85 | public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
86 | return helper.dispatchNestedPreFling(velocityX, velocityY);
87 | }
88 |
89 | // @Override
90 | // public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
91 | // super.onNestedScroll(target, dxConsumed, dyUnconsumed, dxUnconsumed, dyConsumed);
92 | // }
93 |
94 | @Override public boolean onTouchEvent(MotionEvent event) {
95 | boolean rs = false;
96 | final int action = MotionEventCompat.getActionMasked(event);
97 | if (action == MotionEvent.ACTION_DOWN) {
98 | mNestedOffsetY = 0;
99 | }
100 | int y = (int) event.getY();
101 | event.offsetLocation(0,mNestedOffsetY);
102 | switch (action) {
103 | case MotionEvent.ACTION_DOWN:
104 | rs = super.onTouchEvent(event);
105 | mLastY = y;
106 | break;
107 | case MotionEvent.ACTION_MOVE:
108 |
109 | int dy = mLastY - y;
110 | int oldY = getScrollY();
111 | startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
112 |
113 | if (dispatchNestedPreScroll(0, dy, mScrollConsumed, mScrollOffset)) {
114 | dy -= mScrollConsumed[1];
115 | event.offsetLocation(0,-mScrollOffset[1]);
116 | mNestedOffsetY += mScrollOffset[1];
117 | }
118 | rs = super.onTouchEvent(event);
119 | mLastY = y - mScrollOffset[1];
120 | if (dy < 0) {
121 | int newScrollY = Math.max(0, oldY+dy);
122 | dy -= newScrollY - oldY;
123 | if (dispatchNestedScroll(0, newScrollY - dy, 0, dy, mScrollOffset)) {
124 | event.offsetLocation(0,mScrollOffset[1]);
125 | mNestedOffsetY += mScrollOffset[1];
126 | mLastY -= mScrollOffset[1];
127 | }
128 | }
129 | Log.d("dy", dy + "");
130 | Log.d("oldy", oldY+"");
131 | Log.d("mlasty", mLastY+"");
132 | stopNestedScroll();
133 | break;
134 | case MotionEvent.ACTION_UP:
135 | case MotionEvent.ACTION_CANCEL:
136 | rs = super.onTouchEvent(event);
137 | // mLastY = 0;
138 | // mNestedOffsetY = 0;
139 | stopNestedScroll();
140 | break;
141 | }
142 | return rs;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/com/mkishan/nestedScrollCompat/view/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.mkishan.nestedScrollCompat.view;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.support.v7.widget.Toolbar;
6 | import android.view.Menu;
7 | import android.view.MenuItem;
8 |
9 | public class MainActivity extends AppCompatActivity {
10 |
11 | @Override
12 | protected void onCreate(Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_main);
15 | Toolbar toolBar = (Toolbar)findViewById(R.id.toolbar);
16 | toolBar.setTitle("ToolBar");
17 | toolBar.setTitleTextColor(getResources().getColor(android.R.color.white));
18 | setSupportActionBar(toolBar);
19 |
20 | // android.app.FragmentTransaction trans = getFragmentManager().beginTransaction();
21 | // trans.replace(R.id.nestedScrollVw, new ViewFragment());
22 | // trans.commit();
23 | }
24 |
25 | @Override
26 | public boolean onCreateOptionsMenu(Menu menu) {
27 | // Inflate the menu; this adds items to the action bar if it is present.
28 | getMenuInflater().inflate(R.menu.menu_main, menu);
29 | return true;
30 | }
31 |
32 | @Override
33 | public boolean onOptionsItemSelected(MenuItem item) {
34 | // Handle action bar item clicks here. The action bar will
35 | // automatically handle clicks on the Home/Up button, so long
36 | // as you specify a parent activity in AndroidManifest.xml.
37 | int id = item.getItemId();
38 |
39 | //noinspection SimplifiableIfStatement
40 | if (id == R.id.action_settings) {
41 | return true;
42 | }
43 |
44 | return super.onOptionsItemSelected(item);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/mkishan/nestedScrollCompat/view/ViewFragment.java:
--------------------------------------------------------------------------------
1 | package com.mkishan.nestedScrollCompat.view;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ArrayAdapter;
8 |
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * A placeholder fragment containing a simple view.
13 | */
14 | public class ViewFragment extends android.app.Fragment {
15 |
16 | public ViewFragment() {
17 |
18 | }
19 |
20 | @Override
21 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
22 | View rootView = inflater.inflate(R.layout.tab_fragment, container, false);
23 | CompatListView listView = (CompatListView) rootView.findViewById(R.id.listView);
24 | ArrayList list = new ArrayList<>();
25 | for (int i = 0; i < 20; i++) {
26 | list.add(i + "");
27 | }
28 | ArrayAdapter adapter = new ArrayAdapter(getActivity(),
29 | android.R.layout.simple_list_item_1, android.R.id.text1, list);
30 | listView.setAdapter(adapter);
31 | return rootView;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
18 |
19 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/res/layout/tab_fragment.xml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kishan-Cj/nestedScrollCompat-listview/53ba0c8c02d69090a8173697580d2beee74febed/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kishan-Cj/nestedScrollCompat-listview/53ba0c8c02d69090a8173697580d2beee74febed/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kishan-Cj/nestedScrollCompat-listview/53ba0c8c02d69090a8173697580d2beee74febed/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kishan-Cj/nestedScrollCompat-listview/53ba0c8c02d69090a8173697580d2beee74febed/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Compat ListView
3 |
4 | Hello world!
5 | Settings
6 |
7 |
--------------------------------------------------------------------------------
/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------