基于NestedScrolling机制实现下拉刷新 overScroll 等

新版本

Refreshlayout Adapter Statelayout

github地址

Refreshlayout

由于是继续nestedscrolling ,只支持像recycleview nestedscrollview等子view

刷新库部分包含以下功能:
1.普通上拉刷新,下拉加载
2.类似小米系统的橡皮泥模式 elastic_overscroll
3.overscroll类似iphone的橡皮泥模式 overscroll
4.估值模式,只提供上下拉过程中的数值,可监听设置listener做你想要的事情 evaluate
5.估值模式下的内刷新,与普通刷新相比,它是控制adapter最前面一个和最后面一个的高度来显示刷新头尾(有些是互斥的不要都配置)


GIF.gif

GIF2.gif

GIF3.gif
 <coms.kxjsj.refreshlayout_master.RefreshLayout
        android:id="@+id/Refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:canFooter="true"
        app:footerID="@layout/footer_layout_horizontal"
        app:headerID="@layout/header_layout_horizontal"
        app:scrollID="@layout/xx" />

多类型Adapter使用

adpter包含以下主要功能:
1.多类型item的支持 通过addtype
2.不同模式下列宽的控制
3.只设置position 的,估值模式
4.增量更新集成
5.复杂数据根据泛型自动匹配类型,也可重写istype自定义什么情况下是该类型
6.移除了状态布局的支持
[图片上传失败...(image-e1beda-1518149122575)]

默认根据itemholder的泛型确定相应position的类型
[图片上传失败...(image-a5035a-1518149122575)]

状态布局的封装

原adapter的状态布局单独做成一个statlayout,以增加对非recyclerview的支持,用法与之前一样
[图片上传失败...(image-120154-1518149122575)]

更多功能

itemholder 重写相应方法可达到gridlayoutManager staggled设置列宽

  public abstract class ItemHolder<T> {
    private int layout;
    /**
     * StaggeredLayoutManager重写此方法
     *
     * @return 是否占据一个
     */
    public boolean isfull() {
        return false;
    }

    /**
     * GrideLayoutManager重写此方法
     *
     * @param position
     * @return 占的个数
     */
    public int gridSpanSize(T item, int position) {
        return 1;
    }

    /**
     * onBind时调用
     *
     * @param holder
     * @param item
     * @param position
     */
    public abstract void onBind(Holder holder, T item, int position);

    /**
     * 是否是这种Type的view
     *
     * @param item
     * @param position
     * @return
     */
    public boolean istype(Object item, int position){
        return true;
    }

    public int getLayout() {
        return layout;
    }

    public ItemHolder<T> setLayout(int layout) {
        this.layout = layout;
        return this;
    }
}



---




------------------------------------下面过时-------------------------------------------------




#### 基于NestScroll机制实现下拉刷新 overScroll 等
# [最新库简书说明传送门](http://www.jianshu.com/p/88795dff987c)
# [最新库 github传送门](https://github.com/While1true/NestPullView)

[GitHub传送门](https://github.com/While1true/-NestedScrolling-overScroll-.git)
[AppSample](http://pan.baidu.com/s/1gfxM40N)
---
前言:为什么网上这种轮子这么多了,还要造轮子呢?

产品经理:能不能想ios那样,不要滑到低了就划不动了? 需要OverScroll

产品经理:能不能在顶部时往下拉 头部变大 需要视差效果 就是我下面说的估值模式

产品经理: 在顶部时下拉头部变大,底部时,上拉加载

产品经理:上拉加载体验不好,能不能预加载,还没滑到底部时就开始加载,这样感觉很流畅

> 网上轮子虽多,但不是自己造的改起来特麻烦,也不能需要一个功能就去集成一个库吧,

---
看看如何造一个轮子满足以上要求

先看看实际项目效果

![2017-07-11-09-34-05.gif](http://upload-images.jianshu.io/upload_images/6456519-05d86e83e5518835.gif?imageMogr2/auto-orient/strip)


![2017-07-11-09-39-40.gif](http://upload-images.jianshu.io/upload_images/6456519-dc7aecd8f6b0d28a.gif?imageMogr2/auto-orient/strip)


![2017-07-11-09-41-25.gif](http://upload-images.jianshu.io/upload_images/6456519-eedeb9c8d1b63d14.gif?imageMogr2/auto-orient/strip)


---

1.实现的View(只支持竖直的方向):
- SRecyclerview:对Recyclerview的包装
- SScrollView:对ScrollView的包装
- SAllView: 理论支持,所有实现了NestScrollChild的View    daemo 以NestScrollWebView为例

###### xml配置
- SRecyclerView

<com.example.myapplication.View.SRecyclerView
android:background="#f0f0f0"
android:id="@+id/srecyclerview"
android:layout_height="match_parent"
android:layout_width="match_parent">

</com.example.myapplication.View.SRecyclerView>
- SScrollView 同ScrollView
- SAllView  NestedScrollWebView为例

<com.example.myapplication.View.SAllView
android:id="@+id/sallview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.myapplication.View.NestedScrollWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.example.myapplication.View.SAllView>



##### 1.我是如何使用
参数说明

srecyclerview //默认头尾布局
.addDefaultHeaderFooter()
//添加自定义头部
.addHeader(header, 100)
//添加自定义尾部
.addFooter(footer, 50)
//张力比例 默认为3
.setPullRate(3)
//若需要预加载,就是距离倒数第几个item开始加载
.setPreLoadingCount(3)
//set Layoutmanage Adapter
.setAdapter(new GridLayoutManager(this, 2), adapter)
//是否可下拉 是否可上拉 是否要调用下拉加载 是否要调用上拉加载
//boolean head, boolean foot, boolean canLoadingHeader, boolean canloadingFooter
.setRefreshMode(true, true, false, false)
//估值模式:是否真实移动 头部 尾部 false下只提供估值 .setActrullyScrollMode(false, false)
.setRefreshingListener(new SRecyclerView.OnRefreshListener() {
//下拉值 值是负数
@Override
public void pullDown(int height) {
super.pullDown(height);
ic.getLayoutParams().height = ic_origin_height - height;
ic.requestLayout();
}
//上拉值 正数
@Override
public void pullUp(int height) {
super.pullUp(height);
}
//上拉刷新时调用
@Override
public void Loading() {
super.Loading();
}
//预加载时调用
@Override
public void PreLoading() {
super.PreLoading();
}
//下拉刷新时调用
@Override
public void Refreshing() {

                        }
                    });

#### 2.如何集成到你的项目,该如何弄
> 头布局和尾布局换成你的就行了,为什么不集成各种默认的头布局,封装?一是懒,二是实际项目中封装再多也不一定有你要的,没必要做那么多无用
1. 先看看我的默认实现

1.  纯代码写的,android的代码中确实不好写布局
 也有单独代码调用的 addheader addFooter方法

--当然你可以写在xml中写,然后用LayoutInfinite来加载头部尾部View
1. 然后headLayout.add你的头布局  this.headerHeight=头布局高度 --headerHeight有用来作为加载停留的位置
然后headLayout.getlayotparams.topMargin = -headerHeight;将头布局隐藏
1. footLayout.add你的尾布局 this.footerHeight=尾布局高度
1. 动画的实现:请参考代码中默认的headerprogress;headTitle的实现 

public SRecyclerView addDefaultHeaderFooter() {
    isusingDefault = true;
    this.headerHeight = dp2px(65);
    RelativeLayout relativeLayout = new RelativeLayout(getContext());
    RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    params1.addRule(RelativeLayout.CENTER_IN_PARENT);
    relativeLayout.setLayoutParams(params1);
    ImageView imageView = new ImageView(getContext());
    imageView.setImageResource(R.drawable.ptr_background);

// imageView.setImageBitmap(BitmapFactory.decodeByteArray(bg, 0, bg.length));
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
RelativeLayout.LayoutParams paramsimageView = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
paramsimageView.addRule(RelativeLayout.CENTER_HORIZONTAL);
imageView.setId(12);
imageView.setPadding(0, dp2px(12), 0, 0);
imageView.setLayoutParams(paramsimageView);
relativeLayout.addView(imageView);

    LinearLayout linearLayout1 = new LinearLayout(getContext());
    RelativeLayout.LayoutParams linearLayout1params1 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    linearLayout1params1.addRule(RelativeLayout.BELOW, 12);
    linearLayout1params1.addRule(RelativeLayout.CENTER_HORIZONTAL);
    linearLayout1.setLayoutParams(linearLayout1params1);


    headerprogress = new ImageView(getContext());

// headerprogress.setImageBitmap(BitmapFactory.decodeByteArray(pro, 0, pro.length));
headerprogress.setImageResource(R.drawable.ptr_loading);

    headTitle = new TextView(getContext());
    headTitle.setText("下拉刷新");
    LayoutParams headTitleparams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    headTitleparams.gravity = Gravity.CENTER_VERTICAL;
    headTitle.setPadding(dp2px(5), 0, 0, 0);
    headTitle.setLayoutParams(headTitleparams);

    linearLayout1.addView(headerprogress);
    linearLayout1.addView(headTitle);

    relativeLayout.addView(linearLayout1);

    headLayout.removeAllViews();
    LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, headerHeight);
    params2.gravity = Gravity.CENTER_VERTICAL;
    headLayout.setOrientation(HORIZONTAL);
    params2.topMargin = -headerHeight;
    headLayout.setLayoutParams(params2);
    headLayout.addView(relativeLayout);


    this.footHeight = dp2px(45);
    footLayout.removeAllViews();
    LinearLayout linearLayout2 = new LinearLayout(getContext());
    linearLayout2.setOrientation(HORIZONTAL);
    LayoutParams layoutParams2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, footHeight);
    layoutParams2.gravity = Gravity.CENTER_VERTICAL;
    linearLayout2.setLayoutParams(layoutParams2);
    ProgressBar progressBar = new ProgressBar(getContext());
    LayoutParams params3 = new LayoutParams(dp2px(30), dp2px(30));
    params3.gravity = Gravity.CENTER_VERTICAL;
    progressBar.setLayoutParams(params3);
    Drawable drawable = getResources().getDrawable(R.drawable.ptr_loading);
    drawable.setBounds(0, 0, dp2px(30), dp2px(30));
    progressBar.setProgressDrawable(drawable);

    TextView footText = new TextView(getContext());
    footText.setText("正在加载...");
    LayoutParams params4 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    params4.gravity = Gravity.CENTER_VERTICAL;
    footText.setLayoutParams(params4);

    linearLayout2.addView(progressBar);
    linearLayout2.addView(footText);
    footLayout.addView(linearLayout2);
    LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, footHeight);
    layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
    footLayout.setLayoutParams(layoutParams);

    return this;
}

#### 3.原理 NestedScrolling机制
[思路来源参考自马云飞博客打造独一无二的下拉刷新](http://blog.csdn.net/sw950729)
根据他的做了自己的实现,大家可以去查看详细的原理说明。

overscroll的实现:就是空的头尾布局,并去掉加载停留阶段

预加载:大家不想要我这个View的也可单独把这段拿去自己的RecyclerView上用

更多细节使用请参考demo

myRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);

                RefreshLoading(recyclerView, count);
        }
    });


//count:倒数几个开始加载
private void RefreshLoading(RecyclerView recyclerView, int count) {
if (isLoading || prenomore) {
return;
}
int lastPosition = -1;

    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    if (layoutManager instanceof StaggeredGridLayoutManager) {
        //因为StaggeredGridLayoutManager的特殊性可能导致最后显示的item存在多个,所以这里取到的是一个数组
        //得到这个数组后再取到数组中position值最大的那个就是最后显示的position值了
        int[] lastPositions = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
        ((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(lastPositions);
        lastPosition = findMax(lastPositions);
    } else if (layoutManager instanceof LinearLayoutManager) {
        lastPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
    } else if (layoutManager instanceof GridLayoutManager) {
        //通过LayoutManager找到当前显示的最后的item的position
        lastPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
    }

    //内容数量很少无需要预加载
    if (recyclerView.getLayoutManager().getItemCount() - count < 0) {
        return;
    }
    if (lastPosition >= recyclerView.getLayoutManager().getItemCount() - count) {
        if (!isLoading) {
            isLoading = true;
            listener.PreLoading();
        }
    }

}

//找到数组中的最大值
private int findMax(int[] lastPositions) {
    int max = lastPositions[0];
    for (int value : lastPositions) {
        if (value > max) {
            max = value;
        }
    }
    return max;
}
#### 4.其他
大家也看到demo中少了 2 和4两个选项。本来还有个Fling的实现,由于有少许bug,临时删掉了。但在SScrollview中有保留
大家感兴趣的可以查看。其他用法基本和SRecyclerview一样

sscrollview.setRefreshMode(true,true,false,false)
//fling 头部是否出来 尾部是否出来 是否加载
//boolean overscrollhead, boolean overscrollfoot, boolean overloadingheader, boolean overloadingfooter
.setOverScrollEnable(true,true,true,true);

####总结
> 我们做了什么:
1.RecyclerVire ScrollView,WebView或者任何NestedScrollingChild的OverScroll 下拉加载 ,估值模式下根据数值做任何你想做的,可参看上面实际项目的图片,[以及DEMO](http://pan.baidu.com/s/1gfxM40N)  ——————— [ githu代码](https://github.com/While1true/JSSample/tree/master)Sample3目录下
# [ 最新库简书说明传送门](http://www.jianshu.com/p/88795dff987c)
# [最新库 github传送门](https://github.com/While1true/NestPullView)


[累了来听首歌--咏梅](https://changba.com/s/VxmBhNm_g7_SohfNT4TsMQ?&code=RkvQSz26kloiq37EELKi5jfO_iIrZXqjqcgQ1_FoPj_bUJnu-s0jIMTHc3rAO8C9RRlOS2KAxvm13fMb5yk6GGraA4Xc7RJTcZEMgiGcARc)


——
aa
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,617评论 4 59
  • 窗外有一个影子 一个孤单的影子 静静地站在那里 尽管秋风瑟瑟 围墙边竹影摇曳 那影子一动不动 丝毫也没有离去的样子...
    罗启洪阅读 192评论 0 1
  • 每天一定不能只有学习,没有娱乐,娱乐是给自己动力继续前进的。 词根100.前后缀等 赚钱 国珍,练字
    遇荐静心阅读 86评论 0 0
  • 寒假的时候为了更好地提高自己的学习能力和督促自己,我不断得查找和翻阅了很多订阅号,想着借助一些软件或许可以有点帮助...
    vinki阅读 421评论 0 2