先看效果:

主要处理:

使用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. HashMap 和 HashTable 区别

    来源:http://www.importnew.com/7010.html HashMap和Hashtable的区别 HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚 ...

  2. python OptParse模块的用法详解

    OptParse模块的简单介绍 Python 有两个内建的模块用于处理命令行参数: 一个是 getopt只能简单处理 命令行参数: 另一个是 optparse,它功能强大,而且易于使用,可以方便地生成 ...

  3. docker volume创建、备份、nfs存储

    docker存储volume #环境 centos7.4 , Docker version 17.12.0-ce docker volume创建.备份.nfs存储 #docker volume 数据存 ...

  4. 自定义下拉刷新上拉加载View

    MainActivity.java package com.heima52.pullrefresh; import java.util.ArrayList; import com.heima52.pu ...

  5. IOS开发初体验

    IOS开发初体验 搭建开发环境 不多说什么了,开发环境的搭建太简单了,上App Store搜索XCode下载就行了,说多了都是眼泪 创建第一个IOS项目--HolleIOS 创建工程 选择工程创建位置 ...

  6. Weblogic 12c 负载均衡和session复制

    在上一篇,我们介绍了weblogic集群的部署和session的复制,如何将请求负载均衡到这个三个服务器上呢? 这里提供两种方式:(1)weblogic自带的proxy代理        (2) ng ...

  7. 【Java二十周年】Delphi转行java的一些小感触

    本文纯属一届小码农对java使用过程的体验感触 目录: 初遇java编程语言 与java的擦肩 深入java 跨平台性 开源支持 web的支撑 初遇java编程语言 刚上大学的时候,完全是个电脑盲.刚 ...

  8. android 网络获取json并且显示(2)

    1.将要的取得的json数据格式如下: 我们封装之前的类用google提供的JSONArray和JSONObject类对json字符串进行解析. 对于姚明显示每一条数据,我们封装了一个类如下: pub ...

  9. Java之String类型详解

    字符串的特点 A:字符串一旦被赋值,就不能改变. 注意:这里指的是字符串的内容不能改变,而不是引用不能改变. B:字面值作为字符串对象和通过构造方法创建对象的不同 String s = new Str ...

  10. [supervisor] 使用小记(入门教程)

    之前到现在很久没有用了,还是从安装说下,做个简单的实验,系统为Ubuntu14.04 快速安装配置 sudo pip_python install supervisor sudo echo_super ...