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

实现思路:

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:点击打开链接












猜你喜欢

转载自blog.csdn.net/fuckluy/article/details/53227600