diff --git a/app/build.gradle b/app/build.gradle
index 7206f5e..dbb2221 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,8 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:recyclerview-v7:28.0.0'
+ implementation 'com.android.support:design:27.0.0'
+
api project(':library')
// implementation 'com.github.JarvisGG:NestedTouchScrollingLayout:v1.1.1'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b0fbc9a..6f2c1cd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,6 +23,8 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/AppbarLayoutActivity.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/AppbarLayoutActivity.java
new file mode 100644
index 0000000..7fdf3b3
--- /dev/null
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/AppbarLayoutActivity.java
@@ -0,0 +1,248 @@
+package jarvis.com.nestedtouchscrollinglayout;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import jarvis.com.library.NestedTouchScrollingLayout;
+
+/**
+ * @author yyf @ Zhihu Inc.
+ * @since 12-05-2018
+ */
+public class AppbarLayoutActivity extends BaseActivity {
+ private int mContainerItemsCount = 20;
+ private int mInnerItemsCount = 30;
+
+ public static int mHalfWindowHeight = 400; // dp
+
+ public static int mVelocityYBound = 1300;
+
+ private RecyclerView mContainerRecycler;
+
+ private NestedTouchScrollingLayout mNestedTouchScrollingLayout;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_applayout);
+
+ findViewById(R.id.btn_open).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mNestedTouchScrollingLayout.expand();
+ }
+ });
+
+ mContainerRecycler = findViewById(R.id.container_rv);
+ mContainerRecycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+ mContainerRecycler.setAdapter(new InnerAdapter(this, 0x9966CC));
+ mContainerRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+
+ @Override
+ public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDrawOver(c, parent, state);
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.bottom = 30;
+ }
+ });
+
+ mNestedTouchScrollingLayout = findViewById(R.id.wrapper);
+ mNestedTouchScrollingLayout.registerNestScrollChildCallback(new NestedTouchScrollingLayout.INestChildScrollChange() {
+ @Override
+ public void onNestChildScrollChange(float deltaY) {
+
+ }
+
+ @Override
+ public void onNestChildScrollRelease(final float deltaY, final int velocityY) {
+ int totalYRange = mNestedTouchScrollingLayout.getMeasuredHeight();
+
+ int helfLimit = (totalYRange - DisplayUtils.dpToPixel(AppbarLayoutActivity.this, mHalfWindowHeight)) / 2;
+
+ int hideLimit = totalYRange - DisplayUtils.dpToPixel(AppbarLayoutActivity.this, mHalfWindowHeight) / 2;
+
+ int helfHeight = totalYRange - DisplayUtils.dpToPixel(AppbarLayoutActivity.this, mHalfWindowHeight);
+
+ if (velocityY > mVelocityYBound && velocityY > 0) {
+ if (Math.abs(deltaY) > helfHeight) {
+ mNestedTouchScrollingLayout.hiden();
+ } else {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(AppbarLayoutActivity.this,400));
+ }
+ } else if (velocityY < -mVelocityYBound && velocityY < 0) {
+ if (Math.abs(deltaY) < helfHeight) {
+ mNestedTouchScrollingLayout.expand();
+ } else {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(AppbarLayoutActivity.this,400));
+ }
+ } else {
+ if (Math.abs(deltaY) > hideLimit) {
+ mNestedTouchScrollingLayout.hiden();
+ } else if (Math.abs(deltaY) > helfLimit) {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(AppbarLayoutActivity.this, 400));
+ } else {
+ mNestedTouchScrollingLayout.expand();
+ }
+ }
+ }
+
+ @Override
+ public void onFingerUp(float velocityY) {
+
+ }
+
+ @Override
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
+
+ }
+ });
+
+ mNestedTouchScrollingLayout.setSheetDirection(NestedTouchScrollingLayout.SheetDirection.BOTTOM);
+ mNestedTouchScrollingLayout
+ .post(new Runnable() {
+ @Override
+ public void run() {
+ mNestedTouchScrollingLayout.recover(mNestedTouchScrollingLayout.getMeasuredHeight(), null, 0);
+ }
+ });
+ }
+
+ class ContainerAdapter extends RecyclerView.Adapter {
+
+ private Context mContext;
+ private LayoutInflater mInflater;
+
+ public ContainerAdapter(Context context) {
+ this.mContext = context;
+ this.mInflater = LayoutInflater.from(mContext);
+ }
+
+ @NonNull
+ @Override
+ public AppbarLayoutActivity.ContainerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View view = mInflater.inflate(R.layout.recycer_item, viewGroup, false);
+ return new AppbarLayoutActivity.ContainerViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull AppbarLayoutActivity.ContainerViewHolder containerViewHolder, int i) {
+ containerViewHolder.mRecycler.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
+ switch (i % 5) {
+ case 0:
+ containerViewHolder.mRecycler.setAdapter(new AppbarLayoutActivity.InnerAdapter(mContext, 0xFFCCFF));
+ break;
+ case 1:
+ containerViewHolder.mRecycler.setAdapter(new AppbarLayoutActivity.InnerAdapter(mContext, 0x9966CC));
+ break;
+ case 2:
+ containerViewHolder.mRecycler.setAdapter(new AppbarLayoutActivity.InnerAdapter(mContext, 0x33FF33));
+ break;
+ case 3:
+ containerViewHolder.mRecycler.setAdapter(new AppbarLayoutActivity.InnerAdapter(mContext, 0x33FFFF));
+ break;
+ case 4:
+ containerViewHolder.mRecycler.setAdapter(new AppbarLayoutActivity.InnerAdapter(mContext, 0xFFFF00));
+ break;
+ default:
+ break;
+ }
+
+ containerViewHolder.mRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+
+ @Override
+ public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDrawOver(c, parent, state);
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.bottom = 10;
+ }
+ });
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return mContainerItemsCount;
+ }
+ }
+
+ class ContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public RecyclerView mRecycler;
+
+ public ContainerViewHolder(@NonNull View itemView) {
+ super(itemView);
+ mRecycler = itemView.findViewById(R.id.recycler_id);
+ }
+ }
+
+
+
+ public class InnerAdapter extends RecyclerView.Adapter {
+
+ private Context mContext;
+ private LayoutInflater mInflater;
+ private @ColorInt
+ int mBgColor;
+
+ public InnerAdapter(Context context, @ColorInt int color) {
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
+ mBgColor = color;
+ }
+
+ @NonNull
+ @Override
+ public AppbarLayoutActivity.InnerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View view = mInflater.inflate(R.layout.main_item, viewGroup, false);
+ return new AppbarLayoutActivity.InnerViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull AppbarLayoutActivity.InnerViewHolder innerViewHolder, int i) {
+ innerViewHolder.tv.setText("Jarvis ----> " + i);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mInnerItemsCount;
+ }
+ }
+
+ public class InnerViewHolder extends RecyclerView.ViewHolder {
+
+ public TextView tv;
+
+ public InnerViewHolder(@NonNull View itemView) {
+ super(itemView);
+ tv = itemView.findViewById(R.id.main_tv);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/BottomSheetActivity.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/BottomSheetActivity.java
new file mode 100644
index 0000000..c034b1a
--- /dev/null
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/BottomSheetActivity.java
@@ -0,0 +1,251 @@
+package jarvis.com.nestedtouchscrollinglayout;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import jarvis.com.library.NestedTouchScrollingLayout;
+
+/**
+ * @author yyf @ Zhihu Inc.
+ * @since 12-04-2018
+ */
+
+public class BottomSheetActivity extends BaseActivity {
+
+ private int mContainerItemsCount = 20;
+ private int mInnerItemsCount = 30;
+
+ public static int mHalfWindowHeight = 400; // dp
+
+ public static int mVelocityYBound = 1300;
+
+ private RecyclerView mContainerRecycler;
+
+ private NestedTouchScrollingLayout mNestedTouchScrollingLayout;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_bottom);
+
+ findViewById(R.id.btn_open).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mNestedTouchScrollingLayout.expand();
+ }
+ });
+
+ mContainerRecycler = findViewById(R.id.container_rv);
+ mContainerRecycler.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+ mContainerRecycler.setAdapter(new InnerAdapter(this, 0x9966CC));
+ mContainerRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+
+ @Override
+ public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDrawOver(c, parent, state);
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.bottom = 30;
+ }
+ });
+
+ mNestedTouchScrollingLayout = findViewById(R.id.wrapper);
+ mNestedTouchScrollingLayout.registerNestScrollChildCallback(new NestedTouchScrollingLayout.INestChildScrollChange() {
+ @Override
+ public void onNestChildScrollChange(float deltaY) {
+
+ }
+
+ @Override
+ public void onNestChildScrollRelease(final float deltaY, final int velocityY) {
+ int totalYRange = mNestedTouchScrollingLayout.getMeasuredHeight();
+
+ int helfLimit = (totalYRange - DisplayUtils.dpToPixel(BottomSheetActivity.this, mHalfWindowHeight)) / 2;
+
+ int hideLimit = totalYRange - DisplayUtils.dpToPixel(BottomSheetActivity.this, mHalfWindowHeight) / 2;
+
+ int helfHeight = totalYRange - DisplayUtils.dpToPixel(BottomSheetActivity.this, mHalfWindowHeight);
+
+ if (velocityY > mVelocityYBound && velocityY > 0) {
+ if (Math.abs(deltaY) > helfHeight) {
+ mNestedTouchScrollingLayout.hiden();
+ } else {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(BottomSheetActivity.this,400));
+ }
+ } else if (velocityY < -mVelocityYBound && velocityY < 0) {
+ if (Math.abs(deltaY) < helfHeight) {
+ mNestedTouchScrollingLayout.expand();
+ } else {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(BottomSheetActivity.this,400));
+ }
+ } else {
+ if (Math.abs(deltaY) > hideLimit) {
+ mNestedTouchScrollingLayout.hiden();
+ } else if (Math.abs(deltaY) > helfLimit) {
+ mNestedTouchScrollingLayout.peek(mNestedTouchScrollingLayout.getMeasuredHeight() - DisplayUtils.dpToPixel(BottomSheetActivity.this, 400));
+ } else {
+ mNestedTouchScrollingLayout.expand();
+ }
+ }
+ }
+
+ @Override
+ public void onFingerUp(float velocityY) {
+
+ }
+
+ @Override
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
+
+ }
+ });
+
+ mNestedTouchScrollingLayout.setSheetDirection(NestedTouchScrollingLayout.SheetDirection.BOTTOM);
+ mNestedTouchScrollingLayout
+ .post(new Runnable() {
+ @Override
+ public void run() {
+ mNestedTouchScrollingLayout.recover(mNestedTouchScrollingLayout.getMeasuredHeight(), null, 0);
+ }
+ });
+ }
+
+ class ContainerAdapter extends RecyclerView.Adapter {
+
+ private Context mContext;
+ private LayoutInflater mInflater;
+
+ public ContainerAdapter(Context context) {
+ this.mContext = context;
+ this.mInflater = LayoutInflater.from(mContext);
+ }
+
+ @NonNull
+ @Override
+ public ContainerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View view = mInflater.inflate(R.layout.recycer_item, viewGroup, false);
+ return new ContainerViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ContainerViewHolder containerViewHolder, int i) {
+ containerViewHolder.mRecycler.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
+ switch (i % 5) {
+ case 0:
+ containerViewHolder.mRecycler.setAdapter(new InnerAdapter(mContext, 0xFFCCFF));
+ break;
+ case 1:
+ containerViewHolder.mRecycler.setAdapter(new InnerAdapter(mContext, 0x9966CC));
+ break;
+ case 2:
+ containerViewHolder.mRecycler.setAdapter(new InnerAdapter(mContext, 0x33FF33));
+ break;
+ case 3:
+ containerViewHolder.mRecycler.setAdapter(new InnerAdapter(mContext, 0x33FFFF));
+ break;
+ case 4:
+ containerViewHolder.mRecycler.setAdapter(new InnerAdapter(mContext, 0xFFFF00));
+ break;
+ default:
+ break;
+ }
+
+ containerViewHolder.mRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
+ @Override
+ public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ }
+
+ @Override
+ public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.onDrawOver(c, parent, state);
+ }
+
+ @Override
+ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.bottom = 10;
+ }
+ });
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return mContainerItemsCount;
+ }
+ }
+
+ class ContainerViewHolder extends RecyclerView.ViewHolder {
+
+ public RecyclerView mRecycler;
+
+ public ContainerViewHolder(@NonNull View itemView) {
+ super(itemView);
+ mRecycler = itemView.findViewById(R.id.recycler_id);
+ }
+ }
+
+
+
+ public class InnerAdapter extends RecyclerView.Adapter {
+
+ private Context mContext;
+ private LayoutInflater mInflater;
+ private @ColorInt
+ int mBgColor;
+
+ public InnerAdapter(Context context, @ColorInt int color) {
+ mContext = context;
+ mInflater = LayoutInflater.from(mContext);
+ mBgColor = color;
+ }
+
+ @NonNull
+ @Override
+ public InnerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+ View view = mInflater.inflate(R.layout.main_item, viewGroup, false);
+ return new InnerViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull InnerViewHolder innerViewHolder, int i) {
+ innerViewHolder.tv.setText("Jarvis ----> " + i);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mInnerItemsCount;
+ }
+ }
+
+ public class InnerViewHolder extends RecyclerView.ViewHolder {
+
+ public TextView tv;
+
+ public InnerViewHolder(@NonNull View itemView) {
+ super(itemView);
+ tv = itemView.findViewById(R.id.main_tv);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/DisplayUtils.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/DisplayUtils.java
new file mode 100644
index 0000000..694b20d
--- /dev/null
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/DisplayUtils.java
@@ -0,0 +1,97 @@
+package jarvis.com.nestedtouchscrollinglayout;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * @author yyf @ Zhihu Inc.
+ * @since 12-05-2018
+ */
+public class DisplayUtils {
+
+ public static int getScreenWidthPixels(final Context pContext) {
+ if (pContext == null) {
+ return 0;
+ }
+
+ return pContext.getResources().getDisplayMetrics().widthPixels;
+ }
+
+ public static int getScreenHeightPixels(final Context pContext) {
+ if (pContext == null) {
+ return 0;
+ }
+
+ return pContext.getResources().getDisplayMetrics().heightPixels;
+ }
+
+
+ public static int getActionBarHeightPixels(final Context pContext) {
+ final TypedValue typedValue = new TypedValue();
+
+ if (pContext != null && pContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)) {
+ return TypedValue.complexToDimensionPixelSize(typedValue.data, pContext.getResources().getDisplayMetrics());
+ }
+
+ return 0;
+ }
+
+ public static boolean hasNavigationBar(final Context pContext) {
+ final int id = pContext.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
+
+ if (id > 0) {
+ return pContext.getResources().getBoolean(id);
+ } else {
+ return !ViewConfiguration.get(pContext).hasPermanentMenuKey() && !KeyCharacterMap.deviceHasKey(KeyEvent
+ .KEYCODE_BACK);
+ }
+ }
+
+ public static int getNavigationBarHeight(final Context pContext) {
+ if (!DisplayUtils.hasNavigationBar(pContext)) {
+ return 0;
+ }
+
+ final Resources resources = pContext.getResources();
+
+ final int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
+
+ if (resourceId > 0) {
+ return resources.getDimensionPixelSize(resourceId);
+ }
+
+ return 0;
+ }
+
+ public static int pixelToDp(final Context pContext, final float pPixels) {
+ if (pContext == null) {
+ return 0;
+ }
+
+ final float density = pContext.getResources().getDisplayMetrics().density;
+
+ return (int) ((pPixels / density) + 0.5);
+ }
+
+ public static int dpToPixel(final Context pContext, final float pDp) {
+ if (pContext == null) {
+ return 0;
+ }
+
+ final float density = pContext.getResources().getDisplayMetrics().density;
+
+ return (int) ((pDp * density) + 0.5f);
+ }
+
+ public static int spToPixel(final Context pContext, final float pSp) {
+ if (pContext == null) {
+ return 0;
+ }
+
+ return (int) (pSp * pContext.getResources().getDisplayMetrics().scaledDensity + 0.5f);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/MainActivity.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/MainActivity.java
index 81213fd..fe245b6 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/MainActivity.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/MainActivity.java
@@ -20,7 +20,9 @@ public class MainActivity extends BaseActivity {
Class[] demoClasses = new Class[] {
RecyclerViewActivity.class,
WebViewActivity.class,
- ViewPagerActivity.class
+ ViewPagerActivity.class,
+ BottomSheetActivity.class,
+ AppbarLayoutActivity.class
};
private RecyclerView mRecycler;
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/RecyclerViewActivity.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/RecyclerViewActivity.java
index ff0d771..c9aed4c 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/RecyclerViewActivity.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/RecyclerViewActivity.java
@@ -12,6 +12,7 @@
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -83,7 +84,7 @@ public void onFingerUp(float velocityY) {
}
@Override
- public void onNestChildHorizationScroll(boolean show) {
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
}
});
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/WebViewActivity.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/WebViewActivity.java
index 0ebfe1e..f25d4b2 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/WebViewActivity.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/WebViewActivity.java
@@ -5,6 +5,7 @@
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.view.MotionEvent;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
@@ -54,7 +55,7 @@ public void onFingerUp(float velocityY) {
}
@Override
- public void onNestChildHorizationScroll(boolean show) {
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
}
});
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/BaseChildFragment.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/BaseChildFragment.java
index 775a40c..fc0be6a 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/BaseChildFragment.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/BaseChildFragment.java
@@ -6,6 +6,7 @@
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.View;
import jarvis.com.library.NestedTouchScrollingLayout;
@@ -51,7 +52,7 @@ public void onFingerUp(float velocityY) {
}
@Override
- public void onNestChildHorizationScroll(boolean show) {
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
}
});
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/RecyclerViewFragment.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/RecyclerViewFragment.java
index 477c927..172c6ed 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/RecyclerViewFragment.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/RecyclerViewFragment.java
@@ -11,6 +11,7 @@
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -72,7 +73,7 @@ public void onFingerUp(float velocityY) {
}
@Override
- public void onNestChildHorizationScroll(boolean show) {
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
}
});
diff --git a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/WebViewFragment.java b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/WebViewFragment.java
index 52602be..a48a344 100644
--- a/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/WebViewFragment.java
+++ b/app/src/main/java/jarvis/com/nestedtouchscrollinglayout/fragment/WebViewFragment.java
@@ -8,6 +8,7 @@
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceError;
@@ -70,7 +71,7 @@ public void onFingerUp(float velocityY) {
}
@Override
- public void onNestChildHorizationScroll(boolean show) {
+ public void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY) {
}
});
diff --git a/app/src/main/res/layout/activity_applayout.xml b/app/src/main/res/layout/activity_applayout.xml
new file mode 100644
index 0000000..d6fc949
--- /dev/null
+++ b/app/src/main/res/layout/activity_applayout.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_bottom.xml b/app/src/main/res/layout/activity_bottom.xml
new file mode 100644
index 0000000..f416e36
--- /dev/null
+++ b/app/src/main/res/layout/activity_bottom.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index c68efb7..e78ee3b 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -4,4 +4,6 @@
#00574B
#D81B60
#FFF
+ #000
+
diff --git a/library/build.gradle b/library/build.gradle
index 299c0ee..47babe5 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -31,6 +31,9 @@ dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
+
+ api 'com.android.support:design:28.0.0'
+
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
diff --git a/library/src/main/java/jarvis/com/library/NestedTouchScrollingLayout.java b/library/src/main/java/jarvis/com/library/NestedTouchScrollingLayout.java
index ccf9ad4..1c90034 100644
--- a/library/src/main/java/jarvis/com/library/NestedTouchScrollingLayout.java
+++ b/library/src/main/java/jarvis/com/library/NestedTouchScrollingLayout.java
@@ -8,9 +8,12 @@
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.design.widget.AppBarLayout;
+import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.animation.PathInterpolatorCompat;
import android.support.v4.widget.NestedScrollView;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Property;
import android.view.MotionEvent;
@@ -26,6 +29,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* @author yyf @ JarvisGG.io
@@ -116,6 +120,8 @@ public class NestedTouchScrollingLayout extends FrameLayout implements NestedScr
private List mNestChildScrollChangeCallbacks;
+ private Map mOnOffsetChangedListener = new ArrayMap<>();
+
private final Property SHEET_TRANSLATION = new Property(Float.class, "sheetTranslation") {
@Override
@@ -144,7 +150,7 @@ public interface INestChildScrollChange {
void onFingerUp(float velocityY);
- void onNestChildHorizationScroll(boolean show);
+ void onNestChildHorizationScroll(MotionEvent event, float deltaX, float deltaY);
}
public NestedTouchScrollingLayout(@NonNull Context context) {
@@ -203,10 +209,37 @@ public void addView(View child, ViewGroup.LayoutParams params) {
if (getChildCount() >= 1) {
throw new IllegalStateException("child must be 1!!!");
}
+ deepSearchView(child);
mChildView = child;
super.addView(child, params);
}
+ class OnNestOffsetChangedListener implements AppBarLayout.OnOffsetChangedListener {
+ int offsetY = 0;
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int offsetY) {
+ this.offsetY = offsetY;
+ }
+
+ public int getOffsetY() {
+ return Math.abs(offsetY);
+ }
+ }
+
+ private void deepSearchView(View parentView) {
+ if (parentView instanceof AppBarLayout) {
+ OnNestOffsetChangedListener listener = new OnNestOffsetChangedListener();
+ mOnOffsetChangedListener.put(parentView.hashCode(), listener);
+ ((AppBarLayout) parentView).addOnOffsetChangedListener(listener);
+ }
+
+ if (parentView instanceof ViewGroup) {
+ for (int i = 0; i < ((ViewGroup) parentView).getChildCount(); i++) {
+ deepSearchView(((ViewGroup) parentView).getChildAt(i));
+ }
+ }
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
@@ -265,7 +298,6 @@ public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
isFingerHolderTouch = false;
- isLeftorRightTouchLimit = true;
velocityTracker.computeCurrentVelocity(1000);
velocityY = velocityTracker.getYVelocity();
notifyOnFingerUp(velocityY);
@@ -280,13 +312,16 @@ public boolean onTouchEvent(MotionEvent event) {
float deltaY = mDownY - event.getY();
float deltaX = mDownX - event.getX();
- if ((!canScrollLeft(getChildAt(0), event.getX(), event.getX()) && !canScrollRight(getChildAt(0), event.getX(), event.getY()) && !isLeftorRightTouchLimit)
- || (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)) {
- interceptHorizationTouch(event, deltaX, deltaY);
+ if ((!canScrollLeft(getChildAt(0), event.getX(), event.getX()) &&
+ !canScrollRight(getChildAt(0), event.getX(), event.getY()) &&
+ !isLeftorRightTouchLimit) ||
+ (event.getAction() == MotionEvent.ACTION_UP ||
+ event.getAction() == MotionEvent.ACTION_CANCEL)) {
+ interceptHorizontalTouch(event, deltaX, deltaY);
}
if (!mParentOwnsTouch) {
- mParentOwnsTouch = Math.abs(deltaY) > mTouchSlop && Math.abs(deltaY) > Math.abs(deltaX);
+ mParentOwnsTouch = Math.abs(deltaY) > 0 && Math.abs(deltaY) > Math.abs(deltaX);
if (mParentOwnsTouch) {
@@ -325,7 +360,7 @@ public boolean onTouchEvent(MotionEvent event) {
}
}
- if (isHoldTouch) {
+ if (isHoldTouch && deltaY != 0) {
event.offsetLocation(0, mSheetTranslation - mTouchParentViewOriginMeasureHeight);
getChildAt(0).dispatchTouchEvent(event);
} else {
@@ -363,7 +398,7 @@ private boolean isChildCanScroll(MotionEvent event, float deltaY) {
* @param view
* @param x
* @param y
- * @param lockRect
+ * @param lockRect 是否开启 touch 所动在当前 view 区域
* @return
*/
protected boolean canScrollUp(View view, float x, float y, boolean lockRect) {
@@ -386,9 +421,30 @@ && canScrollUp(child, x - childLeft, y - childTop, lockRect)) {
}
}
}
+
+ if (view instanceof CoordinatorLayout &&
+ ((CoordinatorLayout) view).getChildCount() > 0 &&
+ ((CoordinatorLayout) view).getChildAt(0) instanceof AppBarLayout) {
+ AppBarLayout layout = (AppBarLayout) ((CoordinatorLayout) view).getChildAt(0);
+ OnNestOffsetChangedListener listener = mOnOffsetChangedListener.get(layout.hashCode());
+ if (listener != null) {
+ if (listener.getOffsetY() < layout.getMeasuredHeight() && listener.getOffsetY() > 0) {
+ return true;
+ }
+ }
+ }
+
return view.canScrollVertically(-1);
}
+ /**
+ * child can scroll
+ * @param view
+ * @param x
+ * @param y
+ * @param lockRect 是否开启 touch 所动在当前 view 区域
+ * @return
+ */
protected boolean canScrollDown(View view, float x, float y, boolean lockRect) {
if (view instanceof WebView) {
return canWebViewScrollDown();
@@ -408,6 +464,19 @@ && canScrollDown(child, x - childLeft, y - childTop, lockRect)) {
}
}
}
+
+ if (view instanceof CoordinatorLayout &&
+ ((CoordinatorLayout) view).getChildCount() > 0 &&
+ ((CoordinatorLayout) view).getChildAt(0) instanceof AppBarLayout) {
+ AppBarLayout layout = (AppBarLayout) ((CoordinatorLayout) view).getChildAt(0);
+ OnNestOffsetChangedListener listener = mOnOffsetChangedListener.get(layout.hashCode());
+ if (listener != null) {
+ if (listener.getOffsetY() < layout.getMeasuredHeight() && listener.getOffsetY() > 0) {
+ return true;
+ }
+ }
+ }
+
return view.canScrollVertically(1);
}
@@ -480,16 +549,18 @@ private void setSheetTranslation(float newTranslation) {
setTranslation(bottomClip);
}
- public void seAnimtTranslation(float transY) {
+ private void seAnimtTranslation(float transY) {
this.mSheetTranslation = mTouchParentViewOriginMeasureHeight - transY;
setTranslation(transY);
}
- public void setTranslation(float transY) {
+ private void setTranslation(float transY) {
if (mSheetDirection == SheetDirection.BOTTOM && transY < 0) {
+ mChildView.setTranslationY(0);
return;
}
if (mSheetDirection == SheetDirection.TOP && transY > 0) {
+ mChildView.setTranslationY(0);
return;
}
transY = transY > 0 ? transY * mDampingDown : transY * mDampingUp;
@@ -499,12 +570,13 @@ public void setTranslation(float transY) {
}
if (transY == 0) {
mDownSheetTranslation = mTouchParentViewOriginMeasureHeight;
+ mDownY -= mOriginTranslate;
mOriginTranslate = 0;
}
}
/**
- *
+ * 还原到某一位置
* @param target
*/
public void recover(int target) {
@@ -534,13 +606,13 @@ public void onAnimationEnd(@NonNull Animator animation) {
}
- private void interceptHorizationTouch(MotionEvent event, float deltaX, float deltaY) {
+ private void interceptHorizontalTouch(MotionEvent event, float deltaX, float deltaY) {
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
- notifyNestScrollChildHorizationCallback(false);
+ notifyNestScrollChildHorizontalCallback(event, deltaX, deltaY);
return;
}
- if (Math.abs(deltaX) > mTouchSlop * 8 && Math.abs(deltaX) > Math.abs(deltaY) && deltaX > 0) {
- notifyNestScrollChildHorizationCallback(true);
+ if (Math.abs(deltaX) > mTouchSlop * 8 && Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 0) {
+ notifyNestScrollChildHorizontalCallback(event, deltaX, deltaY);
}
}
@@ -613,9 +685,9 @@ private void notifyNestScrollChildReleaseCallback(int velocityY) {
}
}
- private void notifyNestScrollChildHorizationCallback(boolean show) {
+ private void notifyNestScrollChildHorizontalCallback(MotionEvent event, float deltaX, float deltaY) {
for (INestChildScrollChange change : mNestChildScrollChangeCallbacks) {
- change.onNestChildHorizationScroll(show);
+ change.onNestChildHorizationScroll(event, deltaX, deltaY);
}
}
@@ -630,10 +702,6 @@ protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
- public void setSheetDirection(@SheetDirection int direction) {
- mSheetDirection = direction;
- }
-
private float countDragDistanceFromMotionEvent(@NonNull MotionEvent event) {
float distance = event.getRawY();
return distance;
@@ -688,15 +756,24 @@ public float getMinFlingVelocity() {
return minFlingVelocity;
}
-
+ /**
+ * 展开
+ */
public void expand() {
expand(null);
}
+ /**
+ * 中间态
+ * @param offset
+ */
public void peek(int offset) {
peek(offset, null);
}
+ /**
+ * 隐藏
+ */
public void hiden() {
hiden(null);
}
@@ -713,11 +790,35 @@ public void hiden(Runnable runnable) {
recover(getMeasuredHeight(), runnable);
}
+ /**
+ * bottomSheet 方向
+ * @param direction
+ */
+ public void setSheetDirection(@SheetDirection int direction) {
+ mSheetDirection = direction;
+ }
+
+ /**
+ * 下阻尼
+ * @param mDampingDown
+ */
public void setDampingDown(float mDampingDown) {
this.mDampingDown = mDampingDown;
}
+ /**
+ * 上阻尼
+ * @param mDampingUp
+ */
public void setDampingUp(float mDampingUp) {
this.mDampingUp = mDampingUp;
}
+
+ /**
+ * 是否开启拦截
+ * @param b
+ */
+ public void setParentDispatchTouchEvent(boolean b) {
+ isParentDispatchTouchEvent = b;
+ }
}