package yungtat.xt.nesteddemo;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.NestedScrollingParentHelper;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Tong on 2019/4/2
* 使用NestedScrollingParent实现悬浮条
* 给需要悬浮的Item根布局打上"LAYOUT_TAG"的标签,
* 悬浮条打上"FLOAT_TAG"的标签
* 悬浮时替换之前的悬浮条
*/
public class SuspendRecyclerViewextends RecyclerViewimplements NestedScrollingParent {
private static final StringLAYOUT_TAG ="floatView";
private static final StringFLOAT_TAG ="float";
private static final StringHIDDEN_FLOAT_TAG ="hid_float";
private NestedScrollingParentHelpermNestedScrollingParentHelper;
//悬浮的item距离父类多少时显示悬浮
private int mSuspendTop;
//悬浮条
private ViewmSuspendView;
//承载悬浮条的Item
private ViewmSuspendItem;
//嵌套滑动
private ViewmScrollTarget, mScrollParent, mScrollSuspendView;
private ISuspendViewListenermListener;
public interface ISuspendViewListener {
void onSuspendViewListener(int position, View item);
}
public void setSuspendViewListener(ISuspendViewListener listener) {
this.mListener = listener;
}
public SuspendRecyclerView(@NonNull Context context) {
this(context, null);
}
public SuspendRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SuspendRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mSuspendTop =0;
mNestedScrollingParentHelper =new NestedScrollingParentHelper(this);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return false;
}
@Override
public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes) {
mScrollParent = child;
mScrollTarget = target;
mScrollSuspendView = getFloatView(child);
setSuspendLocation(mScrollParent, mScrollSuspendView);
if (targetinstanceof NestedScrollingChild) {
return true;
}
return super.onStartNestedScroll(child, target, axes);
}
@Override
public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes) {
mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes, ViewCompat.TYPE_TOUCH);
}
@Override
public void onStopNestedScroll(@NonNull View target) {
mNestedScrollingParentHelper.onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
}
@Override
public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
int dxUnconsumed, int dyUnconsumed) {
final int oldScrollY = getScrollY();
scrollBy(0, dyUnconsumed);
final int myConsumed = getScrollY() - oldScrollY;
final int myUnconsumed = dyUnconsumed - myConsumed;
dispatchNestedScroll(0, myConsumed, 0, myUnconsumed, null);
}
@Override
public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
setSuspendLocation(mScrollParent, mScrollSuspendView);
if (dy >0) {//向上滑动
if (getItemVirtualY(mScrollParent) <=0) {
consumed[1] =0;
}else {
scrollBy(0, dy);
consumed[1] = dy;
}
}else {//向下滑动
if (!target.canScrollVertically(-1) || getItemVirtualY(mScrollParent) <0) {
if (Math.abs(dy) < Math.abs(getItemVirtualY(mScrollParent)) || (getItemVirtualY(mScrollParent) ==0)) {
scrollBy(0, dy);
}else {
scrollBy(0, getItemVirtualY(mScrollParent));
}
consumed[1] = dy;
}else {
consumed[1] =0;
}
}
}
@Override
public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
if (getItemVirtualY(mScrollParent) >0) {
fling((int) velocityX, (int) (velocityY *0.8));
return true;
}
if (velocityY <0 && (!target.canScrollVertically(-1) || getItemVirtualY(mScrollParent) <0)) {
fling((int) velocityX, (int) (velocityY));
return true;
}
return super.onNestedPreFling(target, velocityX, velocityY);
}
@Override
public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY,
boolean consumed) {
if (velocityY >0 && !target.canScrollVertically(1)) {
fling((int) velocityX, (int) (velocityY *0.8));
return true;
}
return super.onNestedFling(target, velocityX, velocityY, consumed);
}
@Override
public void onScrolled(int dx, int dy) {
super.onScrolled(dx, dy);
initView();
setSuspendLocation(mSuspendItem, mSuspendView);
if (mScrollParent !=null &&mScrollSuspendView !=null &&mScrollTarget !=null) {
setSuspendLocation(mScrollParent, mScrollSuspendView);
}
if (mSuspendItem !=null) {
if (Math.abs(dy) > Math.abs(getItemVirtualY())) {
if ((dy >0 && getItemVirtualY() <0)//向上拉
|| (dy <0)) {//向下拉
stopScroll();
scrollBy(0, getItemVirtualY());
}
}
}
}
private void initView() {
if (getLayoutManager() ==null || !(getLayoutManager()instanceof LinearLayoutManager || getLayoutManager()instanceof StaggeredGridLayoutManager)) {
return;
}
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
int firstPosition = layoutManager.findFirstVisibleItemPosition();
int lastPosition = layoutManager.findLastVisibleItemPosition();
if (firstPosition != lastPosition && lastPosition < getChildCount()) {
for (int i = firstPosition; i < (lastPosition - firstPosition); i++) {
setSuspendLocation(getChildAt(i));
}
}
View child = layoutManager.findViewByPosition(firstPosition);
if (child !=null && child.getTag() !=null && child.getTag().toString().equals(LAYOUT_TAG)) {
mSuspendItem = child;
mSuspendView = getFloatView(child);
if (mSuspendView !=null &&mListener !=null) {
mListener.onSuspendViewListener(firstPosition, child);
}
}
setSuspendLocation(mSuspendItem, mSuspendView);
}
/**
* 悬浮条位置
*
* @param container 容器
* @param view 悬浮条
*/
private void setSuspendLocation(View container, View view) {
if (container !=null && view !=null) {
float kk = -getItemVirtualY(container);
int max = container.getMeasuredHeight() - view.getMeasuredHeight();
if (kk <=0) {
kk =0;
}else if (kk > max) {
kk = max;
}
view.setY(kk);
}
}
/**
* 悬浮条位置
*
* @param container 容器
*/
private void setSuspendLocation(View container) {
if (containerinstanceof ViewGroup) {
int childCount = ((ViewGroup) container).getChildCount();
View mFloatView=null;
View mHidFloatView=null;
for (int i =0; i < childCount; i++) {
View childItem = ((ViewGroup) container).getChildAt(i);
if (childItem !=null && childItem.getTag() !=null) {
if (childItem.getTag().toString().equals(FLOAT_TAG)) {
float kk = -getItemVirtualY(container);
int max = container.getMeasuredHeight() - childItem.getMeasuredHeight();
if (kk <=0) {
kk =0;
}else if (kk > max) {
kk = max;
}
mFloatView=childItem;
childItem.setY(kk);
}else if (childItem.getTag().toString().equals(HIDDEN_FLOAT_TAG)) {
mHidFloatView=childItem;
}
}
}
if(mHidFloatView!=null&&mFloatView!=null){
if(mFloatView.getY()!=0){
mHidFloatView.setVisibility(View.VISIBLE);
mFloatView.setVisibility(View.INVISIBLE);
}else {
mHidFloatView.setVisibility(View.INVISIBLE);
mFloatView.setVisibility(View.VISIBLE);
}
}
}
}
private ViewgetFloatView(@NonNull View child) {
if (childinstanceof ViewGroup) {
int childCount = ((ViewGroup) child).getChildCount();
for (int i =0; i < childCount; i++) {
View childItem = ((ViewGroup) child).getChildAt(i);
if (childItem.getTag() !=null) {
if (childItem.getTag().toString().equals(FLOAT_TAG)) {
return childItem;
}
}
}
}
return null;
}
/**
* item 真实Y轴+想要停止的Y轴
*/
private int getItemVirtualY(View... views) {
if (views.length >=1) {
return (int) (views[0].getY() -mSuspendTop);
}
if (mSuspendItem !=null) {
return (int) (mSuspendItem.getY() -mSuspendTop);
}
return 0;
}
}