ListView 上拉刷新 下拉加载更多(参考imooc)

一.上拉刷新

步骤:

1.需要添加顶部下拉加载界面。

2.监听onScrollListener来判断当前是否显示在ListView的最顶部。

3.因为顶部下拉加载界面是随收拾滑动状态不断改变的,因此我们需要监听onTouch事件,来改变当前状态以及界面显示。

4.根据当前状态加载数据。


大家先看看主角上拉刷新View的设计

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="10dp"
    android:paddingBottom="10dp">
    <LinearLayout
        android:id="@+id/id_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/id_tip"
            android:text="下拉可以刷新"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/id_lastupdatetime"
            android:text="5分钟之前刷新"/>
    </LinearLayout>
    <ImageView
        android:id="@+id/id_arrow"
        android:layout_toLeftOf="@id/id_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/arrow"
        />
    <ProgressBar
        android:id="@+id/id_progress"
        style="?android:attr/progressBarStyle"
        android:layout_toLeftOf="@id/id_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"/>
</RelativeLayout>
</LinearLayout>
是时候把他初始化了

实现OnScrollListener,定义我要使用的变量

public class LoadListView extends ListView implements AbsListView.OnScrollListener {
private View header;
private boolean isRemark;//标记、当前是在ListView最顶端按下的
private int startY;//按下时的Yprivate  int state;//当前的状态
private int scrollState;//ListView的当前滚动状态
private  final int NONE=0;//正常状态
private  final int PULL=1;//提示下拉状态
private  final int RELEASE=2;//提示释放状态
private  final int REFLEASHING=3;//正在刷新状态
private  IRefleshListener iRefleshListener;//


private void initView(Context context) {
    LayoutInflater inflater = LayoutInflater.from(context);
    header = inflater.inflate(R.layout.header_layout, null);
    //通知父布局,占用的宽高
    measureView(header);
    headerHeight = header.getMeasuredHeight();
    Log.i("LoadListView", "headerHeight "  + headerHeight);
    //设置header布局的上边距 
    topPadding(-headerHeight);
    footer = inflater.inflate(R.layout.footer_layout, null);
    footer.findViewById(R.id.id_loadlayout).setVisibility(View.GONE);
    this.setOnScrollListener(this);
    this.addHeaderView(header);
    this.addFooterView(footer);
}
通知父布局,占用的宽高,否则header.getMeasuredHeight()为零
 

/*
通知父布局,占用的宽高
 */
    private void measureView(View view) {
        ViewGroup.LayoutParams p = view.getLayoutParams();
        if (p == null)
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
        int height;
        int tempHeight = p.height;
        if (tempHeight > 0)
            height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
        else
        {
            height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        Log.i("LoadListView", "width:" + width);
        Log.i("LoadListView", "height:" + height);
        view.measure(width,height);
    }
设置header布局的高度为负原始高度来隐藏header 别忘了刷新header控件

//设置header布局的上边距
private void topPadding(int topPaddding) {
    header.setPadding(header.getPaddingLeft(), topPaddding, header.getPaddingRight(), header.getPaddingBottom());
    header.invalidate();
}

记录一下listview第一个item的次序来判断是否scroll达到了最顶端

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    this.firstVisibleItem=firstVisibleItem;
    this.lastVisibleItem = firstVisibleItem + visibleItemCount;
    this.totalItemCount = totalItemCount;
}

记录 scrollState

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    this.scrollState = scrollState;

下面来到了本次代码的高潮部分

判断onTouchEvent来决定header显示啥子东西

@Override
public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            if (firstVisibleItem == 0)
                isRemark = true;//标记 是否在listview最顶端按下
            startY = (int) ev.getY();//按下时的Y        }
        break;
        case MotionEvent.ACTION_MOVE:
            onMove(ev);
            break;
        case MotionEvent.ACTION_UP://判断抬手时的状态
            if (state == RELEASE) {//若是释放状态执行刷新
                state = REFLEASHING;
                //加载最新的数据
                if (this.iRefleshListener != null)
                {
                    this.iRefleshListener.onReflesh();
                    reflashViewByState();
                }
            } else if (state == PULL) {//若是下拉状态 置为正常状态
                state = NONE;
                isRemark = false;
                reflashViewByState();
            }
    }
    return super.onTouchEvent(ev);
}

iRefleshListener是为了调用那个实现它接口的主Activity里面方法 这个怎么做呢 

1.A为主类 B为辅类 在A中实例化B A可以调B B如果想调A 就得这么搞

在B中定义接口

private IRefleshListener iRefleshListener;

public interface IRefleshListener {
    public void onReflesh();
}

并定义一个方法把A传进来

public void setInterface(IRefleshListener iRefleshListener) {
    this.iRefleshListener = iRefleshListener;
}

A类去实现这个接口并把自己传进去

public class MainActivity extends AppCompatActivity implements LoadListView.ILoadListener ,LoadListView.IRefleshListener {

mListView.setInterface(this);

    @Override
    public void onReflesh() {
        //加一个延迟效果
        android.os.Handler handler = new android.os.Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {

                //获取最新数据
                setRefleshDatas();
                //通知界面显示
                ShowListView((ArrayList<Bean>)mDatas);
                //通知listview通知完毕
                mListView.refleshComplete();
            }
        },2000);
    }
}

继续更

/*
判断移动过程中的操作
 */
private void onMove(MotionEvent ev) {
    if (!isRemark)
        return;
    int tempY = (int) ev.getY();
    int space = tempY - startY;
    int topPadding = space - headerHeight;
    switch (state) {
        case NONE://如果大于0个像素 说明状态由空置转变为下拉状态
            if (space > 0)
                state = PULL;
            reflashViewByState();//根据当前状态改变界面显示
            break;
        case PULL:
            topPadding(topPadding);//一步一步似爪牙 
            if (space > headerHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
                state = RELEASE;
                reflashViewByState();
            }
            break;

        case RELEASE:
            topPadding(topPadding);
            if (space < headerHeight + 30) {
                state = PULL;
                reflashViewByState();
            } else if (space <= 0) {
                state = NONE;
                isRemark = false;
                reflashViewByState();
            }
            break;

        case REFLEASHING:
            break;
    }
}
下面是更新界面

/*
根据当前状态改变界面显示
 */
private void reflashViewByState() {
    TextView tip = (TextView) header.findViewById(R.id.id_tip);
    ImageView arrow = (ImageView) header.findViewById(R.id.id_arrow);
    ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.id_progress);
    RotateAnimation anim = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    RotateAnimation anim1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(500);
    anim.setFillAfter(true);
    anim1.setDuration(500);
    anim1.setFillAfter(true);
    switch (state) {
        case NONE:
            topPadding(-headerHeight);
            arrow.clearAnimation();
            break;
        case PULL:
            arrow.setVisibility(View.VISIBLE);
            progressBar.setVisibility(View.GONE);
            tip.setText("下拉可以刷新");
            arrow.setAnimation(anim1);
            break;
        case RELEASE:
            arrow.setVisibility(View.VISIBLE);
            progressBar.setVisibility(View.GONE);
            tip.setText("松开可以刷新");
            arrow.setAnimation(anim);
            break;
        case REFLEASHING:
            topPadding(headerHeight);
            arrow.setVisibility(View.GONE);
            progressBar.setVisibility(View.VISIBLE);
            tip.setText("正在刷新...");
            arrow.clearAnimation();
            break;
    }
}
获取完毕记得给header干掉并记录一下时间

/*
获取完数据
 */
public void refleshComplete() {
    state = NONE;
    isRemark = false;
    reflashViewByState();
    TextView lastUpdateTime = (TextView) header.findViewById(R.id.id_lastupdatetime);
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
    Date date = new Date(System.currentTimeMillis());
    String time = format.format(date);
    lastUpdateTime.setText(time);
}

哈拉先更到这里啦


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值