仿美团滑动后头部固定源码分析

原创 2016年08月29日 14:03:43
public class StickyScrollView extends ScrollView {
    private static final String STICKY = "sticky";
    private View mCurrentStickyView;
    private Drawable mShadowDrawable;
    /**
     * 存放tagstickyView集合
     */
    private List<View> mStickyViews;
    private int mStickyViewTopOffset;
    private int defaultShadowHeight = 10;
    private float density;
    private boolean redirectTouchToStickyView;

    /**
     * 当点击Sticky的时候,实现某些背景的渐变
     */
    private Runnable mInvalidateRunnable = new Runnable() {

        @Override
        public void run() {
            if (mCurrentStickyView != null) {
                int left = mCurrentStickyView.getLeft();
                int top = mCurrentStickyView.getTop();
                int right = mCurrentStickyView.getRight();
                int bottom = getScrollY() + (mCurrentStickyView.getHeight() + mStickyViewTopOffset);
                invalidate(left, top, right, bottom);
            }
            postDelayed(this, 50);
        }
    };

    public StickyScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StickyScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mShadowDrawable = context.getResources().getDrawable(R.drawable.sticky_shadow_default);
        mStickyViews = new LinkedList();
        density = context.getResources().getDisplayMetrics().density;
    }

    /**
     * 找到设置tagView
     *
     * @param viewGroup
     */
    private void findViewByStickyTag(ViewGroup viewGroup) {
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = viewGroup.getChildAt(i);

            if (getStringTagForView(child).contains(STICKY)) {
                mStickyViews.add(child);
            }

            if (child instanceof ViewGroup) {
                findViewByStickyTag((ViewGroup) child);
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed) {
            findViewByStickyTag((ViewGroup) getChildAt(0));
        }
        showStickyView();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        showStickyView();
    }

    /**
     * 总结:
     * 只有一个StickyView的情况下
     * topOffset > 0(getScrollY() < stickyView.getTop()) curStickyView = null;
     * topOffset <= 0(getScrollY() >= stickyView.getTop()) curStickyView = view;
     */
    private void showStickyView() {
        View curStickyView = null;
        for (View v : mStickyViews) {
            int topOffset = v.getTop() - getScrollY();
            // 滑动距离开始大于v.getTop(),StickyView即将被滑出屏幕,CurrentStickyView即将被绘制出来
            if (topOffset <= 0) {
                if (curStickyView == null) {
                    curStickyView = v;
                }
            }
        }
        if (curStickyView != null) {
            // 悬浮框出现之前curStickyView一直为null, 出现之后不为null
            mStickyViewTopOffset = 0;
            mCurrentStickyView = curStickyView;
            post(mInvalidateRunnable);
        } else {
            mCurrentStickyView = null;
            removeCallbacks(mInvalidateRunnable);
        }
    }

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

    /**
     * sticky画出来
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        if (mCurrentStickyView != null) {
            //先保存起来
            canvas.save();
            //将坐标原点移动到(0, getScrollY() + mStickyViewTopOffset)
            canvas.translate(0, getScrollY() + mStickyViewTopOffset);
            // 绘制StickyView
            canvas.clipRect(0, mStickyViewTopOffset, mCurrentStickyView.getWidth(), mCurrentStickyView.getHeight());
            mCurrentStickyView.draw(canvas);
            // 绘制阴影
            if (mShadowDrawable != null) {
                int left = 0;
                int top = mCurrentStickyView.getHeight() + mStickyViewTopOffset;
                int right = mCurrentStickyView.getWidth();
                int bottom = top + (int) (density * defaultShadowHeight + 0.5f);
                mShadowDrawable.setBounds(left, top, right, bottom);
                mShadowDrawable.draw(canvas);
            }
            //重置坐标原点参数
            canvas.restore();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            redirectTouchToStickyView = true;
        }
        // 按下事件开始处理
        if (redirectTouchToStickyView) {
            // 头部布局是否为空
            redirectTouchToStickyView = mCurrentStickyView != null;
            // 判断是否点击的头部布局的范围
            if (redirectTouchToStickyView) {
                redirectTouchToStickyView = ev.getY() <= (mCurrentStickyView
                        .getHeight() + mStickyViewTopOffset)
                        && ev.getX() >= mCurrentStickyView.getLeft()
                        && ev.getX() <= mCurrentStickyView.getRight();
            }
        }
        if (redirectTouchToStickyView) {
            // 事件触摸位置设置到原StickyView的对应位置上
            ev.offsetLocation(0, -1 * ((getScrollY() + mStickyViewTopOffset) - mCurrentStickyView.getTop()));
        }
        return super.dispatchTouchEvent(ev);
    }

}
版权声明: 举报

相关文章推荐

Android 仿美团网,大众点评购买框悬浮效果之修改版

我之前写了一篇关于美团网,大众点评的购买框效果的文章Android对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果,我自己感觉效果并不是很好,如果快速滑动界面,显示悬浮框的时候会出现一...

仿美团app,浮动layout滑动到顶部悬停效果

今天在帖子上看到有人需要做一个类似美团app的一个效果,就是当一个浮动layout的滑动到顶部时,这个浮动layout就悬停下来,当屏幕往下滑动时,浮动layout也跟着往下移动。 因...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

安卓 仿美团网,大众点评购买框悬浮效果学习

先看下效果: 这种布局吸附效果在实际开发中很常见,也是比较合适的需求,如何来实现这个效果我们就要分析一下。 1.如图上所示,我们添加两个吸附布局,a,b其实这个两个布局是一样的 2.最外层vie...

Android 仿美团顶部滑动菜单

先来看下效果图:这是通过 ViewPager 和 GridView 相结合做出来的效果,每一个 ViewPager 页面都是一个 GridView,底部的每个滑动指示圆点都是从布局文件中 inflat...

仿美团详情滑动界面,并兼容NestedScroll嵌套

美团套餐详情的界面。(网上有用setOnTouchListener实现了此功能,但是不能支持多点滑动跟NestedScroll滑动嵌套) NestedScrollView: 有现成的setOnScr...

DropDownMenu仿美团等下拉菜单源码分析

前言最近项目中用到了,多条件可选搜索,因此用到了下拉菜单,在此用到了一个第三方控件,之所以将这个自定义控件贴出来,是感觉作者分析问题的能力很强,解决问题的方法

使用Jquery实现顶部导航栏在页面滑动到自身所在位置之后固定在顶部的效果

如题。         《1》         我们经常会实现一种效果,这种效果让页面内的导航条在页面向下拉动的过程中一直固定在某个位置。有时候在顶部,有时候在侧边。实现的方法非常简单,只需要通过...

header导航菜单固定

最近开发的一个网站头部分为上下两块,上面是快捷入口部分,下面是导航菜单部分。现在的需求是当页面往下拉时,快捷入口部分被遮住,而导航菜单固定,而且处于window最上面。在StackOverflow网站...

Android之仿美团TabLayout的简单使用

TabLayout的简单使用,代码少功能强大,可以直接拿来用、

文章标题

仿美团顶部左右滑动页实现这是本人第一次真正意义上的写技术博客。 目的呢,就是本着共享原则,将自己平时学到做出来的一些东西进行分享。 供大家一起学习交流。如有不足之处,请多多指教。 有哪里可以改进...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)