关闭

ListView的私人订制

标签: listview下拉刷新上拉加载listview扩展
1208人阅读 评论(2) 收藏 举报
分类:

转载请注明出处:http://blog.csdn.net/magic_jss/article/details/52369091
现在开发中Android RecyclerView可能用的比较多,不过ListView作为常用控件学习它的使用和扩展也是十分重要的。简单封装了一个下拉刷新和上拉加载的ListView,你是否也想有个私人订制的ListView呢?或许这篇文章能够帮到你,如有问题恳请指正!欢迎评论哦!

效果图:

这里写图片描述

由于电脑和模拟器的原因可能不太清晰及略卡顿,真机上则很清晰及流畅。

1、自定义ListView

直接上代码

/**
 * Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview
 */
public class PullDownRefurbishLoadListView extends ListView implements
        OnScrollListener, OnClickListener {

    /**
     * head view
     */
    private View headView;
    /**
     * head view height
     */
    private int headViewHeight;
    /**
     * 是否可以下滑刷新
     */
    private boolean isPullDownRefurbish = false;
    /**
     * 文本状态描述
     */
    private TextView tev_status;
    /**
     * 进度条
     */
    private ImageView progressBar;
    /**
     * foot view
     */
    private View footView;
    /**
     * foot view height
     */
    private int footViewHeight;
    /**
     * 是否可以上拉加载
     */
    private boolean isPullHighLoad = false;
    /**
     * 底部布局
     */
    LinearLayout layout_listviewFoot;
    /**
     * 底部文本状态描述
     */
    private TextView tev_status_foot;
    /**
     * 进度条
     */
    ImageView progressBar_foot;
    /**
     * 按下后的初始Y位置
     */
    private float beginY = 0;
    /**
     * 移动的距离
     */
    private int moveY = 0;
    /**
     * 正常状态
     */
    private final static int NONE = 0;
    /**
     * 下拉/上拉状态
     */
    private final static int PULL = 1;
    /**
     * 释放刷新状态
     */
    private final static int RELEASE = 2;
    /**
     * 刷新状态
     */
    private final static int REFURBISH = 3;
    /**
     * 状态
     */
    private static int STATUS;
    /**
     * 是否允许下拉刷新
     */
    private boolean isRefurbishAble = true;
    /**
     * 是否允许上拉加载
     */
    private boolean isLoadAble = true;
    /**
     * context
     */
    private Context context;
    /**
     * 动画
     */
    private RotateAnimation rotateAnimation, rotateAnimation2;
    /**
     * 接口
     */
    private IPullDownRefurbishLoadListView refurbishLoadListView;

    public PullDownRefurbishLoadListView(Context context) {
        super(context);
        init(context);
    }

    public PullDownRefurbishLoadListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PullDownRefurbishLoadListView(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 添加head/foot布局
     * 
     * @param context
     */
    private void init(Context context) {
        headView = LayoutInflater.from(context).inflate(R.layout.listview_head,
                null);
        this.addHeaderView(headView);
        // 设置滑动监听
        this.setOnScrollListener(this);
        headView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        headViewHeight = headView.getMeasuredHeight();
        // 设置headView 偏移出屏幕
        headView.setPadding(0, -headViewHeight, 0, 0);

        tev_status = (TextView) findViewById(R.id.tev_listviewHead_status);
        progressBar = (ImageView) findViewById(R.id.prb_listviewHead_refurbish);

        footView = LayoutInflater.from(context).inflate(
                R.layout.listview_footer, null);
        this.addFooterView(footView);
        footView.measure(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        footViewHeight = footView.getMeasuredHeight();

        layout_listviewFoot = (LinearLayout) footView
                .findViewById(R.id.layout_listviewFoot);
        tev_status_foot = (TextView) footView
                .findViewById(R.id.tev_listviewFoot_state);
        progressBar_foot = (ImageView) findViewById(R.id.prb_listviewFoot_load);
        tev_status_foot.setOnClickListener(this);
        this.context = context;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:

            beginY = ev.getY();

            if (STATUS == REFURBISH) {
                // 不消耗事件
                return false;
            }

        case MotionEvent.ACTION_MOVE:

            this.moveY = (int) (ev.getY() - beginY);

            if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
                if (moveY > 0) {
                    if (moveY > headViewHeight) {
                        STATUS = RELEASE;
                        if (moveY >= (headViewHeight + dp2px(20, context))) {
                            moveY = headViewHeight + dp2px(20, context);
                        }
                    } else if (moveY > 0 && moveY <= headViewHeight) {
                        STATUS = PULL;
                    } else {
                        STATUS = NONE;
                    }
                    setRefurbishByStatus((int) moveY);
                }
            }

            if (isLoadAble && isPullHighLoad && moveY < 0) {
                tev_status_foot.setVisibility(View.GONE);
                progressBar_foot.setVisibility(View.VISIBLE);
                if (Math.abs(moveY) > footViewHeight) {
                    STATUS = RELEASE;
                } else if (Math.abs(moveY) > 0
                        && Math.abs(moveY) <= footViewHeight) {
                    STATUS = PULL;
                } else {
                    STATUS = NONE;
                }
            }

            break;

        case MotionEvent.ACTION_UP:
            if (isRefurbishAble && isPullDownRefurbish && moveY >= 0) {
                switch (STATUS) {
                case PULL:
                    moveY = 0;
                    setRefurbishByStatus(-headViewHeight);
                    break;
                case RELEASE:
                    STATUS = REFURBISH;
                    setRefurbishByStatus((int) moveY);
                    if (refurbishLoadListView != null) {
                        refurbishLoadListView.refurbish();
                    }
                    break;

                }
            }

            if (isLoadAble && isPullHighLoad && moveY < 0) {
                switch (STATUS) {
                case PULL:
                    moveY = 0;
                    STATUS = NONE;
                    tev_status_foot.setVisibility(View.VISIBLE);
                    progressBar_foot.setVisibility(View.GONE);
                    break;
                case RELEASE:
                    STATUS = REFURBISH;
                    progressBar_foot.clearAnimation();
                    if (rotateAnimation2 != null) {
                        rotateAnimation2.cancel();
                    }
                    setAnimationToProgressBarFoot();
                    break;
                }
            }
            break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 设置head布局的上内边距
     * 
     * @param size
     */
    private void setHeadPaddingTop(int size) {
        size = size + (-headViewHeight);
        headView.setPadding(0, size, 0, 0);
    }

    /**
     * 根据状态设置刷新HeadView显示的内容
     */
    private void setRefurbishByStatus(int moveY) {
        switch (STATUS) {
        case NONE:
            tev_status.setText("下拉刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_pull);
            setHeadPaddingTop(-headViewHeight);
            break;
        case PULL:
            tev_status.setText("下拉刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_pull);
            setHeadPaddingTop(moveY);
            break;
        case RELEASE:
            tev_status.setText("释放刷新");
            progressBar.setImageResource(R.drawable.ic_ptr_release);
            setHeadPaddingTop(moveY);
            break;
        case REFURBISH:
            tev_status.setText("刷新中");
            progressBar.setImageResource(R.drawable.ic_ptr_loading);
            setHeadPaddingTop(headViewHeight);

            if (rotateAnimation == null) {
                rotateAnimation = new RotateAnimation(0.0f, 180.0f,
                        Animation.RELATIVE_TO_SELF, 0.5f,
                        Animation.RELATIVE_TO_SELF, 0.5f);
                rotateAnimation.setDuration(150);
                rotateAnimation.setRepeatCount(-1);
            }
            progressBar.setAnimation(rotateAnimation);
            rotateAnimation.start();
            break;
        }
    }

    /**
     * 设置对外公开接口
     * 
     * @param pullDownRefurbish
     */
    public void setIPullDownRefurbish(
            IPullDownRefurbishLoadListView refurbishLoadListView) {
        this.refurbishLoadListView = refurbishLoadListView;
    }

    /**
     * 刷新完成执行
     */
    public void setPullDownRefurbishFinish() {
        moveY = 0;
        STATUS = NONE;
        setRefurbishByStatus((int) moveY);
        progressBar.clearAnimation();
        rotateAnimation.cancel();
    }

    /**
     * 加载完成执行
     */
    public void setPullDownLoadFinish() {
        moveY = 0;
        STATUS = NONE;
        progressBar_foot.clearAnimation();
        rotateAnimation2.cancel();
        progressBar_foot.setVisibility(View.GONE);
        tev_status_foot.setVisibility(View.VISIBLE);
    }

    /**
     * 设置是否允许下拉刷新
     * 
     * @param isRefurbishAble
     */
    public void setRefurbishAble(boolean isRefurbishAble) {
        this.isRefurbishAble = isRefurbishAble;
    }

    /**
     * 设置是否可以上拉加载
     * 
     * @param isLoadAble
     */
    public void setLoadAble(boolean isLoadAble) {
        this.isLoadAble = isLoadAble;
        if (!isLoadAble) {
            layout_listviewFoot.setVisibility(View.GONE);
        }
    }

    @Override
    public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
        // 参数:
        // 查看其滚动状态的视图
        // firstvisibleitem -第一个可见的细胞指数(忽略如果visibleitemcount = = 0)
        // visibleitemcount -可见细胞数
        // totalitemcount -在列表适配器项目数

        // arg1为0时 列表在最顶部
        isPullDownRefurbish = arg1 == 0 ? true : false;
        // arg1为最后一个时arg1==arg3
        isPullHighLoad = (arg1 + arg2) == arg3 ? true : false;
    }

    @Override
    public void onScrollStateChanged(AbsListView arg0, int arg1) {
    }

    /**
     * dp转px
     */
    private int dp2px(float value, Context context) {
        final float scale = context.getResources().getDisplayMetrics().densityDpi;
        return (int) (value * (scale / 160) + 0.5f);
    }

    /**
     * 为progressBar_foot设置动画
     */
    private void setAnimationToProgressBarFoot() {
        if (rotateAnimation2 == null) {
            rotateAnimation2 = new RotateAnimation(0.0f, 180.0f,
                    Animation.RELATIVE_TO_SELF, 0.5f,
                    Animation.RELATIVE_TO_SELF, 0.5f);
            rotateAnimation2.setDuration(150);
            rotateAnimation2.setRepeatCount(-1);
        }
        progressBar_foot.setAnimation(rotateAnimation2);
        rotateAnimation2.start();
        if (refurbishLoadListView != null) {
            refurbishLoadListView.load();
        }
    }

    @Override
    public void onClick(View v) {
        // 点击查看更多
        tev_status_foot.setVisibility(View.GONE);
        progressBar_foot.setVisibility(View.VISIBLE);
        setAnimationToProgressBarFoot();
    }

    /**
     * 接口
     */
    interface IPullDownRefurbishLoadListView {
        /**
         * 刷新事件回调
         */
        void refurbish();

        /**
         * 加载回调
         */
        void load();
    }

}

以上代码主要步骤:

  • 初始化的时候添加HeadView、FootView。
  • 继承ListView实现OnScrollListener接口,重写onScroll方法,因为onScroll方法在ListView滑动的时候会一直回调,因此在onScroll方法中判断是否处于ListView的顶部/底部,从而处理下拉刷新/上拉加载的展现时机。
  • 重写onTouchEvent方法,在按下、滑动、抬起的时候动态处理HeadView、FootView的展现。
  • 添加回调接口,设置回调方法。

    注释比较清楚,不在赘述。

2、xml文件

主布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.magic.test_listviewrefurbish.PullDownRefurbishLoadListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

layout/listview_head.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:paddingBottom="20dp"
        android:paddingTop="20dp" >

        <ImageView
            android:id="@+id/prb_listviewHead_refurbish"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_ptr_pull" />

        <TextView
            android:id="@+id/tev_listviewHead_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="下拉刷新"
            android:textColor="#afafaf"
            android:textSize="12sp" />
    </LinearLayout>

</LinearLayout>

listview_footer.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/layout_listviewFoot"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:paddingBottom="15dp"
        android:paddingTop="15dp" >

        <TextView
            android:id="@+id/tev_listviewFoot_state"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="查看更多"
            android:textColor="@android:color/darker_gray" />

        <ImageView
            android:id="@+id/prb_listviewFoot_load"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_ptr_loading"
            android:visibility="gone" />
    </LinearLayout>

</LinearLayout>

3、Activity中使用

/**
 * Created by magic on 2016年5月12日.带下拉刷新/上拉加载的listview
 */
public class MainActivity extends Activity implements OnItemClickListener {

    PullDownRefurbishLoadListView listView;
    MyAdapter adapter;
    List<String> list = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        listView = (PullDownRefurbishLoadListView) findViewById(R.id.listview);
        list.add("a");
        adapter = new MyAdapter(this, list);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(this);
        //设置是否可以下拉刷新,默认为true
        listView.setRefurbishAble(true);
        //设置是否可以上拉加载,默认为true
        listView.setLoadAble(true);

        listView.setIPullDownRefurbish(new IPullDownRefurbishLoadListView() {

            @Override
            public void refurbish() {
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        list.add(0, "c");
                        adapter.notifyDataSetChanged();
                        listView.setPullDownRefurbishFinish();
                    }
                }, 2000);
            }

            @Override
            public void load() {
                new Handler().postDelayed(new Runnable() {

                    @Override
                    public void run() {
                        list.add("b");
                        adapter.notifyDataSetChanged();
                        listView.setPullDownLoadFinish();
                    }
                }, 2000);
            }
        });
    }

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        Toast.makeText(this, "Hello  " + arg2, Toast.LENGTH_SHORT).show();
    }
}

Adapter比较简单就不写了!

整个项目下载地址:http://download.csdn.net/detail/magic_jss/9616947

END!

5
3

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:53187次
    • 积分:950
    • 等级:
    • 排名:千里之外
    • 原创:38篇
    • 转载:0篇
    • 译文:0篇
    • 评论:36条
    最新评论