自定义ListView实现下拉刷新和分页加载(效果类似知乎)

来源:互联网 发布:推广淘宝联盟怎么转码 编辑:程序博客网 时间:2024/05/19 12:37

摘要:

自定义了一个ListView,实现下拉刷新和分页加载。


下拉刷新效果:

当ListView滑到最顶端的时候,向下滑动手指,ListView并不向下滑动,而是在顶端出现一个headerBar,headerBar的宽度与手指向下滑动的距离成正比,手指滑动距离超过阈值,ListView通过接口回调,通知外部进行refresh,刷新内容,同时headerBar变为从左向右不断滑动的动画。

方案:

通过Override ListView的onTouchEvent(MotionEvent ev)方法实现。


分页加载效果:

当ListView滑动到最底端并停止滑动时,ListView通过接口回调,通知外部进行LoadMore,加载更多。

方案:

实现OnScrollListener接口,Override onScrollStateChanged方法,和onScroll方法


xml代码如下,HeaderView用于下拉刷新,FooterView用于分页加载

</pre><pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="@dimen/abc_action_bar_default_padding_material"    android:orientation="horizontal">    <TextView        android:id="@+id/drag_header"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_gravity="center"        android:background="@android:color/holo_blue_light"        android:visibility="invisible"/>    <LinearLayout        android:id="@+id/refresh_header"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="horizontal"        android:visibility="invisible">        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="@android:color/holo_blue_light"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="0.5"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="@android:color/holo_blue_light"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="0.5"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="@android:color/holo_blue_light"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="0.5"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="@android:color/holo_blue_light"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="0.5"/>        <TextView            android:layout_width="0px"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="@android:color/holo_blue_light"/>    </LinearLayout></FrameLayout>

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content">    <TextView        android:id="@+id/tv_footer"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gravity="center"        android:text="Loading"/></FrameLayout>


Java代码如下

package com.lihao.widget;import android.content.Context;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.animation.Animation;import android.view.animation.LinearInterpolator;import android.view.animation.TranslateAnimation;import android.widget.AbsListView;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;import android.widget.TextView;import android.util.AttributeSet;import android.R.color;import com.lihao.R;public class RefreshAndLoadListView extends ListView implements OnScrollListener {    Context context;    LayoutInflater inflater;    OnRefreshAndLoadListener listener;    FrameLayout.LayoutParams params;    FrameLayout header;    FrameLayout footer;    TextView drag_header;    TextView tv_footer;    LinearLayout refresh_header;    TranslateAnimation animation;    boolean isRefreshing = false;    boolean isLoading = false;    boolean isLoadingOver = false;    boolean pressFromTop = true;    boolean isLastItemVisible;    int pressPosition;    int distanceDown;    int firstVisibleItem;    int listViewWidth;    private final int HEADER_HEIGHT = 10;   // in pix    private final int FOOTER_HEIGHT = 100;  // in pix    private final int ANIM_DURATION = 300;  // in milliseconds    private final int DRAG_THRESHOLD = 400; // in pix    private final float ANIM_OFFSET = (1 + 0.5f) / (5 + 4*0.5f) / 2;    public RefreshAndLoadListView(Context context) {        super(context);        init(context);    }    public RefreshAndLoadListView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context);    }    public RefreshAndLoadListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context);    }        private void init(Context context) {        this.context = context;        inflater = LayoutInflater.from(context);        header = (FrameLayout) inflater.inflate(R.layout.lv_refresh_and_load_header, null);        footer = (FrameLayout) inflater.inflate(R.layout.lv_refresh_and_load_footer, null);        drag_header = (TextView) header.findViewById(R.id.drag_header);        tv_footer = (TextView) footer.findViewById(R.id.tv_footer);        refresh_header = (LinearLayout) header.findViewById(R.id.refresh_header);        this.addHeaderView(header);        this.addFooterView(footer);        setFooterDividersEnabled(false);        setHeaderDividersEnabled(false);        params = (FrameLayout.LayoutParams) drag_header.getLayoutParams();        params.height = HEADER_HEIGHT;        drag_header.setLayoutParams(params);        params = (FrameLayout.LayoutParams) tv_footer.getLayoutParams();        params.height = FOOTER_HEIGHT;        tv_footer.setLayoutParams(params);        params = (FrameLayout.LayoutParams) refresh_header.getLayoutParams();        params.height = HEADER_HEIGHT;        refresh_header.setLayoutParams(params);        this.setOnScrollListener(this);        animation =  new TranslateAnimation(                Animation.RELATIVE_TO_PARENT, -ANIM_OFFSET,                Animation.RELATIVE_TO_PARENT, ANIM_OFFSET,                Animation.RELATIVE_TO_PARENT, 0f,                Animation.RELATIVE_TO_PARENT, 0f);        animation.setRepeatCount(Animation.INFINITE);        animation.setRepeatMode(Animation.RESTART);        animation.setInterpolator(new LinearInterpolator());        animation.setDuration(ANIM_DURATION);        animation.setFillAfter(false);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                pressFromTop = (header.getTop() == 0) && (firstVisibleItem == 0);                pressPosition = (int) ev.getY();                if (animation.hasStarted()) {                    refresh_header.clearAnimation();                    refresh_header.setVisibility(INVISIBLE);                }                break;            case MotionEvent.ACTION_MOVE:                if (pressFromTop) {                    setPressed(false);                    for (int i = 0; i < ev.getHistorySize(); i++) {                        distanceDown = (int) ev.getHistoricalY(i) - pressPosition;                        if (!isRefreshing) {                            onPreRefresh(distanceDown);                            if (distanceDown > DRAG_THRESHOLD) {                                onRefresh();                                return true;                            }                        }                    }                    if (distanceDown > 0) {                        return true;                    }                }                break;            case MotionEvent.ACTION_UP:                if (pressFromTop) {                    distanceDown = 0;                    onPreRefresh(distanceDown);                }        }        return super.onTouchEvent(ev);    }    private void onPreRefresh(int distanceDown) {        if (isRefreshing) return;        drag_header.setVisibility(VISIBLE);        header.setBackgroundColor(color.white);        refresh_header.setVisibility(INVISIBLE);        listViewWidth = header.getMeasuredWidth();        params = (FrameLayout.LayoutParams) drag_header.getLayoutParams();        params.width = distanceDown * listViewWidth / DRAG_THRESHOLD;        drag_header.setLayoutParams(params);    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if (scrollState == SCROLL_STATE_IDLE && isLastItemVisible) {            onLoad();        }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        this.firstVisibleItem = firstVisibleItem;        isLastItemVisible = ((firstVisibleItem + visibleItemCount) == totalItemCount);    }    /**     * 设置listener     */    public void setOnRefreshAndLoadListener(OnRefreshAndLoadListener listener) {        this.listener = listener;    }    /**     * 外部通知ListView数据更新的状态     */    public void onRefreshComplete() {        isRefreshing = false;        refresh_header.clearAnimation();        refresh_header.setVisibility(INVISIBLE);    }    public void onLoadComplete() {        isLoading = false;    }    public void onLoadOver() {        isLoadingOver = true;        tv_footer.setText("No More Data.");    }    public void onError() {        tv_footer.setText("Unknown Error.");    }    /**     * ListView 通过 callback interface 发出更新数据的指令     */    private void onRefresh() {        if (isRefreshing) return;        isRefreshing = true;        drag_header.setVisibility(INVISIBLE);        refresh_header.setVisibility(VISIBLE);        refresh_header.startAnimation(animation);        if (listener != null) {            listener.onRefresh();        }    }    private void onLoad() {        if (isLoading || isLoadingOver) return;        isLoading = true;        if (listener != null) {            listener.onLoad();        }    }    /**     * callback interface     */    public interface OnRefreshAndLoadListener {        public void onRefresh();        public void onLoad();    }}



作者:李浩。

转载请注明出处。

0 0