先看效果:

主要处理:

使用PullToRefreshScrollView修改内部的scrollView源码,更换成可以固定顶部的自定义scrollView

@Override
    protected ScrollView createRefreshableView(Context context, AttributeSet attrs) {
        ScrollView scrollView;
        if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
            //TODO  修改代码 添加滑动固定顶部标题sv
            scrollView = new InternalScrollViewSDK9(context, attrs);
//          scrollView = new FloatScrollView(context, attrs);
        } else {
            scrollView = new ScrollView(context, attrs);
        }

        scrollView.setId(R.id.scrollview);
        return scrollView;
    }

下面是scrollview的代码:

        public static final String FLOAT = "float";

        private ArrayList<View> stickyViews;
        private View currentlyStickingView;
        private float stickyViewTopOffset;
        private int stickyViewLeftOffset;
        private boolean redirectTouchesToStickyView;
        private boolean clippingToPadding;
        private boolean clipToPaddingHasBeenSet;

        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 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, android.view.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, android.view.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(), currentlyStickingView.getHeight());
                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) {
                topForViewRelativeOnlyChild = getTopForViewRelativeOnlyChild(currentlyStickingView);
                ev.offsetLocation(0, -1 * ((getScrollY() + stickyViewTopOffset) - topForViewRelativeOnlyChild));
            }
            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 || ev.getAction() == MotionEvent.ACTION_MOVE) {
                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();
        }

        private void doTheStickyThing() {
            View viewThatShouldStick = null;
            View approachingView = null;
            for (View v : stickyViews) {
                int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop());
                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 ? 0 : Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight());
                if (viewThatShouldStick != currentlyStickingView) {
                    if (currentlyStickingView != null) {
                        stopStickingCurrentlyStickingView();
                    }
                    stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick);
                    startStickingView(viewThatShouldStick);
                }
            } else if (currentlyStickingView != null) {
                stopStickingCurrentlyStickingView();
            }
        }

        private void startStickingView(View viewThatShouldStick) {
            currentlyStickingView = viewThatShouldStick;
        }

        private void stopStickingCurrentlyStickingView() {
            currentlyStickingView = null;
            removeCallbacks(invalidateRunnable);
        }

        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(FLOAT)) {
                        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(FLOAT)) {
                    stickyViews.add(v);
                }
            }
        }

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

完美滑动顶部固定ScrollView,合并可以上拉,下拉加载更多的更多相关文章

  1. Android Demo 下拉刷新+加载更多+滑动删除

    小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第 ...

  2. 【转】Android循环滚动广告条的完美实现,封装方便,平滑过渡,从网络加载图片,点击广告进入对应网址

    Android循环滚动广告条的完美实现,封装方便,平滑过渡,从网络加载图片,点击广告进入对应网址 关注finddreams,一起分享,一起进步: http://blog.csdn.net/finddr ...

  3. listview下拉刷新 上拉(滑动分页)加载更多

    最 近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多.新浪微博就是使用这种方式的典型.当用户从网络上读取微博的时候, ...

  4. RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  5. Android 实现下拉刷新和上拉加载更多的RECYCLERVIEW和SCROLLVIEW

    PullRefreshRecyclerView.java /** * 类说明:下拉刷新上拉加载更多的RecyclerView * Author: gaobaiq * Date: 2016/5/9 18 ...

  6. scroll-view组件实现下拉刷新, 拉到底加载更多

    官方文档已声明,即使在page.json和app.json中开启下拉刷新,scroll-view组件也是不支持的.但我们可以通过曲线救国的方法来实现 实现代码 // wxml <scroll-v ...

  7. 从微信小程序到鸿蒙js开发【13】——list加载更多&回到顶部

    鸿蒙入门指南,小白速来!从萌新到高手,怎样快速掌握鸿蒙开发?[课程入口] 目录: 1.list加载更多 2.list回到顶部 3.<从微信小程序到鸿蒙js开发>系列文章合集 1.list加 ...

  8. 微信小程序 scroll-view 完成上拉加载更多

    我们经常在软件客户端上看到这么一个功能,当我们阅读信息浏览到文章的末尾时,通常会加载出更多的信息.比如,我们在简书客户端上浏览推荐文章时,浏览到屏幕的末尾,此时又加载出了另一页的推荐文章,即实现了上拉 ...

  9. ScrollView嵌套ListView嵌套GridView的上下拉以及加载更多

    ScrollView 效果 ScrollView 说明 一个ScrollView 嵌套ListView 嵌套GridView的上拉加载更多,下拉刷新的demo. 主要是重写了GridView和Lsit ...

随机推荐

  1. MySQL注释中的sql也可能执行

    MySql支持三种注释形式:# 和–属于单行注释,注释范围为该行的结尾:/* */注释属于多行注释,此外该种注释还可以实现行内注释.具体的使用情况如下图中所示(四种使用情形): 除此之外,/* */这 ...

  2. 20160213.CCPP体系详解(0023天)

    程序片段(01):全排列.c 内容概要:全排列密码库 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <std ...

  3. springMVC源码分析--HttpRequestHandlerAdapter(四)

    上一篇博客springMVC源码分析--HandlerAdapter(一)中我们主要介绍了一下HandlerAdapter接口相关的内容,实现类及其在DispatcherServlet中执行的顺序,接 ...

  4. [Matlab]技巧笔记

    1.将字符串作为Matlab命令执行 md = 'dir'; eval(md); 2.将字符串作为系统命令执行 md = 'dir'; system(md); 3.使显示图像的坐标轴使用相同的度量单位 ...

  5. 【Netty源码学习】BootStrap

    BootStrap是客户端的启动类,其主要功能就是设置必要的参数然后启动客户端. 实现如下: Bootstrap b = new Bootstrap(); b.group(group) .channe ...

  6. Java中导出到Excel实现_aspose.cells

    参考http://183615215-qq-com.iteye.com/blog/1858208 包下载:http://pan.baidu.com/s/1o6ju0ZK,将lib的jar包导入到工程中 ...

  7. Python模块探秘 Smtplib发送带有各种附件的邮件

    这两天对Python的邮件模块比较感兴趣,于是就查了查资料.同时在实际的编码过程中也遇到了各种各样的问题.下面我就来分享一下我与smtplib的故事. 前提条件 我的上一篇博文里面讲解了,发送邮件必须 ...

  8. 14 fragment 创建

    静态展示 注意 静态的开始进入界面的生命周期和动态的不同 详情:14 fragment注意点 步骤一:创建一个类继承 Fragment 代码类型一: package com.fmy.demo1; im ...

  9. 2.6、Android Studio创建可伸缩的图片(9-patch文件)

    Draw 9-patch工具是一个所见即所得编辑器,允许你创建可以自动改变大小来适应视图的内容和屏幕的大小. 以下是使用Draw 9-path工具快速创建一个NinePatch图片. 1. 在命令行中 ...

  10. 财务模块多组织,GL, SLA, SOB, COA, BSV, CCID, LE 概念的简单介绍

     GL=  General Ledger 指的是Oracle 的总帐系统. application_id = 101. 在uk似乎居然还有不同的解释(In the UK, it was refer ...