Android中自定义刷新头

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

  • 这里我用的第三方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多。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android常用的自定义刷新方式有两种:下拉刷新和上拉加载更多。 1. 下拉刷新 下拉刷新是指在页面顶部向下拉动时,触发刷新操作,常见的实现方式是使用SwipeRefreshLayout控件,具体实现步骤如下: (1)在布局文件添加SwipeRefreshLayout控件: ``` <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 添加需要刷新的控件 --> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> ``` (2)在Activity或Fragment初始化SwipeRefreshLayout控件,并设置刷新事件: ``` SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { // 执行刷新操作 // 刷新完成后调用setRefreshing(false)停止刷新 swipeRefreshLayout.setRefreshing(false); } }); ``` 2. 上拉加载更多 上拉加载更多是指在页面底部向上拉动时,触发加载更多数据的操作,常见的实现方式是使用RecyclerView控件,具体实现步骤如下: (1)在布局文件添加RecyclerView控件: ``` <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` (2)在Activity或Fragment初始化RecyclerView控件,并添加滑动监听器: ``` RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 判断是否已经到达底部 if (!recyclerView.canScrollVertically(1)) { // 加载更多数据 } } }); ``` 需要注意的是,上拉加载更多需要在滑动到底部时才会触发,因此需要在RecyclerView设置adapter时添加FooterView,以提示用户正在加载更多数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值