ListView的私人订制

来源:互联网 发布:淘宝红包怎样设 编辑:程序博客网 时间:2024/05/17 06:21

转载请注明出处: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