美文网首页
ListView全解析

ListView全解析

作者: fastcv | 来源:发表于2019-07-07 22:11 被阅读0次

    前言

    ListView作为一个基本过去式的组件,作用就不在这里再说了,直接开始我们的总结。

    常用属性

    属性 说明
    android:listSelector="@color/pink" listView item 选中时的颜色
    android:divider="#f9b68b" 分割线颜色(android:divider="@drawable/@null" 不想显示分割线)
    android:dividerHeight="1dp" 分割线边距
    android:scrollbars="none" 不显示滚动条
    android:fadingEdge="none" 去掉上边和下边黑色的阴影
    android:transcriptMode="alwaysScroll" 通过设置的控件transcriptMode属性可以将Android平台的控件(支持ScrollBar)自动滑动到最底部。

    使用

    废话不多说,先来效果图:


    listview.gif

    简单的使用教程网上有许多,现在我们实现的是自定义的Listview(下拉刷新和上拉加载),适配器使用自定义的万能Listview适配器,分两步进行:

    1、自定义Listview

    1、继承Listview,重写构造方法

    public class RefreshListView extends ListView {
    
    
        public RefreshListView(Context context) {
            super(context);
        }
    
        public RefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    }
    

    2、初始化HeaderView和FooterView

    ListView提供两个方法addFooterView和addHeaderView去添加头View和尾部View

    private void initFooterView() {
            this.setOnScrollListener(this);
            mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
            this.addFooterView(mFooterView);
            tv_pull_list_header_title = mFooterView.findViewById(R.id.tv_pull_list_header_title);
            pb_pull_list_header = mFooterView.findViewById(R.id.pb_pull_list_header);
            mFooterView.measure(0,0);
            mFooterViewHeight = mFooterView.getMeasuredHeight();   //得到FooterView的高度
            mFooterView.setPadding(0,0,0,0-mFooterViewHeight);   //隐藏FooterView
        }
    
        private void initHeaderView() {
            mHearder = View.inflate(getContext(), R.layout.refresh_listview_header, null);
            this.addHeaderView(mHearder);
            refresh_tips = mHearder.findViewById(R.id.refresh_tips);
            refresh_last_time = mHearder.findViewById(R.id.refresh_last_time);
            ivArrow = mHearder.findViewById(R.id.ivArrow);
            pbWaiting = mHearder.findViewById(R.id.pbWaiting);
            mHearder.measure(0,0);
            mHeaderHeight = mHearder.getMeasuredHeight();   //得到HeaderView的高度
            mHearder.setPadding(0, 0-mHeaderHeight,0,0);    //隐藏HeaderView
        }
    

    3、重写onTouchEvent方法监听HeaderView的状态

    这里的逻辑是,拿到点击时的y坐标,在移动的时候去得到偏移量,然后和我们我HeaderView的高度进行运算得到padding,这个值即为我们HeaderView需要隐藏的高度

    @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                {
                    if (valueAnimator.isRunning())
                        valueAnimator.end();
                    startY = (int) ev.getY();
                    Log.e("SayHallo","MotionEvent.ACTION_DOWN startY = " + startY);
                }
                break;
                case MotionEvent.ACTION_MOVE:
                {
                    Log.e("SayHallo","MotionEvent.ACTION_MOVE");
                    if (startY == -1) {// 确保startY有效
                        startY = (int) ev.getY();
                    }
    
                    if(mCurrrentState == LoadState.STATE_REFRESHING) break;
    
                    endY = (int) ev.getY();
                    moveY = px2dp(endY - startY,getContext());
    
                    if( moveY > 0 && getFirstVisiblePosition() == 0){
                        // 计算padding
                        padding = moveY-mHeaderHeight;
                        if(padding < 1)  //预留位置
                          mHearder.setPadding(0,padding,0,0);
    
                        if (padding > 0 && mCurrrentState != LoadState.STATE_RELEASE_REFRESH )
                        {
                            mCurrrentState = LoadState.STATE_RELEASE_REFRESH;
                            refreshState();
                        }else if (padding < 0 && mCurrrentState != LoadState.STATE_PULL_REFRESH) {// 改为下拉刷新状态
                            mCurrrentState = LoadState.STATE_PULL_REFRESH;
                            refreshState();
                        }
                        return true;
                    }
    
    
                }
                break;
                case MotionEvent.ACTION_UP:
                {
                    Log.e("SayHallo","padding = " + padding);
                    if (mCurrrentState == LoadState.STATE_RELEASE_REFRESH)
                    {
    
                        mCurrrentState = LoadState.STATE_REFRESHING;
                        mHearder.setPadding(0,0,0,0);
                        refreshState();
                    }else if (mCurrrentState == LoadState.STATE_PULL_REFRESH){
                        if (padding != 0)
                           scroll_Start(padding);
                    }
    
                    startY = -1;   //重置
                    padding = 0;
    
                }
                break;
                default:
                   break;
            }
            return super.onTouchEvent(ev);
        }
    

    4、实现onScrollStateChanged方法监听FooterView的状态

    @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            Log.e("SayHallo","到底了.....");
            if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
                    || scrollState == OnScrollListener.SCROLL_STATE_FLING) {
    
                if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
                    Log.e("SayHallo","到底了.....");
    //                mFooterView.setPadding(0, 0, 0, 0);// 显示
                    setSelection(getCount() - 1);// 改变listview显示位置
    
                    isLoadingMore = true;
    
                    if (mListener != null) {
                        mListener.onLoadMore();
                    }
                }
            }
        }
    

    完整的代码如下:

    public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
    
        //头View中的一些组件
        private View mHearder;
        private TextView refresh_tips;   //显示文字(刷新状态)
        private TextView refresh_last_time;   //显示时间(刷新完成)
        private ImageView ivArrow;   //指向图
        private ProgressBar pbWaiting;   //刷新的圈圈
        private int mHeaderHeight;   //头View的测量高度
    
        //脚View中的一些组件
        private View mFooterView;
        private TextView tv_pull_list_header_title;   //显示文字(加载状态)
        private ProgressBar pb_pull_list_header;    //刷新的圈圈
        private int mFooterViewHeight;   //脚View的测量高度
    
        private int startY = -1;   //按下时的Y坐标(相对于屏幕的绝对坐标)
        private LoadState mCurrrentState = LoadState.STATE_PULL_REFRESH;
        private int endY;
        private int moveY;
        private ValueAnimator valueAnimator;
        private int padding = 0;
    
        private int lastEndY = 0;
    
        public RefreshListView(Context context) {
            super(context);
            initHeaderView();
            initFooterView();
            initArrowAnim();
        }
    
        public RefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initHeaderView();
            initFooterView();
            initArrowAnim();
        }
    
        public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initHeaderView();
            initFooterView();
            initArrowAnim();
        }
    
    
        private void initFooterView() {
            this.setOnScrollListener(this);
            mFooterView = View.inflate(getContext(), R.layout.refresh_listview_footer, null);
            this.addFooterView(mFooterView);
            tv_pull_list_header_title = mFooterView.findViewById(R.id.tv_pull_list_header_title);
            pb_pull_list_header = mFooterView.findViewById(R.id.pb_pull_list_header);
            mFooterView.measure(0,0);
            mFooterViewHeight = mFooterView.getMeasuredHeight();
            mFooterView.setPadding(0,0,0,0-mFooterViewHeight);
        }
    
        private void initHeaderView() {
            mHearder = View.inflate(getContext(), R.layout.refresh_listview_header, null);
            this.addHeaderView(mHearder);
            refresh_tips = mHearder.findViewById(R.id.refresh_tips);
            refresh_last_time = mHearder.findViewById(R.id.refresh_last_time);
            ivArrow = mHearder.findViewById(R.id.ivArrow);
            pbWaiting = mHearder.findViewById(R.id.pbWaiting);
            mHearder.measure(0,0);
            mHeaderHeight = mHearder.getMeasuredHeight();
            mHearder.setPadding(0, 0-mHeaderHeight,0,0);
        }
    
        private void initArrowAnim() {
            valueAnimator = ValueAnimator.ofInt(0, 0);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction())
            {
                case MotionEvent.ACTION_DOWN:
                {
                    if (valueAnimator.isRunning())
                        valueAnimator.end();
                    startY = (int) ev.getY();
                    Log.e("SayHallo","MotionEvent.ACTION_DOWN startY = " + startY);
                }
                break;
                case MotionEvent.ACTION_MOVE:
                {
                    Log.e("SayHallo","MotionEvent.ACTION_MOVE");
                    if (startY == -1) {// 确保startY有效
                        startY = (int) ev.getY();
                    }
    
                    if(mCurrrentState == LoadState.STATE_REFRESHING) break;
    
                    endY = (int) ev.getY();
                    moveY = px2dp(endY - startY,getContext());
    
                    if( moveY > 0 && getFirstVisiblePosition() == 0){
                        // 计算padding
                        padding = moveY-mHeaderHeight;
                        if(padding < 1)  //预留位置
                          mHearder.setPadding(0,padding,0,0);
    
                        if (padding > 0 && mCurrrentState != LoadState.STATE_RELEASE_REFRESH )
                        {
                            mCurrrentState = LoadState.STATE_RELEASE_REFRESH;
                            refreshState();
                        }else if (padding < 0 && mCurrrentState != LoadState.STATE_PULL_REFRESH) {// 改为下拉刷新状态
                            mCurrrentState = LoadState.STATE_PULL_REFRESH;
                            refreshState();
                        }
                        return true;
                    }
    
    
                }
                break;
                case MotionEvent.ACTION_UP:
                {
                    Log.e("SayHallo","padding = " + padding);
                    if (mCurrrentState == LoadState.STATE_RELEASE_REFRESH)
                    {
    
                        mCurrrentState = LoadState.STATE_REFRESHING;
                        mHearder.setPadding(0,0,0,0);
                        refreshState();
                    }else if (mCurrrentState == LoadState.STATE_PULL_REFRESH){
                        if (padding != 0)
                           scroll_Start(padding);
                    }
    
                    startY = -1;   //重置
                    padding = 0;
    
                }
                break;
                default:
                   break;
            }
            return super.onTouchEvent(ev);
        }
    
        //px转化为dp
        public static int px2dp(float pxValue, Context activity) {
            final float scale = activity.getResources().getDisplayMetrics().density;
            return (int) ((pxValue - 0.5f) / scale);
        }
    
        /**
         * 刷新下拉控件的布局
         */
        private void refreshState() {
            switch (mCurrrentState) {
                case STATE_PULL_REFRESH:
                    refresh_tips.setText("下拉刷新");
                    ivArrow.setVisibility(View.VISIBLE);
                    pbWaiting.setVisibility(View.INVISIBLE);
    //                ivArrow.startAnimation(animDown);
                    break;
                case STATE_RELEASE_REFRESH:
                    refresh_tips.setText("松开刷新");
                    ivArrow.setVisibility(View.VISIBLE);
                    pbWaiting.setVisibility(View.INVISIBLE);
    //                ivArrow.startAnimation(animUp);
                    break;
                case STATE_REFRESHING:
                    refresh_tips.setText("正在刷新...");
                    ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
                    ivArrow.setVisibility(View.INVISIBLE);
                    pbWaiting.setVisibility(View.VISIBLE);
    
                    if (mListener != null) {
                        mListener.onRefresh();
                    }
                    break;
    
                default:
                    break;
            }
        }
    
        OnRefreshListener mListener;
        private boolean isLoadingMore;
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            Log.e("SayHallo","到底了.....");
            if (scrollState == OnScrollListener.SCROLL_STATE_IDLE
                    || scrollState == OnScrollListener.SCROLL_STATE_FLING) {
    
                if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
                    Log.e("SayHallo","到底了.....");
    //                mFooterView.setPadding(0, 0, 0, 0);// 显示
                    setSelection(getCount() - 1);// 改变listview显示位置
    
                    isLoadingMore = true;
    
                    if (mListener != null) {
                        mListener.onLoadMore();
                    }
                }
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    
        }
    
    
        public interface OnRefreshListener {
             void onRefresh();
             void onLoadMore();// 加载下一页数据
        }
    
        public void setOnRefreshListener(OnRefreshListener listener) {
            mListener = listener;
        }
    
        /*
         * 收起下拉刷新的控件
         */
        public void onRefreshComplete(boolean success) {
            if (isLoadingMore) {// 正在加载更多...
                mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局
                isLoadingMore = false;
            } else {
                mCurrrentState = LoadState.STATE_PULL_REFRESH;
    
                ivArrow.setVisibility(View.VISIBLE);
                pbWaiting.setVisibility(View.INVISIBLE);
    
                scroll_Start(1);
    //            mHearder.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
    
                if (success) {
                    refresh_tips.setText("刷新成功");
                    refresh_last_time.setText("最后刷新时间:" + getCurrentTime());
                }
            }
        }
    
        /**
         * 获取当前时间
         */
        public String getCurrentTime() {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return format.format(new Date());
        }
    
        private void scroll_Start(int p) {
    
            valueAnimator.setIntValues(p,-mHeaderHeight);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
    
                    mHearder.setPadding(0,value,0,0);
                }
            });
            valueAnimator.setDuration(500);
            valueAnimator.start();
        }
    
        enum LoadState {
            STATE_PULL_REFRESH,     // 下拉刷新
            STATE_RELEASE_REFRESH ,     // 松开刷新
            STATE_REFRESHING        //正在刷新
        }
    }
    

    自定义万能Listview适配器

    1、首先,实现万能ViewHolder

    public class ListViewHolder {
    
        private SparseArray<View> mViews;
        private int mPosition;
        private View mConvertView;
        private Context context;
    
        public ListViewHolder(Context context, ViewGroup parent, int position, int layoutId) {
            this.mPosition = position;
            this.context = context;
            this.mViews = new SparseArray<View>();
            mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
            mConvertView.setTag(this);
    
        }
    
        public static ListViewHolder get(Context context, View convertView,
                                     ViewGroup parent,int position, int layoutId) {
    
            if (convertView == null) {
                return new ListViewHolder(context, parent, position, layoutId);
            } else {
                ListViewHolder holder = (ListViewHolder) convertView.getTag();
                return holder;
            }
        }
    
        /**
         * 通过viewId获取控件
         */
        public <T extends View> T getView(int viewId) {
    
            View view = mViews.get(viewId);
    
            if (view == null) {
                view = mConvertView.findViewById(viewId);
                mViews.put(viewId, view);
            }
    
            return (T) view;
    
        }
    
        public View getConvertView() {
            return mConvertView;
        }
    
        /**
         * 封装setText方法,设置TextView的值
         */
        public ListViewHolder setTextViewVualue(int viewId, String text) {
            TextView tv = getView(viewId);
            tv.setText(text);
            return this;
        }
    
        /**
         * 封装setText方法,设置TextView的值
         */
        public ListViewHolder setImageViewVualue(int viewId, int id) {
            ImageView iv = getView(viewId);
            iv.setImageDrawable(context.getResources().getDrawable(id));
            return this;
        }
    }
    

    2、实现万能适配器

    public abstract class AbsListViewAdapter<T> extends BaseAdapter {
    
        protected Context mContext;
        protected List<T> mDatas;
        protected LayoutInflater mInflater;
        protected int mLayoutId;
    
        public AbsListViewAdapter(Context context, List<T> datas, int LayoutId) {
            this.mContext = context;
            mInflater = LayoutInflater.from(context);
            this.mLayoutId = LayoutId;
            this.mDatas = datas;
        }
    
        @Override
        public int getCount() {
    
            return mDatas.size();
        }
    
        @Override
        public T getItem(int position) {
    
            return mDatas.get(position);
        }
    
        @Override
        public long getItemId(int position) {
    
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            ListViewHolder holder = ListViewHolder.get(mContext, convertView,
                    parent, position, mLayoutId);
    
            convert(holder, getItem(position));
    
            return holder.getConvertView();
        }
    
        public abstract void convert(ListViewHolder holder, T t);
    }
    

    实现Listview的显示

    1、实现实体类

    public class Enety{
    
            public Enety(String title, int icon) {
                this.title = title;
                this.icon = icon;
            }
    
            public String title;
            public int icon;
        }
    

    2、实现适配器

    class MyAdapter extends AbsListViewAdapter<Enety> {
    
            public MyAdapter(Context context, List<Enety> datas, int LayoutId) {
                super(context, datas, LayoutId);
            }
    
            @Override
            public void convert(ListViewHolder holder, Enety enety) {
                holder.setTextViewVualue(R.id.title, enety.title)
                        .setImageViewVualue(R.id.image, enety.icon);
            }
        }
    

    3、实现整个效果

    public class MainActivity extends AppCompatActivity {
    
        private RefreshListView listView;
        private MyAdapter adapter1;
        private ArrayList<Enety> eneties;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = findViewById(R.id.refreshlist);
            eneties = new ArrayList<>();
            for (int i = 0;i< 100 ; i++) {
                Enety enety = new Enety("这是标题"+i,R.mipmap.ic_launcher);
                eneties.add(enety);
            }
            adapter1 = new MyAdapter(this,eneties,R.layout.shouxinrenzhengliebiao);
            listView.setAdapter(adapter1);
            listView.setOnRefreshListener(new RefreshListView.OnRefreshListener() {
                @Override
                public void onRefresh() {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Enety enety = new Enety("下拉新增数据",R.mipmap.ic_launcher);
                            eneties.add(0,enety);
                            adapter1.notifyDataSetChanged();
                            listView.onRefreshComplete(true);
                        }
                    },3000);
    
    
                }
    
                @Override
                public void onLoadMore() {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Enety enety = new Enety("上拉加载数据",R.mipmap.ic_launcher);
                            eneties.add(enety);
                            adapter1.notifyDataSetChanged();
                            listView.onRefreshComplete(true);
                        }
                    },500);
                }
            });
    
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Log.e("Say1","position = " + position);
                }
            });
    
            listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                    Log.e("Say1","onItemLongClick position = " + position);
                    return true;
                }
            });
        }
    
        public class Enety{
            public Enety(String title, int icon) {
                this.title = title;
                this.icon = icon;
            }
    
            public String title;
            public int icon;
        }
    
    
        class MyAdapter extends AbsListViewAdapter<Enety> {
    
            public MyAdapter(Context context, List<Enety> datas, int LayoutId) {
                super(context, datas, LayoutId);
            }
    
            @Override
            public void convert(ListViewHolder holder, Enety enety) {
                holder.setTextViewVualue(R.id.title, enety.title)
                        .setImageViewVualue(R.id.image, enety.icon);
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:ListView全解析

          本文链接:https://www.haomeiwen.com/subject/zzmihctx.html