ListView的下拉加载更多

1.思路

1.自定义下拉刷新的布局文件

2.自定义listview初始化下拉刷新的布局文件

3.隐藏头部的下拉刷新布局,设置header的topPadding为其高度的负值

4.测量子view的width和height.

5.设置listview的滑动监听事件

6.重写onTouch()方法,根据不同的手势状态设置下拉刷新状态值的改变

7.下拉刷新完成后的状态

8.定义接口,加载下拉刷新的数据

2.代码部分

1.自定义下拉刷新的布局文件
<?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="wrap_content">

    <RelativeLayout
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:padding="10dp"
            android:gravity="center"
            android:id="@+id/ll_layout"
            android:layout_centerInParent="true"
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/text"
                android:textSize="15dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉可以刷新"/>

            <TextView
                android:textSize="12dp"
                android:layout_marginTop="8dp"
                android:text="2016年3月20日 18:30"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/lastupdata_time"/>

        </LinearLayout>

        <ImageView
            android:layout_marginRight="10dp"
            android:layout_toLeftOf="@+id/ll_layout"
            android:id="@+id/image_arrow"
            android:layout_centerVertical="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/pull_to_refresh_arrow"
            android:layout_alignEnd="@+id/progressbar" />

        <ProgressBar
            android:layout_centerVertical="true"
            android:paddingLeft="65dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/progressbar"
            android:visibility="gone"/>
    </RelativeLayout>
</LinearLayout>
2.自定义listview初始化下拉刷新的布局文件
private void initView(Context context) {
    layoutInflater = LayoutInflater.from(context);
    header = layoutInflater.inflate(R.layout.header_layout, null);
        measureView(header);
        // 获取到header头部的高度
        headerHeight = header.getMeasuredHeight();
        topPadding(-headerHeight);
        // 在头部添加下拉刷新的的布局
        this.addHeaderView(header);
        this.setOnScrollListener(this);
    }
3.隐藏头部的下拉刷新布局,设置header的topPadding为其高度的负值
// 获取到header头部的高度
  headerHeight = header.getMeasuredHeight();
      topPadding(-headerHeight);
          /**
           *  设置布局的上边距隐藏
           */

   private void topPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding,
         header.getPaddingRight(), header.getPaddingBottom());
        // 刷新界面
        header.invalidate();
    }
4.测量子view的width和height.
    /**
     * 告诉父布局header占用的宽/高
     * @param child 子控件
     */
    private void measureView(View child) {
        ViewGroup.LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        // 获取到子孩子的宽度
        int measureWidth = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        int measureHeight;
        int tempHeight = params.height;
        if (tempHeight > 0) {
            measureHeight = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
        } else {
            measureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        child.measure(measureWidth, measureHeight);
    }
5.设置listview的滑动监听事件
 @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState = scrollState;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                         int totalItemCount) {
        this.firstVisibleItem = firstVisibleItem;
    }
6.重写onTouch()方法,根据不同的手势状态设置下拉刷新状态值的改变
 @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (firstVisibleItem == 0) {
                    isMove = true;
                    // 记录按下的起点的纵坐标
                    startY = (int) ev.getY();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                move(ev);
                break;
            case MotionEvent.ACTION_UP:
                // 当抬起的时候状态就要从释放状态---->正在刷新
                if (state == RELEASE) {
                    state = REFRESHING;
                    refreshByState();
                    // 刷新数据
                    iRefreshDataListener.onRefresh();
                }else if (state == PULL) {
                    state = NORMAL;
                    isMove = false;
                    refreshByState();
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

/**
 * 判断移动过程中的操作
 */

private void move(MotionEvent ev) {
    //
    if (!isMove) {
        return;
    }
    int tempY = (int) ev.getY();
    // 移动的距离
    int space = tempY - startY;
    // 在下拉的的过程中是不断的发生变化的
    int topPadding = space - headerHeight;
    // 在移动的过程中状态是不断的的发生变化的
    switch (state) {
        case NORMAL:
            if (space > 0) {
                state = PULL;
                refreshByState();
            }
            break;
        case PULL:
            topPadding(topPadding);
            // 当距离大于一定的长度的时候就是是处于释放状态
            if (space > headerHeight + 20
                    && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
                state = RELEASE;
                refreshByState();
            }
            break;
        case RELEASE:
            topPadding(topPadding);
            // 如果距离小于某一个长度,那么久是处于下拉状态
            if (space < headerHeight + 20) {
                state = PULL;
                refreshByState();
            } else if (space <= 0){
                // 当距离小于0的时候就是正常状态
                state = NORMAL;
                isMove = false;
                refreshByState();
            }
            break;

    }
}

// 根据当前的状态改变界面显示
private  void refreshByState() {
    ImageView arrow = (ImageView) header.findViewById(R.id.image_arrow);
    TextView text = (TextView) header.findViewById(R.id.text);
    ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progressbar);
    // 创建动画
    RotateAnimation animation1 = new RotateAnimation(0,180,
            Animation.RELATIVE_TO_SELF,0.5f,
            Animation.RELATIVE_TO_SELF,0.5f);
    animation1.setFillAfter(true);
    animation1.setDuration(500);

    RotateAnimation animation2 = new RotateAnimation(180,0,
            Animation.RELATIVE_TO_SELF,0.5f,
            Animation.RELATIVE_TO_SELF,0.5f);
    animation2.setFillAfter(true);
    animation2.setDuration(500);

    switch (state) {
        case NORMAL:
            topPadding(-headerHeight);
            arrow.clearAnimation();
            break;
        case PULL:
            progressBar.setVisibility(View.GONE);
            arrow.setVisibility(View.VISIBLE);
            text.setText("下拉刷新");
            arrow.clearAnimation();
            arrow.setAnimation(animation1);
            break;
        case RELEASE:
            progressBar.setVisibility(View.GONE);
            arrow.setVisibility(View.VISIBLE);
            text.setText("松开刷新");
            arrow.clearAnimation();
            arrow.setAnimation(animation2);
            break;
        case REFRESHING:
            topPadding(100);
            progressBar.setVisibility(View.VISIBLE);
            arrow.setVisibility(View.GONE);
            text.setText("正在刷新....");
            arrow.clearAnimation();
            break;
    }
}
7.下拉刷新完成后的状态
  public void refreshComplete() {
        state = NORMAL;
        isMove = false;
        refreshByState();
        TextView refresh_time = (TextView) header.findViewById(R.id.lastupdata_time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
        Date date = new Date(System.currentTimeMillis());
        String time = sdf.format(date);
        refresh_time.setText(time);

    }
8.定义接口,加载下拉刷新的数据
public void setlistener(IRefreshDataListener iRefreshDataListener) {
        this.iRefreshDataListener = iRefreshDataListener;

    }

    // 刷新数据的接口
    public interface IRefreshDataListener{
        public void onRefresh();
    }

3.部分代码解释

1.getMeasuredHeight()与getHeight()的区别:

当view不能完全显示在整个屏幕的时候,getMeasuredHeight = getHeight + 隐藏在屏幕外的view的高度;getMeasuredHeight()是实际View的大小,与屏幕高度无关.

2.getChildMeasureSpec与makeMeasureSpec的区别:

参见该大神的博客

4.完整代码

1.mainActivity
public class MainActivity extends AppCompatActivity implements RefreshListView.IRefreshDataListener{
    private RefreshListView listView;
    private List<ItemBean> list = new ArrayList<>();
    private MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView = (RefreshListView) findViewById(R.id.listview);
        listView.setlistener(this);
        initData();
        showData();
    }

    // 初始化数据
    private void initData() {
        for (int i = 0; i <10 ; i++) {
            ItemBean item = new ItemBean();
            item.setImageView(R.mipmap.ic_launcher);
            item.setContent("这是内容   " + i);
            item.setTitle("标题   " + i);
            list.add(item);
        }

    }

    private void showData() {
        if (adapter == null) {
            adapter = new MyAdapter(list, this);

            listView.setAdapter(adapter);
        } else {
            adapter.onDataChanged(list);
        }
    }

    private void refreshData() {
        for (int i = 0; i <2; i++) {
            ItemBean item = new ItemBean();
            item.setImageView(R.mipmap.ic_launcher);
            item.setContent("这是刷新内容   " + i);
            item.setTitle("标题   " + i);
            // 将数据添加在第一个位置
            list.add(0,item);
        }
    }

    @Override
    public void onRefresh() {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // 获取到最新数据
                refreshData();
                // 通知界面更新数据
                showData();
                // 通知listview刷新数据完毕
                listView.refreshComplete();
            }
        }, 2500);
    }
}
2.adapter
public class MyAdapter extends BaseAdapter {

    private List<ItemBean> list;
    private Context context;

    public MyAdapter(List<ItemBean> list, Context context) {
        this.list = list;
        this.context = context;
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = View.inflate(context, R.layout.list_item, null);
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageview);
            viewHolder.content = (TextView) convertView.findViewById(R.id.text_content);
            viewHolder.title = (TextView) convertView.findViewById(R.id.text_title);
            convertView.setTag(viewHolder);
        }else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // 获取到数据对每一个控件进行赋值
        ItemBean itemBean = list.get(position);
        itemBean.setImageView(itemBean.getImageView());
        viewHolder.content.setText(itemBean.getContent());
        viewHolder.title.setText(itemBean.getTitle());

        return convertView;
    }

    public void onDataChanged(List<ItemBean> list) {
        this.list = list;
        this.notifyDataSetChanged();

    }


    class ViewHolder{
        private ImageView imageView;
        private TextView content;
        private TextView title;
    }
}
3.itembean
public class ItemBean {
    private int imageView;
    private String title;
    private String content;

    public int getImageView() {
        return imageView;
    }

    public void setImageView(int imageView) {
        this.imageView = imageView;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}
4.refreshListview
public class RefreshListView extends ListView implements AbsListView.OnScrollListener{

    private LayoutInflater layoutInflater;
    private View header;
    private int headerHeight;
    private int firstVisibleItem;
    private boolean isMove;// 标记,是否是移动状态
    private int startY; // 按下的的位置
    private int scrollState;// 当前滚动的状态
    IRefreshDataListener iRefreshDataListener;// 刷新数据的接口

    private int state;
    final int NORMAL = 0;//正常状态
    final int PULL = 1;//下拉状态
    final int RELEASE = 2;//释放状态
    final int REFRESHING = 3;//正在刷新状态


    public RefreshListView(Context context) {
        super(context);
        initView(context);
    }

    public RefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        layoutInflater = LayoutInflater.from(context);
        header = layoutInflater.inflate(R.layout.header_layout, null);
        measureView(header);
        // 获取到header头部的高度
        headerHeight = header.getMeasuredHeight();
        topPadding(-headerHeight);
        // 在头部添加下拉刷新的的布局
        this.addHeaderView(header);
        this.setOnScrollListener(this);
    }

    /**
     * 告诉父布局header占用的宽/高
     * @param child 子控件
     */
    private void measureView(View child) {
        ViewGroup.LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                         ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        // 获取到子孩子的宽度
        int measureWidth = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        int measureHeight;
        int tempHeight = params.height;
        if (tempHeight > 0) {
            measureHeight = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
        } else {
            measureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        child.measure(measureWidth, measureHeight);
    }

    /**
     *  设置布局的上边距隐藏
     */

    private void topPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding,
                header.getPaddingRight(), header.getPaddingBottom());
        // 刷新界面
        header.invalidate();
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (firstVisibleItem == 0) {
                    isMove = true;
                    // 记录按下的起点的纵坐标
                    startY = (int) ev.getY();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                move(ev);
                break;
            case MotionEvent.ACTION_UP:
                // 当抬起的时候状态就要从释放状态---->正在刷新
                if (state == RELEASE) {
                    state = REFRESHING;
                    refreshByState();
                    // 刷新数据
                    iRefreshDataListener.onRefresh();
                }else if (state == PULL) {
                    state = NORMAL;
                    isMove = false;
                    refreshByState();
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 判断移动过程中的操作
     */

    private void move(MotionEvent ev) {
        //
        if (!isMove) {
            return;
        }
        int tempY = (int) ev.getY();
        // 移动的距离
        int space = tempY - startY;
        // 在下拉的的过程中是不断的发生变化的
        int topPadding = space - headerHeight;
        // 在移动的过程中状态是不断的的发生变化的
        switch (state) {
            case NORMAL:
                if (space > 0) {
                    state = PULL;
                    refreshByState();
                }
                break;
            case PULL:
                topPadding(topPadding);
                // 当距离大于一定的长度的时候就是是处于释放状态
                if (space > headerHeight + 20
                        && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
                    state = RELEASE;
                    refreshByState();
                }
                break;
            case RELEASE:
                topPadding(topPadding);
                // 如果距离小于某一个长度,那么久是处于下拉状态
                if (space < headerHeight + 20) {
                    state = PULL;
                    refreshByState();
                } else if (space <= 0){
                    // 当距离小于0的时候就是正常状态
                    state = NORMAL;
                    isMove = false;
                    refreshByState();
                }
                break;

        }
    }

    // 根据当前的状态改变界面显示
    private  void refreshByState() {
        ImageView arrow = (ImageView) header.findViewById(R.id.image_arrow);
        TextView text = (TextView) header.findViewById(R.id.text);
        ProgressBar progressBar = (ProgressBar) header.findViewById(R.id.progressbar);
        // 创建动画
        RotateAnimation animation1 = new RotateAnimation(0,180,
                Animation.RELATIVE_TO_SELF,0.5f,
                Animation.RELATIVE_TO_SELF,0.5f);
        animation1.setFillAfter(true);
        animation1.setDuration(500);

        RotateAnimation animation2 = new RotateAnimation(180,0,
                Animation.RELATIVE_TO_SELF,0.5f,
                Animation.RELATIVE_TO_SELF,0.5f);
        animation2.setFillAfter(true);
        animation2.setDuration(500);

        switch (state) {
            case NORMAL:
                topPadding(-headerHeight);
                arrow.clearAnimation();
                break;
            case PULL:
                progressBar.setVisibility(View.GONE);
                arrow.setVisibility(View.VISIBLE);
                text.setText("下拉刷新");
                arrow.clearAnimation();
                arrow.setAnimation(animation1);
                break;
            case RELEASE:
                progressBar.setVisibility(View.GONE);
                arrow.setVisibility(View.VISIBLE);
                text.setText("松开刷新");
                arrow.clearAnimation();
                arrow.setAnimation(animation2);
                break;
            case REFRESHING:
                topPadding(100);
                progressBar.setVisibility(View.VISIBLE);
                arrow.setVisibility(View.GONE);
                text.setText("正在刷新....");
                arrow.clearAnimation();
                break;
        }
    }

    /**
     * 下拉刷新完成
     */
    public void refreshComplete() {
        state = NORMAL;
        isMove = false;
        refreshByState();
        TextView refresh_time = (TextView) header.findViewById(R.id.lastupdata_time);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
        Date date = new Date(System.currentTimeMillis());
        String time = sdf.format(date);
        refresh_time.setText(time);

    }

    public void setlistener(IRefreshDataListener iRefreshDataListener) {
        this.iRefreshDataListener = iRefreshDataListener;

    }

    // 刷新数据的接口
    public interface IRefreshDataListener{
        public void onRefresh();
    }
}

你可能感兴趣的:(ListView,数据)