Android 浮动置顶菜单实战

一、效果图

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

二、总体布局xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ll_headinfo"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_alignParentTop="true"
        android:background="@color/black_333333"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="头部导航"
            android:textColor="@color/white" />
    </LinearLayout>

    <com.example.yangdechengapplication.scrollview.StickyScrollViewList
        android:id="@+id/sticky_scroll_view_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/ll_headinfo"
        android:focusable="true"
        android:focusableInTouchMode="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:id="@+id/ll_top"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="80dp">

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:background="#b18f8f"
                        android:gravity="center"
                        android:text="这里可以无限添加顶部内容"
                        android:textColor="#000000"
                        android:textSize="20sp" />

                </RelativeLayout>
            </LinearLayout>

            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"></View>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:tag="sticky">

                <android.support.design.widget.TabLayout
                    android:id="@+id/tabs_order"
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="@color/white"
                    app:tabIndicatorColor="#F23A3A"
                    app:tabIndicatorHeight="3dp"
                    app:tabMinWidth="80dp"
                    app:tabMode="scrollable"
                    app:tabSelectedTextColor="#F23A3A"
                    app:tabTextColor="#333333" />
            </LinearLayout>


            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"></View>

            <com.example.yangdechengapplication.scrollview.CustomViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="#ffffff"
                android:visibility="visible" />

            <LinearLayout
                android:id="@+id/ll_bottom_info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:layout_marginTop="20dp"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="这里可以无限添加底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:background="#89a66f"
                    android:text="底部内容"
                    android:textColor="#000000"
                    android:textSize="20sp" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="10dp" />


            </LinearLayout>
        </LinearLayout>
    </com.example.yangdechengapplication.scrollview.StickyScrollViewList>

    <LinearLayout
        android:id="@+id/ll_bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:layout_alignParentBottom="true"
        android:background="@color/black_333333"
        android:gravity="center"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="底部导航"
            android:textColor="@color/white" />
    </LinearLayout>
</RelativeLayout>

三、StickyScrollViewActivity类

package com.example.yangdechengapplication.scrollview;

import android.app.Activity;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;

import com.example.yangdechengapplication.R;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by decheng.yang on 2017/10/26.
 */

public class StickyScrollViewActivity extends FragmentActivity implements StickyScrollViewList.OnScrollChangedListener, StickyScrollViewList.IOnScrollToEnd {

    private StickyScrollViewList mStickyScrollViewList;
    private TabLayout tabsOrder;

    private List<Fragment> fragmentList;
    private String[] titles;
    private CustomViewPager viewPager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stickyscrollview);
        mStickyScrollViewList = (StickyScrollViewList) findViewById(R.id.sticky_scroll_view_list);
        mStickyScrollViewList.setOnScrollListener(this);
        mStickyScrollViewList.setOnScrollToEndListener(this);
        tabsOrder = (TabLayout) findViewById(R.id.tabs_order);
        viewPager = (CustomViewPager) findViewById(R.id.viewPager);
        initMemu();
    }

    private void initMemu() {

        titles = new String[4];
        titles[0] = "昆明";
        titles[1] = "北京";
        titles[2] = "上海";
        titles[3] = "深圳";

        fragmentList = getChildFragmentList(titles);

        MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragmentList, titles, StickyScrollViewActivity.this);
        viewPager.setAdapter(adapter);
        viewPager.setOffscreenPageLimit(titles.length);
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                viewPager.resetHeight(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        viewPager.resetHeight(0);
        //viewPager.setPageTransformer(true, new ZoomOutPageTransformer());
        //viewPager.setPageTransformer(true, new DepthPageTransformer());
        //TabLayout
        //TabLayout tabLayout = (TabLayout)findViewById(R.id.tabLayout);
        tabsOrder.setupWithViewPager(viewPager);
        tabsOrder.setTabMode(TabLayout.MODE_SCROLLABLE);

       /* Animation animation = (Animation) AnimationUtils.loadAnimation(StickyScrollViewActivity.this, R.anim.fade_in);
        LayoutAnimationController lac = new LayoutAnimationController(animation);
        lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
        lac.setDelay(0.5f);
        tabsOrder.setLayoutAnimation(lac);*/


    }

    private List<Fragment> getChildFragmentList(String[] titles) {
        List<Fragment> fragmentList = new ArrayList<>();
        for (int i = 0; i < titles.length; i++) {
            Bundle bundle = new Bundle();

            String s = "";
            if (i == 0 || i == 3) {
                s = "我是菜单" + i + "的内容啊\n第一条 注意物资的种类和标识,不能因搬运\n" +
                        "第二条 尽量使用搬运工具;";
            } else if (i == 1) {
                s = "我是菜单" + i + "的内容啊\n第一条 注意物资的种类和标识,不能因搬运\n" +
                        "第二条 尽量使用搬运工具;\n" +
                        "第三条 注意人身和物资安全;\n" +
                        "第四条 注意物资的种类和标识,不能因搬运而使物资混乱不清,注意人身和物资安全;";
            } else if (i == 2) {
                s = "我是菜单" + i + "的内容啊\n第一条 注意物资的种类和标识,不能因搬运\n" +
                        "第二条 尽量使用搬运工具;\n" +
                        "第三条 注意人身和物资安全;\n" +
                        "第四条 注意物资的种类和标识,不能因搬运而使物资混乱不清,注意人身和物资安全; \"第三条 注意人身和物资安全;\\n\" +\n" +
                        "                        \"第四条 注意物资的种类和标识,不能因搬运而使物资混乱不清,注意人身和物资安全; \"第三条 注意人身和物资安全;\\n\" +\n" +
                        "                        \"第四条 注意物资的种类和标识,不能因搬运而使物资混乱不清,注意人身和物资安全;";
            }


            bundle.putString("content", s);
            bundle.putInt("position", i);
            TabLayoutFragment orderDetailRemarkFragment = new TabLayoutFragment();
            orderDetailRemarkFragment.setArguments(bundle);
            fragmentList.add(orderDetailRemarkFragment);
            orderDetailRemarkFragment.setCustomViewPager(this.viewPager);


        }
        return fragmentList;
    }

    @Override
    public void onScrollChanged(int l, int t, int oldl, int oldt) {

    }

    @Override
    public void onScrollToEnd() {

    }
}

四、CustomViewPager类

package com.example.yangdechengapplication.scrollview;

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;

import java.util.HashMap;
import java.util.LinkedHashMap;

/**
 * Created by decheng.yang on 2017/10/30.
 */

public class CustomViewPager extends ViewPager {

    private int current;
    private int height = 0;
    /**
     * 保存position与对于的View
     */
    private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();

    private boolean scrollble = true;

    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mChildrenViews.size() > current) {
            View child = mChildrenViews.get(current);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            height = child.getMeasuredHeight();
        }

        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    public void resetHeight(int current) {
        this.current = current;
        if (mChildrenViews.size() > current) {

            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
            if (layoutParams == null) {
                layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height);
            } else {
                layoutParams.height = height;
            }
            setLayoutParams(layoutParams);
        }
    }

    /**
     * 保存position与对于的View
     */
    public void setObjectForPosition(View view, int position) {
        mChildrenViews.put(position, view);
    }


    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!scrollble) {
            return true;
        }
        return super.onTouchEvent(ev);
    }


    public boolean isScrollble() {
        return scrollble;
    }

    public void setScrollble(boolean scrollble) {
        this.scrollble = scrollble;
    }

}

五、MyFragmentPagerAdapter类

package com.example.yangdechengapplication.scrollview;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by decheng.yang on 2017/10/13.
 */

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {


    private String[] titles;
    //public final int COUNT = titles.length;
    private List<Fragment> fragmentList = new ArrayList<>();
    private Context context;

    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragmentList, String[] titles, Context context) {
        super(fm);
        this.context = context;
        this.fragmentList = fragmentList;
        this.titles = titles;
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentList.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles[position];
    }
}

六、StickyScrollViewList类

package com.example.yangdechengapplication.scrollview;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.widget.ScrollView;

import com.example.yangdechengapplication.R;

import java.util.ArrayList;

public class StickyScrollViewList extends ScrollView {

    /**
     * Tag for views that should stick and have constant drawing. e.g.
     * TextViews, ImageViews etc
     */
    public static final String STICKY_TAG = "sticky";

    /**
     * Flag for views that should stick and have non-constant drawing. e.g.
     * Buttons, ProgressBars etc
     */
    public static final String FLAG_NONCONSTANT = "-nonconstant";

    /**
     * Flag for views that have aren't fully opaque
     */
    public static final String FLAG_HASTRANSPARANCY = "-hastransparancy";

    /**
     * Default height of the shadow peeking out below the stuck view.
     */
    private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp;
    /**
     * XKJ add for add 50dp offset of top
     */
    private static final int MIN_STICK_TOP = 0;// px
    //    private static final int MIN_STICK_TOP = 0;
    private ArrayList<View> stickyViews;
    private View currentlyStickingView;
    private float stickyViewTopOffset;
    private int stickyViewLeftOffset;
    private boolean redirectTouchesToStickyView;
    private boolean clippingToPadding;
    private boolean clipToPaddingHasBeenSet;

    private int mShadowHeight;
    private Drawable mShadowDrawable;
    private OnScrollChangedListener mOnScrollHandler = null;
    private IOnScrollToEnd mOnScrollToEnd = null;
    private IOnScroollToTop mOnScrollToTop = null;

    private final Runnable invalidateRunnable = new Runnable() {

        @Override
        public void run() {
            if (currentlyStickingView != null) {
                int l = getLeftForViewRelativeOnlyChild(currentlyStickingView);
                int t = getBottomForViewRelativeOnlyChild(currentlyStickingView);
                int r = getRightForViewRelativeOnlyChild(currentlyStickingView);
                int b = (int) (getScrollY() + (currentlyStickingView.getHeight() +
                        stickyViewTopOffset));
                invalidate(l, t, r, b);
            }
            postDelayed(this, 16);
        }
    };

    public StickyScrollViewList(Context context) {
        this(context, null);
    }

    public StickyScrollViewList(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.scrollViewStyle);
    }

    public StickyScrollViewList(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setup();

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StickyScrollView,
                defStyle, 0);

        final float density = context.getResources().getDisplayMetrics().density;
        int defaultShadowHeightInPix = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);

        mShadowHeight = a.getDimensionPixelSize(R.styleable.StickyScrollView_stuckShadowHeight,
                defaultShadowHeightInPix);

        int shadowDrawableRes = a.getResourceId(R.styleable.StickyScrollView_stuckShadowDrawable,
                -1);

        if (shadowDrawableRes != -1) {
            mShadowDrawable = context.getResources().getDrawable(shadowDrawableRes);
        }

        a.recycle();

    }

    /**
     * Sets the height of the shadow drawable in pixels.
     *
     * @param height
     */
    public void setShadowHeight(int height) {
        mShadowHeight = height;
    }

    public void setup() {
        stickyViews = new ArrayList<View>();
    }

    private int getLeftForViewRelativeOnlyChild(View v) {
        int left = v.getLeft();
        while (v.getParent() != getChildAt(0)) {
            v = (View) v.getParent();
            left += v.getLeft();
        }
        return left;
    }

    private int getTopForViewRelativeOnlyChild(View v) {
        int top = v.getTop();
        while (v.getParent() != getChildAt(0)) {
            v = (View) v.getParent();
            top += v.getTop();
        }
        return top;
    }

    private int getRightForViewRelativeOnlyChild(View v) {
        int right = v.getRight();
        while (v.getParent() != getChildAt(0)) {
            v = (View) v.getParent();
            right += v.getRight();
        }
        return right;
    }

    private int getBottomForViewRelativeOnlyChild(View v) {
        int bottom = v.getBottom();
        while (v.getParent() != getChildAt(0)) {
            v = (View) v.getParent();
            bottom += v.getBottom();
        }
        return bottom;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!clipToPaddingHasBeenSet) {
            clippingToPadding = true;
        }
        notifyHierarchyChanged();
    }

    @Override
    public void setClipToPadding(boolean clipToPadding) {
        super.setClipToPadding(clipToPadding);
        clippingToPadding = clipToPadding;
        clipToPaddingHasBeenSet = true;
    }

    @Override
    public void addView(View child) {
        super.addView(child);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, int index) {
        super.addView(child, index);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, int width, int height) {
        super.addView(child, width, height);
        findStickyViews(child);
    }

    @Override
    public void addView(View child, ViewGroup.LayoutParams params) {
        super.addView(child, params);
        findStickyViews(child);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (currentlyStickingView != null) {
            canvas.save();
            canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() +
                    stickyViewTopOffset
                    + (clippingToPadding ? getPaddingTop() : 0));

            canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth() -
                            stickyViewLeftOffset,
                    currentlyStickingView.getHeight() + mShadowHeight + 1);

            if (mShadowDrawable != null) {
                int left = 0;
                int right = currentlyStickingView.getWidth();
                int top = currentlyStickingView.getHeight();
                int bottom = currentlyStickingView.getHeight() + mShadowHeight;
                mShadowDrawable.setBounds(left, top, right, bottom);
                mShadowDrawable.draw(canvas);
            }

            canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(),
                    currentlyStickingView.getHeight());
            if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
                showView(currentlyStickingView);
                currentlyStickingView.draw(canvas);
                hideView(currentlyStickingView);
            } else {
                currentlyStickingView.draw(canvas);
            }
            canvas.restore();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            redirectTouchesToStickyView = true;
        }

        if (redirectTouchesToStickyView) {
            redirectTouchesToStickyView = currentlyStickingView != null;
            if (redirectTouchesToStickyView) {
                redirectTouchesToStickyView = ev.getY() <= (currentlyStickingView.getHeight() +
                        stickyViewTopOffset)
                        && ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView)
                        && ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView);
            }
        } else if (currentlyStickingView == null) {
            redirectTouchesToStickyView = false;
        }
        if (redirectTouchesToStickyView) {
            ev.offsetLocation(0, -1
                    * ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild
                    (currentlyStickingView)));

            // XKJ add TODO: remove this
            currentlyStickingView.invalidate();
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean hasNotDoneActionDown = true;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (redirectTouchesToStickyView) {
            ev.offsetLocation(0,
                    ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild
                            (currentlyStickingView)));
        }

        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            hasNotDoneActionDown = false;
        }

        if (hasNotDoneActionDown) {
            MotionEvent down = MotionEvent.obtain(ev);
            down.setAction(MotionEvent.ACTION_DOWN);
            super.onTouchEvent(down);
            hasNotDoneActionDown = false;
        }

        if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent
                .ACTION_CANCEL) {
            hasNotDoneActionDown = true;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        doTheStickyThing();
        if (mOnScrollHandler != null) {
            mOnScrollHandler.onScrollChanged(l, t, oldl, oldt);
        }
        int maxScroll = getChildAt(0).getHeight() - getHeight();
        if (getChildCount() > 0 && t == maxScroll) {
            if (mOnScrollToEnd != null) {
                mOnScrollToEnd.onScrollToEnd();
            }
        }
        if (getChildCount() <= 0 && t == getChildAt(0).getHeight()) {
            if (mOnScrollToTop != null) {
                mOnScrollToTop.onScroollToTop();
            }
        }
    }

    public void setOnScrollListener(OnScrollChangedListener handler) {
        mOnScrollHandler = handler;
    }

    public interface OnScrollChangedListener {
        public void onScrollChanged(int l, int t, int oldl, int oldt);
    }

    public interface IOnScrollToEnd {
        public void onScrollToEnd();
    }

    public interface IOnScroollToTop {
        public void onScroollToTop();
    }

    public void setOnScrollToEndListener(IOnScrollToEnd handler) {
        mOnScrollToEnd = handler;
    }

    private void doTheStickyThing() {
        View viewThatShouldStick = null;
        View approachingView = null;
        for (View v : stickyViews) {
            int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ?
                    0 : getPaddingTop())
                    - MIN_STICK_TOP;// add 50dp

            if (viewTop <= 0) {
                if (viewThatShouldStick == null
                        || viewTop > (getTopForViewRelativeOnlyChild(viewThatShouldStick) -
                        getScrollY() + (clippingToPadding ? 0
                        : getPaddingTop()))) {
                    viewThatShouldStick = v;
                }
            } else {
                if (approachingView == null
                        || viewTop < (getTopForViewRelativeOnlyChild(approachingView) -
                        getScrollY() + (clippingToPadding ? 0
                        : getPaddingTop()))) {
                    approachingView = v;
                }
            }
        }
        if (viewThatShouldStick != null) {
            stickyViewTopOffset = approachingView == null ? MIN_STICK_TOP : Math.min(MIN_STICK_TOP,
                    getTopForViewRelativeOnlyChild(approachingView) - getScrollY()
                            + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick
                            .getHeight());
            if (viewThatShouldStick != currentlyStickingView) {
                if (currentlyStickingView != null) {
                    stopStickingCurrentlyStickingView();
                }
                // only compute the left offset when we start sticking.
                stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick);
                startStickingView(viewThatShouldStick);
            }
        } else if (currentlyStickingView != null) {
            stopStickingCurrentlyStickingView();
        }
    }

    private void startStickingView(View viewThatShouldStick) {
        currentlyStickingView = viewThatShouldStick;
        if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
            hideView(currentlyStickingView);
        }
        if (((String) currentlyStickingView.getTag()).contains(FLAG_NONCONSTANT)) {
            post(invalidateRunnable);
        }
    }

    private void stopStickingCurrentlyStickingView() {
        if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)) {
            showView(currentlyStickingView);
        }
        currentlyStickingView = null;
        removeCallbacks(invalidateRunnable);
    }

    /**
     * Notify that the sticky attribute has been added or removed from one or
     * more views in the View hierarchy
     */
    public void notifyStickyAttributeChanged() {
        notifyHierarchyChanged();
    }

    private void notifyHierarchyChanged() {
        if (currentlyStickingView != null) {
            stopStickingCurrentlyStickingView();
        }
        stickyViews.clear();
        findStickyViews(getChildAt(0));
        doTheStickyThing();
        invalidate();
    }

    private void findStickyViews(View v) {
        if (v instanceof ViewGroup) {
            ViewGroup vg = (ViewGroup) v;
            for (int i = 0; i < vg.getChildCount(); i++) {
                String tag = getStringTagForView(vg.getChildAt(i));
                if (tag != null && tag.contains(STICKY_TAG)) {
                    stickyViews.add(vg.getChildAt(i));
                } else if (vg.getChildAt(i) instanceof ViewGroup) {
                    findStickyViews(vg.getChildAt(i));
                }
            }
        } else {
            String tag = (String) v.getTag();
            if (tag != null && tag.contains(STICKY_TAG)) {
                stickyViews.add(v);
            }
        }
    }

    private String getStringTagForView(View v) {
        Object tagObject = v.getTag();
        return String.valueOf(tagObject);
    }

    private void hideView(View v) {
        if (Build.VERSION.SDK_INT >= 11) {
            v.setAlpha(0);
        } else {
            AlphaAnimation anim = new AlphaAnimation(1, 0);
            anim.setDuration(0);
            anim.setFillAfter(true);
            v.startAnimation(anim);
        }
    }

    private void showView(View v) {
        if (Build.VERSION.SDK_INT >= 11) {
            v.setAlpha(1);
        } else {
            AlphaAnimation anim = new AlphaAnimation(0, 1);
            anim.setDuration(0);
            anim.setFillAfter(true);
            v.startAnimation(anim);
        }
    }

    /**
     * 解决vviewpager在scrollview滑动冲突的问题
     */
    // 滑动距离及坐标
    private float xDistance, yDistance, xLast, yLast;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                xDistance = yDistance = 0f;
                xLast = ev.getX();
                yLast = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float curX = ev.getX();
                final float curY = ev.getY();

                xDistance += Math.abs(curX - xLast);
                yDistance += Math.abs(curY - yLast);
//                com.ihaveu.utils.Log.i("test", "curx:"+curX+",cury:"+curY+",xlast:"+xLast+",
// ylast:"+yLast);
//                xLast = curX;
//                yLast = curY;

                if (xDistance > yDistance) {
                    return false;
                }

        }
        return super.onInterceptTouchEvent(ev);
    }
}

七、 TabLayoutFragment类

package com.example.yangdechengapplication.scrollview;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.example.yangdechengapplication.R;

/**
 * Created by decheng.yang on 2017/10/26.
 */

public class TabLayoutFragment extends android.support.v4.app.Fragment {
    private TextView tv_content;
    private View view;
    private CustomViewPager customViewPager;
    private String content = "";
    private int position = 0;

    public void setCustomViewPager(CustomViewPager customViewPager) {
        this.customViewPager = customViewPager;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        if (getArguments() != null) {
            content = (String) getArguments().get("content");
            position = (int) getArguments().get("position");
        }
        view = inflater.inflate(R.layout.fragment_tablayoutfragment, container, false);
        customViewPager.setObjectForPosition(view, position);

        super.onCreateView(inflater, container, savedInstanceState);
        tv_content = (TextView) view.findViewById(R.id.tv_content);
        tv_content.setText(content);
        return view;
    }
}

八、 TabLayoutFragment的布局xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">


    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:textColor="#DA3850" />
</LinearLayout>

如果对你有帮助,赏我1元奶粉钱吧,多谢!

微信:

这里写图片描述

支付宝:

这里写图片描述

发布了53 篇原创文章 · 获赞 58 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/XiNanHeiShao/article/details/78569571
今日推荐