相信很多小伙伴在开发中都会遇到自定义下拉刷新头和自定义加载尾的需求,下面我分享一下我的自定义刷新头的实现。

  • 这里我用的第三方SmartRefreshLayout,这个实现自定义的时候较为简单,首先导入依赖
//1.1.0 (1.0.5及以前版本的老用户升级需谨慎,API改动过大)
compile 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-28'
compile 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0-alpha-28'//没有使用特殊Header,可以不加这行
compile 'com.android.support:appcompat-v7:25.3.1'//版本 23以上(必须)

//1.1.0 androidx 版本
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-andx-11'
implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.0-andx-11'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
  • 自定义MyHeaderView 实现RefreshHeader并实现其中的方法,直接上代码
package gov.pianzong.androidnga.view;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.scwang.smartrefresh.layout.api.RefreshHeader;
import com.scwang.smartrefresh.layout.api.RefreshKernel;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.constant.RefreshState;
import com.scwang.smartrefresh.layout.constant.SpinnerStyle;

import gov.pianzong.androidnga.R;

/**
 * 自定义刷新的头布局
 */
public class MyHeaderView extends RelativeLayout implements RefreshHeader {

    private ImageView imageView1;
    private ImageView imageView2;
    private RelativeLayout header_rl_bg;

    private Context context;

    public MyHeaderView(Context context) {
        this(context, null);
    }

    public MyHeaderView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyHeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        View view = LayoutInflater.from(context).inflate(R.layout.listview_header, this);
        header_rl_bg = view.findViewById(R.id.header_rl_bg);
        imageView1 = view.findViewById(R.id.image_1);
        imageView2 = view.findViewById(R.id.image_2);

    }
    
/**
     * 状态改变事件 {@link RefreshState}
     * @param refreshLayout RefreshLayout
     * @param oldState 改变之前的状态
     * @param newState 改变之后的状态
     */
    @Override
    public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
        switch (newState) {
            case RefreshReleased:
                Animation Animation1 = AnimationUtils.loadAnimation(context, R.anim.header_rotate_anim_1);
                imageView1.startAnimation(Animation1);
                Animation Animation2 = AnimationUtils.loadAnimation(context, R.anim.header_rotate_anim_2);
                imageView2.startAnimation(Animation2);
                break;
        }
    }
    /**
     * 下拉过程中不断调用此方法 (headerHeight:450,extendHeight:675)
     * @param percent
     * @param offset
     * @param headerHeight
     * @param extendHeight
     */
    @Override
    public void onPullingDown(float percent, int offset, int headerHeight, int extendHeight) {
        imageView1.setRotation(percent*360);
        imageView2.setRotation((1-percent)*360);
    }

    /**
     * 刷新结束以后回调
     * @param layout
     * @param success
     * @return
     */
    @Override
    public int onFinish(@NonNull RefreshLayout layout, boolean success) {
        imageView1.clearAnimation();
        imageView2.clearAnimation();
        return 0;
    }

    /**
     * 以下的方法都是RefreshHeader需要重写的方法
     */
    @Override
    public void onReleasing(float percent, int offset, int headerHeight, int extendHeight) {
    }

    @Override
    public void onRefreshReleased(RefreshLayout layout, int headerHeight, int extendHeight) {
    }

    @NonNull
    @Override
    public View getView() {
        return this;
    }

/**
     * Translate,//平行移动        特点: HeaderView高度不会改变,
    * Scale,//拉伸形变            特点:在下拉和上弹(HeaderView高度改变)时候,会自动触发OnDraw事件
    * FixedBehind,//固定在背后    特点:HeaderView高度不会改变,
    * FixedFront,//固定在前面     特点:HeaderView高度不会改变,
    * MatchLayout//填满布局       特点:HeaderView高度不会改变,尺寸充满 RefreshLayout
     */
    @NonNull
    @Override
    public SpinnerStyle getSpinnerStyle() {
        return SpinnerStyle.Translate;
    }

    @Override
    public void setPrimaryColors(int... colors) {

    }

    @Override
    public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {

    }


    @Override
    public void onStartAnimator(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) {

    }

    @Override
    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {

    }

    @Override
    public boolean isSupportHorizontalDrag() {
        return false;
    }

}

具体就是以上,代码很简单,我实现的是旋转动画,主要涉及到

  1. onPullingDown:这个是在手指下拉过成功不断回调的一个方法,根据手指下拉的偏移量,对两个图片进行旋转,一个正转一个倒转;
  2. onStateChanged:这个是监控手指的状态,有很多状态,因为需要我这里只用到了RefreshReleased(用户松开手,开始刷新) 这时候开启动画
  3. onFinish:是刷新结束以后调用的,这个时候便是结束动画;
  4. getSpinnerStyle:这个方法是控制刷新头的样式,具体样式可以看代码中的注释;

自定义刷新头之后其实可以直接用,为了xml简单我这里自定义下MySmartRefreshLayout,直接指定用刚才自定义的头:

public class MySmartRefreshLayout extends SmartRefreshLayout {
    MyHeaderView  mHeaderView;

    public MySmartRefreshLayout (Context context) {
        this(context, null);
    }

    public MySmartRefreshLayout (Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySmartRefreshLayout (Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mHeaderView= new MyHeaderView(context);
        mHeaderView.setLayoutParams(layoutParams);
        addView(mHeaderView, 0);
    }
}

那么自定义完成之后就是使用了:

<?xml version="1.0" encoding="utf-8"?>

<gov.pianzong.androidnga.view.MySmartRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/refreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ListView
            android:id="@+id/list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

</gov.pianzong.androidnga.view.MySmartRefreshLayout>
public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private MyAdapter myAdapter;
    private List<Object> dataList = new ArrayList<Object>();
    private MySmartRefreshLayout pullRefreshLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pullRefreshLayout = findViewById(R.id.refreshLayout);
        listView = findViewById(R.id.list_view);

        initData();
        myAdapter = new MyAdapter();
        listView.setAdapter(myAdapter);

        pullRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        dataList.clear();
                        for (int i = 0; i < 10; i++) {
                            dataList.add("第" + i + "条数据-----");
                        }
                        myAdapter.notifyDataSetChanged();
                        pullRefreshLayout.finishRefresh();
                    }
                }, 3000);
            }
        }).setOnLoadmoreListener(new OnLoadmoreListener() {
            @Override
            public void onLoadmore(RefreshLayout refreshlayout) {
                //加载跟多的代码
                dataList.add("这是一条新数据条数据-----");
                myAdapter.notifyDataSetChanged();
                pullRefreshLayout.finishLoadmore();
            }
        });

    }


    private void initData() {
        for (int i = 0; i < 10; i++) {
            dataList.add("第" + i + "条数据");
        }

    }


    class MyAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return dataList.size();
        }

        @Override
        public Object getItem(int position) {
            return dataList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder = null;
            if (convertView != null && convertView instanceof LinearLayout) {
                viewHolder = (ViewHolder) convertView.getTag();
            } else {
                //加载布局
                viewHolder = new ViewHolder();
                convertView = View.inflate(MainActivity.this, R.layout.listview_item01, null);
                viewHolder.tv_text = (TextView) convertView.findViewById(R.id.tv_text01);
                convertView.setTag(viewHolder);
            }
            viewHolder.tv_text.setText(dataList.get(position)+"");
            return convertView;
        }


        class ViewHolder {
            private TextView tv_text;
        }

    }

}

自此自定义刷新头便完成了!!!

总结:
SmartRefreshLayout是一个强大的刷新库,不光可以自定义,本身他也自带了很多炫酷的功能,具体的可以看 SmartRefreshLayout,这种自定义的刷新头较为简单,但是因为SmartRefreshLayout的强大,导入依赖后也会致apk包变大,粗略估计差不多大个2M多。

(小女子菜鸟一枚,以上问题均是自己开发遇到并解决的,如有不对或有更好的方法请大佬们指教,如对你们有帮助,倍感荣幸)