下拉刷新框架SpringView的使用

SpringView

Github

android开发游记:SpringView 下拉刷新的高效解决方案,定制你自己风格的拖拽页面

SpringView 是一个提供了上下拖拽的功能组件,能够进行高度自定义,实现各种下拉\上拉动画效果,demo里实现了:仿阿里旅行、仿美团,仿QQ下拉刷红包,仿acfun等,完全兼容源生控件如ListView、RecyclerView、ScrollView、WebView等,使用简单,轻易定制自己风格的拖拽页面。

SpringView 单独将头部/尾部独立出来,几乎可以实现任何你想要的效果,只需要继承BaseHeader(或Footer)实现接口

SpringView 能在运行时动态地替换头部/尾部,只需要设置不同的头尾即可:springView.setHeader(MyHeader());

SpringView 支持多点触控,可以两只手连续拖拽,你可以定制一些非常有趣的效果(例如demo5)

SpringView 提供了2种拖拽方式(重叠和跟随),可以动态地切换

SpringView 为不想去自定义头/尾的懒人提供了7种默认的实现(模仿了阿里,腾讯,美团等多种风格)如下,还会继续增加

SpringView 支持和 AppBarLayout 联动

如何使用 SpringView

依赖

dependencies {

   //SpringView核心库 (只包含DefaultHeader/Footer)
   implementation 'com.liaoinstan.springview:library:1.7.0'

   //以下是各个风格的Header/Footer,选择自己喜欢的引入
   implementation 'com.liaoinstan.springview:AcfunHeader:1.7.0'         //AcFun风格 (header and footer)
   implementation 'com.liaoinstan.springview:AliHeader:1.7.0'           //阿里旅行风格 (header and footer)
   implementation 'com.liaoinstan.springview:MeituanHeader:1.7.0'       //美团风格 (header and footer)
   implementation 'com.liaoinstan.springview:RotationHeader:1.7.0'      //齿轮机械风格 (header and footer)
   implementation 'com.liaoinstan.springview:WeixinHeader:1.7.0'        //微信小程序header(只有header)
   implementation 'com.liaoinstan.springview:DuHeader:1.7.0'            //'毒'App header(只有header)
}

在布局文件中添加SpringView,注意SpringView和ScrollView有同样的限制:只能有一个子元素:

<com.liaoinstan.springview.widget.SpringView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:header="@layout/myheader"
            app:footer="@layout/myfooter">

            <ListView RecyclerView ScrollView or others
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>

    </com.liaoinstan.springview.widget.SpringView>

当然,你也可以不在布局中设置header\footer,使用代码动态添加:

springView.setHeader(new DefaultHeader(this));
springView.setFooter(new DefaultFooter(this));

添加监听

springView.setListener(new SpringView.OnFreshListener() {
      @Override
      public void onRefresh() {
      }
      @Override
      public void onLoadmore() {
      }
});

基本使用:配合RecyclerView和默认头部和底部DefaultHeader,DefaultFooter

<?xml version="1.0" encoding="utf-8"?>
<com.liaoinstan.springview.widget.SpringView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/springView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".my.MyDemo1Activity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager">

    </androidx.recyclerview.widget.RecyclerView>


</com.liaoinstan.springview.widget.SpringView>
public class MyDemo1Activity extends AppCompatActivity {

    private SpringView mSpringView;

    private RecyclerView mRecyclerView;

    private List<String> mDatas = new ArrayList<>();

    private RvAdapter mRvAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_demo1);

        mSpringView = (SpringView) findViewById(R.id.springView);
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);

        //拖拽类型
        //OVERLAP 重叠
        //FOLLOW  跟随
        //DRAG    拖拽
        //SCROLL  滚动
        mSpringView.setType(SpringView.Type.FOLLOW);

        //设置header/footer
        mSpringView.setHeader(new DefaultHeader(this));
        mSpringView.setFooter(new DefaultFooter(this));


        mRvAdapter = new RvAdapter(this, mDatas);
        mRecyclerView.setAdapter(mRvAdapter);

        loadData();

        mSpringView.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(() -> {
                    loadData();
                    Toast.makeText(MyDemo1Activity.this, "下拉刷新", Toast.LENGTH_SHORT).show();
                    mSpringView.onFinishFreshAndLoad();
                }, 1000);
            }

            @Override
            public void onLoadmore() {

                new Handler().postDelayed(() -> {
                    loadMore();
                    Toast.makeText(MyDemo1Activity.this, "上拉加载", Toast.LENGTH_SHORT).show();
                    mSpringView.onFinishFreshAndLoad();
                }, 1000);
            }
        });

    }

    private void loadData() {
        mDatas.clear();
        for (int i = 1; i <= 30; i++) {
            mDatas.add("赵丽颖" + i);
        }
        mRvAdapter.notifyDataSetChanged();
    }

    private void loadMore() {
        for (int i = 1; i <= 10; i++) {
            mDatas.add("赵丽颖更多" + i);
        }
        mRvAdapter.notifyDataSetChanged();
    }
}

在ScrollView中使用:可以自定义头部和底部布局文件

<?xml version="1.0" encoding="utf-8"?>
<com.liaoinstan.springview.widget.SpringView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/springView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:footer="@layout/default_footer"
    app:header="@layout/default_header">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:background="#68b3f3"
                android:gravity="center"
                android:text="TextView1"
                android:textColor="#ffffff" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:background="#ff0"
                android:gravity="center"
                android:text="TextView2"
                android:textColor="#ffffff" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:background="#0f0"
                android:gravity="center"
                android:text="TextView3"
                android:textColor="#ffffff" />


        </LinearLayout>

    </androidx.core.widget.NestedScrollView>


</com.liaoinstan.springview.widget.SpringView>

public class MyDemo2Activity extends AppCompatActivity {

    private SpringView mSpringView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_demo2);

        mSpringView = (SpringView) findViewById(R.id.springView);

        mSpringView.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(() -> {
                    Toast.makeText(MyDemo2Activity.this, "下拉刷新", Toast.LENGTH_SHORT).show();
                    mSpringView.onFinishFreshAndLoad();
                }, 2000);
            }

            @Override
            public void onLoadmore() {

                new Handler().postDelayed(() -> {
                    Toast.makeText(MyDemo2Activity.this, "上拉加载", Toast.LENGTH_SHORT).show();
                    mSpringView.onFinishFreshAndLoad();
                }, 2000);
            }
        });
    }
}

在ListView中使用:配合齿轮机械风格头部和底部

       <com.liaoinstan.springview.widget.SpringView
            android:id="@+id/springview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff">

            <ListView
                android:id="@+id/list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#f9f9f9"
                android:divider="@null" />

        </com.liaoinstan.springview.widget.SpringView>

RotationHeader:齿轮机械风格

springView.setHeader(new RotationHeader());
springView.setFooter(new RotationFooter());

在RecyclerView中使用:配合阿里旅行风格头部和底部

        <com.liaoinstan.springview.widget.SpringView
            android:id="@+id/springview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff">

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycle"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#ffffff"
                android:scrollbars="vertical" />

        </com.liaoinstan.springview.widget.SpringView>

AliHeader:阿里旅行风格

  springView.setHeader(new AliHeader(this, R.drawable.ali, true));   //参数为:logo图片资源,是否显示文字
  springView.setFooter(new AliFooter(this, false));

在WebView中使用:自定义头部布局文件

       <com.liaoinstan.springview.widget.SpringView
            android:id="@+id/springview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#797a7d"
            app:header="@layout/header_web"
            app:type="overlap">

            <WebView
                android:id="@+id/webView"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

        </com.liaoinstan.springview.widget.SpringView>

header_web.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="top|center_horizontal">

    <LinearLayout
        android:orientation="vertical"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="网页由 github.com 提供"
            android:id="@+id/textView2"
            android:textColor="#b2b2b2"
            android:textSize="12sp"
            android:layout_gravity="center_horizontal" />

        <TextView
            android:layout_marginTop="5dp"
            android:layout_width="match_parent"
            android:gravity="center"
            android:layout_height="wrap_content"
            android:textColor="#b2b2b2"
            android:text="已启用QQ浏览器X5内核"
            android:textSize="12sp"
            android:id="@+id/textView3"
            android:layout_gravity="center_horizontal" />
    </LinearLayout>
</LinearLayout>

自己编写的头部和底部的布局

  <com.liaoinstan.springview.widget.SpringView
        android:id="@+id/springView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:footer="@layout/my_footer"
        app:header="@layout/my_header">
  </androidx.core.widget.NestedScrollView>

my_header

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="70dp">

    <ProgressBar
        android:id="@+id/default_header_progressbar"
        android:layout_width="30dp"
        android:layout_height="30dp" />

    <TextView
        android:id="@+id/default_header_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="下拉刷新"
        android:textColor="#777777" />

</LinearLayout>

my_footer

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:orientation="horizontal"
    android:gravity="center"
    android:layout_height="50dp">

        <ProgressBar
            android:id="@+id/default_footer_progressbar"
            android:layout_width="30dp"
            android:layout_height="30dp" />

        <TextView
            android:id="@+id/default_footer_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#777777"
            android:text="加载更多" />

</LinearLayout>

AcfunHeader:AcFun风格

springView.setHeader(new AcFunHeader(this, R.drawable.acfun_header));
springView.setFooter(new AcFunFooter(this, R.drawable.acfun_footer));

Drag Header

简单定制的QQ新年刷红包效果,可以在此基础上自己增加动画特效,这里只是模拟出该效果框架进行演示,故该Header不放在library里面。

具体使用看官方案例。

public class Demo6Activity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {

    private SpringView springView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo6);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ((RadioGroup) findViewById(R.id.group_header)).setOnCheckedChangeListener(this);

        springView = findViewById(R.id.springview);
        springView.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                //如果当前设置的头部是QQHeader,则不finish
                if (springView.getHeader() instanceof QQHeader) return;
                new Handler().postDelayed(() -> springView.onFinishFreshAndLoad(), 1000);
            }

            @Override
            public void onLoadmore() {
                new Handler().postDelayed(() -> springView.onFinishFreshAndLoad(), 1000);
            }
        });
        springView.setHeader(new QQHeader().setMovePara(1.5f));     //设置拖拽系数(值越大,移动越慢)
        springView.setFooter(new DefaultFooter(this, R.drawable.progress_small));
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        switch (checkedId) {
            case R.id.drag_header:
                springView.setHeader(new QQHeader());
                break;
            case R.id.nomal_header:
                springView.setHeader(new DefaultHeader(this));
                break;
        }
    }
}

MeituanHeader,MeituanFooter:美团风格

public class Demo7Activity extends AppCompatActivity {

    private SpringView springView;

    //下拉过程动画
    private int[] pullAnimSrcs = new int[]{R.drawable.mt_pull, R.drawable.mt_pull01, R.drawable.mt_pull02, R.drawable.mt_pull03, R.drawable.mt_pull04, R.drawable.mt_pull05};
    //刷新中动画
    private int[] refreshAnimSrcs = new int[]{R.drawable.mt_refreshing01, R.drawable.mt_refreshing02, R.drawable.mt_refreshing03, R.drawable.mt_refreshing04, R.drawable.mt_refreshing05, R.drawable.mt_refreshing06};
    //加载更多底部动画
    private int[] loadingAnimSrcs = new int[]{R.drawable.mt_loading01, R.drawable.mt_loading02};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo7);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        springView = findViewById(R.id.springview);
        springView.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(() -> springView.onFinishFreshAndLoad(), 2000);
            }

            @Override
            public void onLoadmore() {
                new Handler().postDelayed(() -> springView.onFinishFreshAndLoad(), 2000);
            }
        });
        springView.setHeader(new MeituanHeader(this, pullAnimSrcs, refreshAnimSrcs));
        springView.setFooter(new MeituanFooter(this, loadingAnimSrcs));
    }
}

SpringView不会和水平滑动有冲突,侧滑删除试试


        RecyclerView recyclerView = findViewById(R.id.recycle);
        recyclerView.setHasFixedSize(true);
        RecyclerAdapter recyclerAdapter = new RecyclerAdapter(mDatas);
        recyclerView.setAdapter(recyclerAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new MyItemTouchCallback(recyclerAdapter));
        itemTouchHelper.attachToRecyclerView(recyclerView);

具体使用看官方案例。

TabLayout+ViewPager+Fragment+CoordinatorLayout+CollapsingToolbarLayout

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".demo9.Demo9Activity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="250dp"
                android:scaleType="centerCrop"
                android:src="@drawable/bk_test"
                app:layout_collapseMode="parallax" />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay"
                app:title="Demo9Activity" />

        </com.google.android.material.appbar.CollapsingToolbarLayout>

    </com.google.android.material.appbar.AppBarLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tab"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:tabIndicatorColor="#5793e6"
            app:tabIndicatorHeight="1dp"
            app:tabSelectedTextColor="#5793e6"
            app:tabTextColor="#665793e6"
            tools:background="#33ff0000" />

        <!--app:tabTextAppearance="@style/TabLayoutTextStyle"-->

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/pager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />

    </LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

具体使用看官方案例。

给header和footer设置为DRAG模式

//给header和footer设置为DRAG模式
springView.setHeader(new MeituanHeader(this, pullAnimSrcs, refreshAnimSrcs).setType(SpringView.Type.DRAG));
springView.setFooter(new MeituanFooter(this, loadingAnimSrcs).setType(SpringView.Type.DRAG));
image.png

SpringView 现在支持在内部嵌套布局了(在下拉的头部中嵌套一些布局)

具体使用看官方案例。

实现类似于微信下拉 拉出小程序列表

具体使用看官方案例。

SpringView新增了SCROLL模式,基于这种模式可以实现自动加载等效果,下拉到底部实现自动加载

具体使用看官方案例。

springView.setHeader(new AliHeader(this));
springView.setFooter(new AutoFooter());

DuHeader风格

下拉刷新后弹出:为你更新20条新内容。

image.png
    <com.liaoinstan.springview.duheader.TopBarFrameLayout
        android:id="@+id/top_bar_frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <com.liaoinstan.springview.widget.SpringView
            android:id="@+id/springview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffffff">

            <ScrollView
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/text"
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ffffff"
                        android:gravity="center"
                        android:text="We are in ScrollView"
                        android:textColor="#cccccc" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ECECF0"
                        android:gravity="center"
                        android:text="这是一个仿'毒'APP的效果"
                        android:textColor="#333333"
                        android:textSize="12sp" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ffffff" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ECECF0" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ffffff" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ECECF0" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ffffff" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="200dp"
                        android:background="#ECECF0" />

                </LinearLayout>
            </ScrollView>

        </com.liaoinstan.springview.widget.SpringView>

    </com.liaoinstan.springview.duheader.TopBarFrameLayout>
       topBarFrameLayout = findViewById(R.id.top_bar_frame_layout);
        springView = findViewById(R.id.springview);
        springView.setListener(new SpringView.OnFreshListener() {
            @Override
            public void onRefresh() {
                new Handler().postDelayed(() -> {
                    //0.5秒后再结束header刷新动画(模仿'毒'的延迟,大概0.5秒左右)
                    springView.onFinishFreshAndLoadDelay(500);
                    //开始展开topBar顶部提示,并在2.5秒回自动收回
                    topBarFrameLayout.setTopBarText("为你更新20条新内容");
                    topBarFrameLayout.showAndHideDelay(2500);
                }, 2000);
            }

            @Override
            public void onLoadmore() {
                new Handler().postDelayed(() -> springView.onFinishFreshAndLoad(), 2000);
            }
        });
        springView.setHeader(new DuHeader());

具体使用看官方案例。

如何自定义一个Header或Footer

新建一个MyHeader基础自BaseHeader:

public class MyHeader extends BaseHeader {

    private TextView textView;

    private int i = 0;

    /**
     * 获取Header
     *
     * @param inflater
     * @param viewGroup
     * @return
     */
    @Override
    public View getView(LayoutInflater inflater, ViewGroup viewGroup) {
        View view = inflater.inflate(R.layout.header_my, viewGroup, true);
        textView = (TextView) view.findViewById(R.id.textView);
        return view;
    }

    /**
     * 即将开始拖拽时的回调,可进行初始化操作
     */

    @Override
    public void onPreDrag(View rootView) {
        super.onPreDrag(rootView);
    }


    /**
     * 手指拖拽过程中不断回调,dy为拖拽的距离,可以根据拖动的距离添加拖动过程动画
     *
     * @param rootView
     * @param dy       拖动距离,下拉为+,上拉为-
     */
    @Override
    public void onDropAnim(View rootView, int dy) {

    }

    /**
     * 手指拖拽过程中每次经过临界点时回调,upORdown是向上经过还是向下经过
     *
     * @param rootView
     * @param upORdown 是上拉还是下拉 true(上),false(下)
     */
    @Override
    public void onLimitDes(View rootView, boolean upORdown) {
        //实现onLimitDes方法,在每次经过临界点时改变TextView的内容:
        i++;
        textView.setText("松开刷新" + i);
    }

    /**
     * 拉动超过临界点后松开时回调
     */
    @Override
    public void onStartAnim() {
        textView.setText("正在刷新");
    }

    /**
     * 头部已经全部弹回时回调
     */
    @Override
    public void onFinishAnim() {
        textView.setText("下拉刷新");
    }

}

mSpringView.setHeader(new MyHeader());

这样就完成了一个简单的自定义Header,Footer同理。

自定义头部Gif图片

public class GifHeader extends BaseHeader {

    private GifDrawable mGifDrawable;

    private ViewGroup.LayoutParams mLp;

    private int mLoadingW = 0, mLoadingH = 0;

    private GifImageView mGifImageView;

    private Context mContext;

    public GifHeader(Context context) {
        mContext = context;
    }

    /**
     * 获取Header
     *
     * @param inflater
     * @param viewGroup
     * @return
     */
    @Override
    public View getView(LayoutInflater inflater, ViewGroup viewGroup) {
        View view = inflater.inflate(R.layout.gif_header, viewGroup, true);
        mGifImageView = view.findViewById(R.id.gif_second);

        mGifDrawable = (GifDrawable) mGifImageView.getDrawable();

        mLoadingW = dip2px(mContext, 238f);
        mLoadingH = dip2px(mContext, 120f);
        mLp = mGifImageView.getLayoutParams();

        return view;
    }

    /**
     * 即将开始拖拽时的回调,可进行初始化操作
     */

    @Override
    public void onPreDrag(View rootView) {
        super.onPreDrag(rootView);
        mGifDrawable.stop();
    }


    /**
     * 手指拖拽过程中不断回调,dy为拖拽的距离,可以根据拖动的距离添加拖动过程动画
     *
     * @param rootView
     * @param dy       拖动距离,下拉为+,上拉为-
     */
    @Override
    public void onDropAnim(View rootView, int dy) {
        if (dy > 238f) {
            changeLoadingWH(1);
        } else if (dy <= 238f) {
            changeLoadingWH(dy / 238f);
        }
    }

    /**
     * 手指拖拽过程中每次经过临界点时回调,upORdown是向上经过还是向下经过
     * 实现onLimitDes方法,在每次经过临界点时改变TextView的内容:
     *
     * @param rootView
     * @param upORdown 是上拉还是下拉 true(上),false(下)
     */
    @Override
    public void onLimitDes(View rootView, boolean upORdown) {

    }

    /**
     * 拉动超过临界点后松开时回调
     */
    @Override
    public void onStartAnim() {
        mGifDrawable.start();
    }

    /**
     * 头部已经全部弹回时回调
     */
    @Override
    public void onFinishAnim() {
        mGifDrawable.reset();
        mGifDrawable.stop();
    }

    /**
     * 这个方法用于设置当前View的临界高度(limit hight),即拉动到多少会被认定为刷新超作,而没到达该高度则不会执行刷新
     * 返回值大于0才有效,如果<=0 则设置为默认header的高度
     * 默认返回0
     */
    @Override
    public int getDragLimitHeight(View rootView) {
        return 200;
    }

    /**
     * 这个方法用于设置下拉最大高度(max height),无论怎么拉动都不会超过这个高度
     * 返回值大于0才有效,如果<=0 则默认600px
     * 默认返回0
     */
    @Override
    public int getDragMaxHeight(View rootView) {
        return 1000;
    }

    /**
     * 这个方法用于设置下拉弹动高度(spring height),即弹动后停止状态的高度
     * 返回值大于0才有效,如果<=0 则设置为默认header的高度
     * 默认返回0
     */
    @Override
    public int getDragSpringHeight(View rootView) {
        return 450;
    }

    private void changeLoadingWH(float fraction) {
        mLp.width = (int) (mLoadingW * fraction);
        mLp.height = (int) (mLoadingH * fraction);
        mGifImageView.setLayoutParams(mLp);
    }


    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="horizontal"
    tools:ignore="MissingDefaultResource">


    <pl.droidsonroids.gif.GifImageView
        android:id="@+id/gif_second"
        android:layout_width="238dp"
        android:layout_height="120dp"
        android:src="@drawable/refresh_header3"
        android:layout_gravity="center" />

</LinearLayout>

自定义Footer

public class MyFooter extends BaseFooter {

    private Context context;
    private int rotationSrc;
    private TextView footerTitle;
    private ProgressBar footerProgressbar;

    public MyFooter(Context context) {
        this(context, R.drawable.progress_small);
    }

    public MyFooter(Context context, int rotationSrc) {
        this.context = context;
        this.rotationSrc = rotationSrc;
    }

    @Override
    public View getView(LayoutInflater inflater, ViewGroup viewGroup) {
        View view = inflater.inflate(R.layout.default_footer, viewGroup, true);
        footerTitle = (TextView) view.findViewById(R.id.default_footer_title);
        footerProgressbar = (ProgressBar) view.findViewById(R.id.default_footer_progressbar);
        footerProgressbar.setIndeterminateDrawable(ContextCompat.getDrawable(context, rotationSrc));
        return view;
    }

    @Override
    public void onPreDrag(View rootView) {
    }

    @Override
    public void onDropAnim(View rootView, int dy) {
    }

    /**
     * 手指拖拽过程中每次经过临界点时回调,upORdown是向上经过还是向下经过
     *
     * @param rootView
     * @param upORdown 是上拉还是下拉 true(上),false(下)
     */
    @Override
    public void onLimitDes(View rootView, boolean upORdown) {
        if (upORdown) {
            footerTitle.setText("松开载入更多");
        } else {
            footerTitle.setText("查看更多");
        }
    }

    @Override
    public void onStartAnim() {
        footerTitle.setVisibility(View.INVISIBLE);
        footerProgressbar.setVisibility(View.VISIBLE);
    }

    @Override
    public void onFinishAnim() {
        footerTitle.setText("查看更多");
        footerTitle.setVisibility(View.VISIBLE);
        footerProgressbar.setVisibility(View.INVISIBLE);
    }
}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" >

        <ProgressBar
            android:id="@+id/default_footer_progressbar"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerInParent="true"
            android:visibility="invisible" />

        <TextView
            android:id="@+id/default_footer_title"
            android:gravity="center"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#777777"
            android:text="加载更多" />
    </RelativeLayout>

</LinearLayout>

如何自定义最大下拉高度,临界高度,和回弹高度

在BaseHeader(BaseFooter同理)中默认已经实现3个方法,分别返回的是临界高度(limit hight),下拉最大高度(max height),下拉弹动高度(spring height):
如果有更加复杂的需求,需要更改这些高度的话,就在自己的Header中重写这些方法,注释已经很清楚了:

public abstract class BaseHeader implements SpringView.DragHander{
    /**
     * 这个方法用于设置当前View的临界高度(limit hight),即拉动到多少会被认定为刷新超作,而没到达该高度则不会执行刷新
     * 返回值大于0才有效,如果<=0 则设置为默认header的高度
     * 默认返回0
     */
    @Override
    public int getDragLimitHeight(View rootView) {
        return 0;
    }

    /**
     * 这个方法用于设置下拉最大高度(max height),无论怎么拉动都不会超过这个高度
     * 返回值大于0才有效,如果<=0 则默认600px
     * 默认返回0
     */
    @Override
    public int getDragMaxHeight(View rootView) {
        return 0;
    }

    /**
     * 这个方法用于设置下拉弹动高度(spring height),即弹动后停止状态的高度
     * 返回值大于0才有效,如果<=0 则设置为默认header的高度
     * 默认返回0
     */
    @Override
    public int getDragSpringHeight(View rootView) {
        return 0;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358