转载自hongyang blog:http://blog.youkuaiyun.com/lmj623565791/article/details/52204039
稍微改动了源码,因为要做的效果有点差别:实际效果为米多财富app产品中心首页(目前线上的app虽然实现了效果,但是快速滑动,有时会有bug),所以想要换一种思路解决,就是接下来要讨论的内容。——嵌套滑动
android 5.0之后,引入了几个类:
NestedScrollingChild
NestedScrollingParent
NestedScrollingChildHelper
NestedScrollingParentHelper
——v4包已经向下兼容,详细用法可以谷歌。
源码:
主要改动了
StickyNavLayout类的内容,其他类没有修改
package com.zhy.stickynavlayout.view;
import android.content.Context;
import android.support.v4.view.NestedScrollingParent;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.OverScroller;
import com.zhy.stickynavlayout.R;
public class StickyNavLayout extends LinearLayout implements NestedScrollingParent
{
//每次事件会调用一次
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes)
{
return true;
}
@Override
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes)
{
}
@Override
public void onStopNestedScroll(View target)
{
//getScrollY()的范围在0和mTopViewHeight/2之间
if(getScrollY()<=mTopViewHeight/4)//自动滑下来
{
mScroller.startScroll(0,getScrollY(),0,-getScrollY(),500);
}
else
{
mScroller.startScroll(0,getScrollY(),0,mTopViewHeight/2-getScrollY(),500);
}
postInvalidate();
}
@Override
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)
{
}
@Override
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed)
{
//dy向上移动为正,向下移动为负
boolean hiddenTop = dy > 0 && getScrollY() < mTopViewHeight/2;//为true表示还没有被隐藏
boolean showTop = dy < 0 && getScrollY() >= 0 && !ViewCompat.canScrollVertically(target, -1);//为true表示不能再往下滑动了
//target滑动的时候为true,
if (hiddenTop || showTop)//表示头部还没有完全隐藏
{
scrollBy(0, dy);
consumed[1] = dy;
}
}
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed)
{
return false;
}
@Override
public boolean onNestedPreFling(View target, float velocityX, float velocityY)
{
//down - //up+
if (getScrollY() >= mTopViewHeight/2) return false;
fling((int) velocityY);//没演示出什么作用
return true;
}
@Override
public int getNestedScrollAxes()
{
return 0;
}
private View mTop;
private View mNav;
private ViewPager mViewPager;
private int mTopViewHeight;
private OverScroller mScroller;
public StickyNavLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
mScroller = new OverScroller(context);
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
mTop = findViewById(R.id.id_stickynavlayout_topview);
mNav = findViewById(R.id.id_stickynavlayout_indicator);
View view = findViewById(R.id.id_stickynavlayout_viewpager);
if (!(view instanceof ViewPager))
{
throw new RuntimeException(
"id_stickynavlayout_viewpager show used by ViewPager !");
}
mViewPager = (ViewPager) view;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
//目的是防止滑动到顶部之后底部出现空白
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
getChildAt(0).measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
//重新设置viewpager的高度
ViewGroup.LayoutParams params = mViewPager.getLayoutParams();
params.height = getMeasuredHeight() - mNav.getMeasuredHeight()-mTop.getMeasuredHeight()/2;
//重新设置高度,使不会出现底部空白
setMeasuredDimension(getMeasuredWidth(), mTop.getMeasuredHeight() + mNav.getMeasuredHeight() + mViewPager.getMeasuredHeight());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mTopViewHeight = mTop.getMeasuredHeight();
}
public void fling(int velocityY)
{
mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
invalidate();
}
@Override
public void scrollTo(int x, int y)
{
if (y < 0)
{
y = 0;
}
if (y > mTopViewHeight/2)
{
y = mTopViewHeight/2;
}
if (y != getScrollY())
{
super.scrollTo(x, y);
}
}
@Override
public void computeScroll()
{
if (mScroller.computeScrollOffset())
{
scrollTo(0, mScroller.getCurrY());
invalidate();
}
}
}
SimpleViewPagerIndicator类
package com.zhy.stickynavlayout.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
public class SimpleViewPagerIndicator extends LinearLayout
{
private static final int COLOR_TEXT_NORMAL = 0xFF000000;
private static final int COLOR_INDICATOR_COLOR = Color.GREEN;
private String[] mTitles;
private int mTabCount;
private int mIndicatorColor = COLOR_INDICATOR_COLOR;
private float mTranslationX;
private Paint mPaint = new Paint();
private int mTabWidth;
public SimpleViewPagerIndicator(Context context)
{
this(context, null);
}
public SimpleViewPagerIndicator(Context context, AttributeSet attrs)
{
super(context, attrs);
mPaint.setColor(mIndicatorColor);
mPaint.setStrokeWidth(9.0F);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
mTabWidth = w / mTabCount;
}
public void setTitles(String[] titles)
{
mTitles = titles;
mTabCount = titles.length;
generateTitleView();
}
public void setIndicatorColor(int indicatorColor)
{
this.mIndicatorColor = indicatorColor;
}
@Override
protected void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
canvas.save();
canvas.translate(mTranslationX, getHeight() - 2);
canvas.drawLine(0, 0, mTabWidth, 0, mPaint);
canvas.restore();
}
public void scroll(int position, float offset)
{
/**
* <pre>
* 0-1:position=0 ;1-0:postion=0;
* </pre>
*/
mTranslationX = getWidth() / mTabCount * (position + offset);
invalidate();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
{
return super.dispatchTouchEvent(ev);
}
private void generateTitleView()
{
if (getChildCount() > 0)
this.removeAllViews();
int count = mTitles.length;
setWeightSum(count);
for (int i = 0; i < count; i++)
{
TextView tv = new TextView(getContext());
LayoutParams lp = new LayoutParams(0,
LayoutParams.MATCH_PARENT);
lp.weight = 1;
tv.setGravity(Gravity.CENTER);
tv.setTextColor(COLOR_TEXT_NORMAL);
tv.setText(mTitles[i]);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
tv.setLayoutParams(lp);
tv.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
}
});
addView(tv);
}
}
}
MainActivity类
package com.zhy.stickynavlayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import com.zhy.stickynavlayout.view.SimpleViewPagerIndicator;
public class MainActivity extends FragmentActivity
{
private String[] mTitles = new String[] { "简介", "评价", "相关" };
private SimpleViewPagerIndicator mIndicator;
private ViewPager mViewPager;
private FragmentPagerAdapter mAdapter;
private TabFragment[] mFragments = new TabFragment[mTitles.length];
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initDatas();
initEvents();
}
private void initEvents()
{
mViewPager.setOnPageChangeListener(new OnPageChangeListener()
{
@Override
public void onPageSelected(int position)
{
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels)
{
mIndicator.scroll(position, positionOffset);
}
@Override
public void onPageScrollStateChanged(int state)
{
}
});
}
private void initDatas()
{
mIndicator.setTitles(mTitles);
for (int i = 0; i < mTitles.length; i++)
{
mFragments[i] = (TabFragment) TabFragment.newInstance(mTitles[i]);
}
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
{
@Override
public int getCount()
{
return mTitles.length;
}
@Override
public Fragment getItem(int position)
{
return mFragments[position];
}
};
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(0);
}
private void initViews()
{
mIndicator = (SimpleViewPagerIndicator) findViewById(R.id.id_stickynavlayout_indicator);
mViewPager = (ViewPager) findViewById(R.id.id_stickynavlayout_viewpager);
}
}
TabFragment类
package com.zhy.stickynavlayout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.zhy.base.adapter.ViewHolder;
import com.zhy.base.adapter.recyclerview.CommonAdapter;
import java.util.ArrayList;
import java.util.List;
public class TabFragment extends Fragment
{
public static final String TITLE = "title";
private String mTitle = "Defaut Value";
private RecyclerView mRecyclerView;
// private TextView mTextView;
private List<String> mDatas = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getArguments() != null)
{
mTitle = getArguments().getString(TITLE);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_tab, container, false);
mRecyclerView = (RecyclerView) view
.findViewById(R.id.id_stickynavlayout_innerscrollview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// mTextView = (TextView) view.findViewById(R.id.id_info);
// mTextView.setText(mTitle);
for (int i = 0; i < 50; i++)
{
mDatas.add(mTitle + " -> " + i);
}
mRecyclerView.setAdapter(new CommonAdapter<String>(getActivity(), R.layout.item, mDatas)
{
@Override
public void convert(ViewHolder holder, String o)
{
holder.setText(R.id.id_info, o);
}
});
return view;
}
public static TabFragment newInstance(String title)
{
TabFragment tabFragment = new TabFragment();
Bundle bundle = new Bundle();
bundle.putString(TITLE, title);
tabFragment.setArguments(bundle);
return tabFragment;
}
}
activity_main.xml类
<com.zhy.stickynavlayout.view.StickyNavLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="@id/id_stickynavlayout_topview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#4400ff00" >
<TextView
android:layout_width="match_parent"
android:layout_height="256dp"
android:gravity="center"
android:text="软件介绍"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
<com.zhy.stickynavlayout.view.SimpleViewPagerIndicator
android:id="@id/id_stickynavlayout_indicator"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#ffffffff" >
</com.zhy.stickynavlayout.view.SimpleViewPagerIndicator>
<android.support.v4.view.ViewPager
android:id="@id/id_stickynavlayout_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</android.support.v4.view.ViewPager>
</com.zhy.stickynavlayout.view.StickyNavLayout >
fragment_tab.xml
<android.support.v7.widget.RecyclerView android:id="@id/id_stickynavlayout_innerscrollview"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44ff0000"
android:scrollbars="none">
</android.support.v7.widget.RecyclerView>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="@+id/id_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff"
android:gravity="center">
</TextView>
</FrameLayout>