ListView的下拉刷新、滑动删除和上拉加载更多

来源:互联网 发布:python 2.7不支持中文 编辑:程序博客网 时间:2024/05/16 05:44

实现思路:

1、在ListView中添加header并在开始时隐藏,通过设置header的topPadding为负的header的高度,实现该效果

2、监听手势(用onTouchEvent),先判断ListView是否已经到达顶部,到达顶部以后根据滑动幅度(手指还没有抬起来)可分为两种状态,一种是幅度不够,则松开手指后LiveView恢复原样,一种是下拉幅度够了则更改header中的View信息,第三种状态是正在刷新,在松开手指时更新为该状态

3、ListView的滑动监听,如果在滑动时为状态3,则开启线程更新ListView中的数据(借助handler)

效果图:






header布局:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <!--ListView的头部布局-->    <FrameLayout        android:id="@+id/fl"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:paddingLeft="120dp">        <ImageView            android:id="@+id/refresh"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:src="@drawable/pull_to_refresh_arrow" />        <ProgressBar            android:id="@+id/progress"            style="@style/Widget.AppCompat.ProgressBar"            android:layout_gravity="center"            android:max="100"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:visibility="gone" />    </FrameLayout>       <LinearLayout        android:id="@+id/ly"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_toRightOf="@id/fl"        android:gravity="center_horizontal"        android:orientation="vertical"        android:paddingBottom="10dp"        android:paddingLeft="10dp"        android:paddingRight="10dp"        android:paddingTop="10dp">        <TextView            android:id="@+id/tip"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:gravity="center_horizontal"            android:text="下拉刷新"            android:textSize="15sp" />        <TextView            android:id="@+id/update_last_time"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:gravity="center_horizontal" />    </LinearLayout></RelativeLayout>

mainActivity布局:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.he.sample.MainActivity">    <com.example.he.sample.myListView        android:id="@+id/lv"        android:layout_width="match_parent"        android:layout_height="wrap_content"></com.example.he.sample.myListView></RelativeLayout>

myListView:

/** * header下拉时的三种种状态,UN_PREPARE表示滑动的幅度不够不需要刷新,PREPARE表示的含义是现在松手就能刷新,REFRESH表示正在刷新 */enum State {    UN_PREPARE, PREPARE, REFRESH}public class myListView extends ListView {    private View header;    private int headerHeight;    private int startY;    private boolean top;//用于判断是否在顶部滑动    private boolean firstState = true;//是否是第一次进行状态判断    private State state = State.UN_PREPARE;//滑动的状态,用于listView滑动事件的处理,见MainActivity.class    private TextView title;    private ImageView image;    private ProgressBar bar;    public myListView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context);    }    public myListView(Context context) {        super(context);        initView(context);    }    public myListView(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    /**     * 加载header视图     *     * @param context     */    private void initView(Context context) {        header = LayoutInflater.from(context).inflate(R.layout.head, null);        title = (TextView) header.findViewById(R.id.tip);        image = (ImageView) header.findViewById(R.id.refresh);        bar = (ProgressBar) header.findViewById(R.id.progress);        header.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);//测量head        headerHeight = header.getMeasuredHeight();//获取高度        topPadding(-headerHeight);        this.addHeaderView(header);    }    /**     * 修改header的PaddingTop值达到隐藏header、随着滑动慢慢出现的效果     *     * @param topPadding     */    protected void topPadding(int topPadding) {        header.setPadding(header.getPaddingLeft(), topPadding,                header.getPaddingRight(), header.getPaddingBottom());        header.invalidate();    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                int t = this.getFirstVisiblePosition();                //t为0表示到达屏幕顶部                if (t == 0) {                    top = true;                    startY = (int) ev.getY();                }                break;            case MotionEvent.ACTION_UP:                top = false;                firstState = true;                //在状态2时松手则切换到状态3的视图                if (state == State.PREPARE)                    refreshView(State.REFRESH, 0);                //在状态1时松手则恢复原样                if (state == State.UN_PREPARE)                    topPadding(-headerHeight);                break;            case MotionEvent.ACTION_MOVE:                if (top)                    onMove(ev);                break;        }        return super.onTouchEvent(ev);    }    /**     * 手指正在滑动时进行状态判断     * @param event     */    private void onMove(MotionEvent event) {        int lastY = (int) event.getY();        int space = lastY - startY;        int padding = space - headerHeight;        Log.i("padding", "" + padding);        //状态1        if (padding < 30) {            Log.i("state", "1");            if (firstState)                refreshView(State.UN_PREPARE, padding);        }        //状态2        else if (padding > 30 && padding < 100) {            firstState = false;            refreshView(State.PREPARE, padding);        }    }    /**     * 根据不同的状态,完成相应的操作     */    private void refreshView(State s, int padding) {        switch (s) {            case UN_PREPARE:                topPadding(padding);                state = State.UN_PREPARE;//更新状态                bar.setVisibility(View.GONE);                image.setVisibility(View.VISIBLE);                title.setText("下拉刷新");                break;            case PREPARE:                image.setVisibility(View.VISIBLE);                bar.setVisibility(View.GONE);                topPadding(padding);                state = State.PREPARE;//更新状态                //更新header中的视图                /**                 * 创建旋转动画达到向下的箭头朝上的目的,旋转180度,以自身为中心                 */                RotateAnimation animation = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5F, RotateAnimation.RELATIVE_TO_SELF, 0.5F);                animation.setDuration(0);//0毫秒内完成效果               animation.setFillAfter(true);//图片的显示为执行动画后的样子                image.startAnimation(animation);                title.setText("松手进行刷新");                topPadding(padding);                break;            case REFRESH:                image.setVisibility(View.GONE);//隐藏image                bar.setVisibility(View.VISIBLE);//显示bar                //更新header中的视图                image.clearAnimation();//清除image上的动画                title.setText("正在刷新");                state = State.REFRESH;//更新状态                break;        }    }    public int getHeaderHeight() {        return headerHeight;    }    public State getState() {        return state;    }}

MainActivity:

public class MainActivity extends AppCompatActivity {    private static final int OK = 1;    private myListView listView;    private ArrayAdapter<Integer> adapter;    private int headerHeight;    private List<Integer> list;    private Random random = new Random(47);//随机数    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case OK:                    adapter.notifyDataSetChanged();//刷新数据                    listView.topPadding(-headerHeight);//隐藏header                    break;            }        }    };    @Override    protected void onCreate(final Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        listView = (myListView) findViewById(R.id.lv);        headerHeight = listView.getHeaderHeight();        list = new ArrayList<Integer>();        initList();        adapter = new ArrayAdapter<Integer>(this, android.R.layout.simple_list_item_1, list);        listView.setAdapter(adapter);        /**         * listView的滑动监听         */        listView.setOnScrollListener(new AbsListView.OnScrollListener() {            @Override            public void onScrollStateChanged(AbsListView view, int scrollState) {                //正在刷新则刷新数据                if (listView.getState() == State.REFRESH) {                    onRefresh();                }            }            @Override            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {            }        });    }    private void initList() {        for (int i = 0; i < 50; i++) {            list.add(random.nextInt(50));        }    }    /**     * 更新数据     */    private void onRefresh() {        new Thread(new Runnable() {            @Override            public void run() {                Message message = new Message();                message.what = OK;                for (int i : list) {                    list.set(i, random.nextInt(50));                }                handler.sendMessageDelayed(message, 2000);//2s以后发送message            }        }).start();    }}

源码地址:点击打开链接

在自己实现的下拉刷新的基础上添加了ListView的滑动删除,关于滑动删除的教程请看这篇文章:点击打开链接,但是这位博主的代码是不适合添加了header的ListView的,如果完全按文中代码加到我这个项目中会出现部分item无法滑动的问题,只需将文中的

 //我们想知道当前点击了哪一行              int position = pointToPosition(x, y);              if (position != INVALID_POSITION) {                  DataHolder data = (DataHolder) getItemAtPosition(position);                  itemRoot = data.rootView;              }  
修改为

int position = pointToPosition(x, y);int firstPosition = getFirstVisiblePosition();if (position != INVALID_POSITION) {curView = (ScrollDeleteLinearLayout) getChildAt(position - firstPosition);}




其实官方给我们提供了SwipeRefreshLayout可用于ListView的刷新,它已经帮我们把内部实现封装好了,Demo:点击打开链接


ListView的上拉加载更多和下拉刷新的代码基本上是一样的,只不过不是添加header而是添加footer,其他实现基本相同,有个要注意的地方是,由于ListView添加数据能直接显示出来,所以添加的位置要做变动否则看不出效果

下拉加载更多的Demo:点击打开链接












0 0
原创粉丝点击