原博客链接:http://blog.youkuaiyun.com/lmj623565791/article/details/52204039
/** * http://blog.youkuaiyun.com/yanbober/article/details/49904715 Scroller详解及源码浅析 */ public class StickyNavLayout extends LinearLayout implements NestedScrollingParent { private static final String TAG = "StickyNavLayout"; @Override public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { Log.e(TAG, "onStartNestedScroll"); return true; } @Override public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { Log.e(TAG, "onNestedScrollAccepted"); } @Override public void onStopNestedScroll(View target) { Log.e(TAG, "onStopNestedScroll"); } @Override public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { Log.e(TAG, "onNestedScroll"); } @Override public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { // 手指向上滑动dy > 0 下滑 dy < 0 // 手指上滑 顶部布局未完全隐藏 boolean hiddenTop = dy > 0 && getScrollY() < mTopViewHeight; // 手指下滑 // ViewCompat.canScrollVertically(target, -1) 检测target能否在指定的方向垂直滚动, 负数表示向上滚动 返回true表示能够上下滑 false表示不能下滑 boolean showTop = dy < 0 && getScrollY() >= 0 && !ViewCompat.canScrollVertically(target, -1); if (hiddenTop || showTop) { // 自己处理事件并且消费事件 scrollBy(0, dy); consumed[1] = dy; } } @Override public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { Log.e(TAG, "onNestedFling"); return false; } @Override public boolean onNestedPreFling(View target, float velocityX, float velocityY) { Log.e(TAG, "onNestedPreFling"); //down - //up+ 顶部布局完全隐藏 if (getScrollY() >= mTopViewHeight) { return false; } fling((int) velocityY); return true; } @Override public int getNestedScrollAxes() { Log.e(TAG, "getNestedScrollAxes"); return 0; } private View mTop; private View mNav; private ViewPager mViewPager; private int mTopViewHeight; private OverScroller mScroller; private VelocityTracker mVelocityTracker; public StickyNavLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(LinearLayout.VERTICAL); mScroller = new OverScroller(context); } private void initVelocityTrackerIfNotExists() { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } } private void recycleVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } @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)); ViewGroup.LayoutParams params = mViewPager.getLayoutParams(); params.height = getMeasuredHeight() - mNav.getMeasuredHeight(); 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) { /** * 在快速滑动松开的基础上开始惯性滚动,滚动距离取决于fling的初速度 */ 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) { y = mTopViewHeight; } if (y != getScrollY()) { super.scrollTo(x, y); } } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(0, mScroller.getCurrY()); invalidate(); } } }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(); // rotate(float)这个方法的旋转中心是坐标的原点 // 移动我们画图的坐标系的原点 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); } } }