自定义listview的下拉刷新和上拉加载

第一次写博客,有点小激动,以后会坚持下来,记录学习的生涯
经常会用到listview的下拉刷新和上拉加载,虽然个github上有很多开源的框架,总感觉用着不是很理解,决定自己写一写。
效果图:

自定义listview,添加headerview和footerview,监听滚动事件;

MyListView.java

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class MyListView extends ListView implements AbsListView.OnScrollListener {

    public int height;
    private int offsetheight;//记录listview下拉偏移量
    private ImageView arrow;
    private TextView dateText;
    private TextView tipsText;
    private View headerView;//listview头布局
    public View footView;//listview脚布局
    private int totalItemCount;//全部的列表项
    private int startY;//listview开始下拉的位置
    private int firstVisibleItem;//记录第一个下拉的项
    private int lastVisibleItem;
    private int STATE;//记录当前状态
    private boolean isFromBegin;//记录是否从头开始下拉
    private final int NONE = 0;//listview处于静态
    private final int PULL = 1;//listview处于下拉状态
    private final int RELESE = 2;//listview处于松开刷新的状态
    private final int RELESING = 3;//listview处于正在刷新状态
    private LoadListener loadListener;//底部加载监听
    public ProgressBar progressBar;
    private RefreshListener refreshListener;//头部刷新监听

    public void setRefreshListener(RefreshListener refreshListener) {
        this.refreshListener = refreshListener;
    }

    public void setLoadListener(LoadListener loadListener) {
        this.loadListener = loadListener;
    }

    public MyListView(Context context) {
        super(context);
        init(context);
    }

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);

    }


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

    }

    /**
     * 初始化组件,添加headerView和footView
     */

    public void init(Context context) {
        headerView = LayoutInflater.from(context).inflate(R.layout.headerview, null);
        footView = LayoutInflater.from(context).inflate(R.layout.footview, null);
        arrow = (ImageView) headerView.findViewById(R.id.arrow);
        dateText = (TextView) headerView.findViewById(R.id.date);
        tipsText = (TextView) headerView.findViewById(R.id.tips);
        progressBar = (ProgressBar) headerView.findViewById(R.id.progressbar);
        notifyView(headerView);
        height = headerView.getMeasuredHeight();
        setPadding(-height);
        footView.setVisibility(INVISIBLE);
        this.addHeaderView(headerView);//添加头布局
        this.addFooterView(footView);//添加脚布局
        this.setOnScrollListener(this);
        this.setVerticalScrollBarEnabled(false);//隐藏滚动条
    }


    /**
     * 通知父布局测量子布局的尺寸
     */

    public void notifyView(View view) {
        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
        if (layoutParams == null) {
            layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        }
        int with = ViewGroup.getChildMeasureSpec(0, 0, view.getWidth());
        int height;
        int viewheight = view.getHeight();
        if (viewheight > 0) {
            MeasureSpec.makeMeasureSpec(viewheight, MeasureSpec.EXACTLY);
        } else {
            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(with, viewheight);
    }


    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

        //判断是否到达列表的最底部和加载数据
        if (this.lastVisibleItem == this.totalItemCount) {
            footView.setVisibility(VISIBLE);
            loadListener.getLoadData();
        }

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

        this.firstVisibleItem = firstVisibleItem;
        this.lastVisibleItem = firstVisibleItem + visibleItemCount;
        this.totalItemCount = totalItemCount;

    }

    /**
     * 监听listview的touch事件
     */

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (firstVisibleItem == 0) {
                    STATE = NONE;
                    isFromBegin = true;
                    startY = (int) ev.getY();

                }
                break;
            case MotionEvent.ACTION_MOVE:
                move(ev);
                break;
            case MotionEvent.ACTION_UP:
                if (STATE == RELESE) {
                    STATE = RELESING;
                    ChangeViewFromState(STATE);
                } else if (STATE == PULL) {
                    STATE = NONE;
                    ChangeViewFromState(STATE);
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * @param ev
     * listview滑动状态的处理,分发处理listview下拉达到的状态
     */
    public void move(MotionEvent ev) {
        if (!isFromBegin) {
            return;
        }
        offsetheight = (int) ev.getY() - startY;
        switch (STATE) {
            case NONE:
                setPadding(offsetheight);
                if (offsetheight > 0) {
                    STATE = PULL;
                    ChangeViewFromState(STATE);
                }

                break;
            case PULL:
                setPadding(offsetheight);
                if (offsetheight >= height + 60) {
                    STATE = RELESE;
                    ChangeViewFromState(STATE);
                }
                break;
            case RELESE:
                setPadding(offsetheight);
                if (offsetheight < height + 60) {
                    STATE = PULL;
                    ChangeViewFromState(STATE);
                }

                break;


        }


    }

    /**
     * 设置headerview的padding
     * @param offsetHeight
     */
    public void setPadding(int offsetHeight) {
        headerView.setPadding(headerView.getPaddingLeft(), -height + offsetHeight, headerView.getPaddingLeft(), headerView.getPaddingBottom());
        headerView.invalidate();
    }

    /**
     * 根据当前的状态改变headerview的view
     * @param state
     */

    public void ChangeViewFromState(int state) {
        RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setDuration(500);
        animation.setFillAfter(true);
        RotateAnimation animation1 = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation1.setDuration(500);
        animation1.setFillAfter(true);
        switch (state) {
            case NONE:
                arrow.clearAnimation();
                setPadding(-height);
                tipsText.setText("下拉刷新");
                break;
            case PULL:
                arrow.clearAnimation();
                //arrow.setAnimation(animation1);
                tipsText.setText("下拉刷新");
                arrow.setVisibility(VISIBLE);
                progressBar.setVisibility(GONE);
                break;
            case RELESE:
                arrow.clearAnimation();
                arrow.setAnimation(animation);
                tipsText.setText("松开刷新");

                break;
            case RELESING:
                setPadding(height);
                arrow.clearAnimation();
                tipsText.setText("正在刷新...");
                arrow.setVisibility(GONE);
                progressBar.setVisibility(VISIBLE);
                refreshListener.getRefreshData();
                break;
        }

    }

    /**
     * listview的下拉刷新数据接口
     */
    public interface RefreshListener {
        public void getRefreshData();
    }

    /**
     * listview的上拉加载数据接口
     */
    public interface LoadListener {
        public void getLoadData();
    }

    /**
     * 更新headerview刷新的时间
     */
    public void refreshTime() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm", Locale.CHINA);
        Date date = new Date(System.currentTimeMillis());
        String datatime = simpleDateFormat.format(date);
        dateText.setText(datatime);
    }
}

其它部分比较简单,就不展示出来了

以下是对提供的参考资料的总结,按照要求结构化多个要点分条输出: 4G/5G无线网络优化与网规案例分析: NSA站点下终端掉4G问题:部分用户反馈NSA终端频繁掉4G,主要因终端主动发起SCGfail导致。分析显示,在信号较好的环境下,终端可能因节能、过热保护等原因主动释放连接。解决方案建议终端侧进行分析处理,尝试关闭节电开关等。 RSSI算法识别天馈遮挡:通过计算RSSI平均值及差值识别天馈遮挡,差值大于3dB则认定有遮挡。不同设备分组规则不同,如64T和32T。此方法可有效帮助现场人员识别因环境变化引起的网络问题。 5G 160M组网小区CA不生效:某5G站点开启100M+60M CA功能后,测试发现UE无法正常使用CA功能。问题原因在于CA频点集标识配置错误,修正后测试正常。 5G网络优化与策略: CCE映射方式优化:针对诺基亚站点覆盖农村区域,通过优化CCE资源映射方式(交织、非交织),提升RRC连接建立成功率和无线接通率。非交织方式相比交织方式有显著提升。 5G AAU两扇区组网:与三扇区组网相比,AAU两扇区组网在RSRP、SINR、下载速率和上传速率上表现不同,需根据具体场景选择适合的组网方式。 5G语音解决方案:包括沿用4G语音解决方案、EPS Fallback方案和VoNR方案。不同方案适用于不同的5G组网策略,如NSA和SA,并影响语音连续性和网络覆盖。 4G网络优化与资源利用: 4G室分设备利旧:面对4G网络投资压减与资源需求矛盾,提出利旧多维度调优策略,包括资源整合、统筹调配既有资源,以满足新增需求和提质增效。 宏站RRU设备1托N射灯:针对5G深度覆盖需求,研究使用宏站AAU结合1托N射灯方案,快速便捷地开通5G站点,提升深度覆盖能力。 基站与流程管理: 爱立信LTE基站邻区添加流程:未提供具体内容,但通常涉及邻区规划、参数配置、测试验证等步骤,以确保基站间顺畅切换和覆盖连续性。 网络规划与策略: 新高铁跨海大桥覆盖方案试点:虽未提供详细内容,但可推测涉及高铁跨海大桥区域的4G/5G网络覆盖规划,需考虑信号穿透、移动性管理、网络容量等因素。 总结: 提供的参考资料涵盖了4G/5G无线网络优化、网规案例分析、网络优化策略、资源利用、基站管理等多个方面。 通过具体案例分析,展示了无线网络优化中的常见问题及解决方案,如NSA终端掉4G、RSSI识别天馈遮挡、CA不生效等。 强调了5G网络优化与策略的重要性,包括CCE映射方式优化、5G语音解决方案、AAU扇区组网选择等。 提出了4G网络优化与资源利用的策略,如室分设备利旧、宏站RRU设备1托N射灯等。 基站与流程管理方面,提到了爱立信LTE基站邻区添加流程,但未给出具体细节。 新高铁跨海大桥覆盖方案试点展示了特殊场景下的网络规划需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值