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

原创 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);
    }

}

相关文章推荐

仿美团APP的底部滑动菜单实现

仿美团APP的底部滑动菜单

高仿美团app,浮动layout滑动到顶部

返回博客列表 原 高仿美团app,浮动layout滑动到顶部悬停效果   谁带我去看看世界 发布时间: 2015/06/16 17:41 阅读: 1867 收藏: 29...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

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

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

仿美团头部筛选效果

  • 2017年07月12日 17:26
  • 17.26MB
  • 下载

类似appcan仿美团头部下拉菜单

  • 2015年12月01日 12:28
  • 150KB
  • 下载

android_如何巧妙在Listview滑动时将头部固定

ListView增加头部,并且该头部在随着ListView滑动时需要固定,下拉刷新采用的是android5的SwipeRefresh。 实现方案: 在顶部增加一个跟ListView头部一模一样 在Li...

固定头部滑动导航

  • 2015年10月16日 17:09
  • 5KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:仿美团滑动后头部固定源码分析
举报原因:
原因补充:

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