android自定义带下拉刷新和Checkbox的ListView

来源:互联网 发布:c语言 实例 pdf 编辑:程序博客网 时间:2024/05/18 08:13

(尊重原创转载请说明来处,谢谢)

       android自定义控件,就是根据自己的喜好、项目需求随意设计制作控件的外表和功能,不可谓不霸气!之前写了一篇关于带有编辑和删除功能的侧滑ListView,感觉效果不错的样子,所以现在再来写一篇最近实现的一个控件:带有下拉刷新和选择框的ListView,咱也是有点审美的人是不是,那还是老套路大家先看脸呗,毕竟相貌过得去才有干劲嘛~~~

 

       个人呢觉得程序嘛,重要的是思路,只要有了思路,问题肯定是可以解决的;反过来说,如果只注重细枝末节而忽略了总体思想,效果很可能是不理想的,印象也不是最深刻的。那么问题来了,我为什么要说这些呢?因为下面我会主要讲解自己的思路,最后还会附上亲测可以运行的代码供大家学习,欢迎各位大神拍砖:

1:先说一下选择框:大家一定会认为我在item的布局中放置了一个checkbox是不是?我确实是这么做的,但是呢,checkbox的优先级是高于listview的,所以为了解决冲突,在checkbox的布局文件中添加了这些属性,

android:focusable="false"android:focusableInTouchMode="false"android:clickable="false" 
此外在adapter中使用了HashMap<Integer,Boolean>来记录checkbox的选中状态,点击一次选中,再次点击时取消

item代码:

<?xml version="1.0" encoding="utf-8"?><!-- ListView的头部 --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <!-- 内容 -->    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/head_contentLayout" >        <!-- 箭头头像、进度条 -->        <FrameLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_marginLeft="50dp"            android:layout_centerVertical="true">            <!-- 箭头 -->            <ImageView                android:id="@+id/head_arrowImageView"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_gravity="center"                android:src="@drawable/upward"/>            <!-- 进度条 -->            <ProgressBar                android:id="@+id/head_progressBar"                android:layout_width="40dp"                android:layout_height="40dp"                style="?android:attr/progressBarStyleSmall"                android:layout_gravity="center"                android:visibility="gone"/>        </FrameLayout>        <!-- 提示、最近更新 -->        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerHorizontal="true"            android:orientation="vertical"            android:gravity="center_horizontal">            <!-- 提示 -->            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_marginTop="20dp"                android:layout_marginBottom="20dp"                android:textColor="@android:color/white"                android:id="@+id/head_tipsTextView"                android:textSize="20sp"                android:text="head_tips_text"/>        </LinearLayout>    </RelativeLayout></LinearLayout>


2:下拉刷新问题:首先呢是自定义了一个title布局文件,布局文件里有TextView、Img什么的,而这个布局文件是依靠代码将它添加到listview中,也就是说listview多了一项,只不过这个item平时是隐藏的,当手指滑动时,代码控制它动态显示或者隐藏,headTitle布局代码:

<?xml version="1.0" encoding="utf-8"?><!-- ListView的头部 --><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <!-- 内容 -->    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:id="@+id/head_contentLayout" >        <!-- 箭头头像、进度条 -->        <FrameLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentLeft="true"            android:layout_marginLeft="50dp"            android:layout_centerVertical="true">            <!-- 箭头 -->            <ImageView                android:id="@+id/head_arrowImageView"                android:layout_width="50dp"                android:layout_height="50dp"                android:layout_gravity="center"                android:src="@drawable/upward"/>            <!-- 进度条 -->            <ProgressBar                android:id="@+id/head_progressBar"                android:layout_width="40dp"                android:layout_height="40dp"                style="?android:attr/progressBarStyleSmall"                android:layout_gravity="center"                android:visibility="gone"/>        </FrameLayout>        <!-- 提示、最近更新 -->        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerHorizontal="true"            android:orientation="vertical"            android:gravity="center_horizontal">            <!-- 提示 -->            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_marginTop="20dp"                android:layout_marginBottom="20dp"                android:textColor="@android:color/white"                android:id="@+id/head_tipsTextView"                android:textSize="20sp"                android:text="head_tips_text"/>        </LinearLayout>    </RelativeLayout></LinearLayout>

自定义listview代码:

package com.lei.diyrefresh;import android.widget.ListView;import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.animation.LinearInterpolator;import android.view.animation.RotateAnimation;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListAdapter;import android.widget.ProgressBar;import android.widget.TextView;public class RefreshCheckBoxListView extends ListView implements OnScrollListener {    private final static int RELEASE_TO_REFRESH = 0;    private final static int PULL_TO_REFRESH = 1;    //正在刷新    private final static int REFRESHING = 2;    //刷新完成    private final static int DONE = 3;    private final static int LOADING = 4;    private final static int RADIO = 3;    private LayoutInflater mInflater;    private LinearLayout mHeadView;//header    private TextView mTipsTextView;//header 标题    private ImageView mArrowImageView;//动画图片    private ProgressBar mProgressBar;    private RotateAnimation mAnimation;//逆时针180    private RotateAnimation mReverseAnimation;//顺时针180    private boolean mIsRecored;    private int mHeadContentWidth;    private int mHeadContentHeight;    private int mStartY;    private int mFirstItemIndex;    private int mState;    private boolean mIsBack;    private boolean mISRefreshable;    private OnRefreshListener mRefreshListener;    public RefreshCheckBoxListView(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    private void initView(Context context) {        mInflater = LayoutInflater.from(context);        mHeadView = (LinearLayout) mInflater.inflate(R.layout.item_head_of_listview, null);        mArrowImageView = (ImageView) mHeadView.findViewById(R.id.head_arrowImageView);        mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.head_progressBar);        mTipsTextView = (TextView) mHeadView.findViewById(R.id.head_tipsTextView);        measureView(mHeadView);//测量        mHeadContentHeight = mHeadView.getMeasuredHeight();        System.out.println("mHeadContentHeight = " + mHeadContentHeight);        mHeadContentWidth = mHeadView.getMeasuredWidth();        System.out.println("mHeadContentWidth = " + mHeadContentWidth);        mHeadView.setPadding(0, -1 * mHeadContentHeight, 0, 0);        mHeadView.invalidate();        addHeaderView(mHeadView, null, false);//将header添加到listView中        setOnScrollListener(this);        mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);        mAnimation.setInterpolator(new LinearInterpolator());        mAnimation.setDuration(250);        mAnimation.setFillAfter(true);        mReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);        mReverseAnimation.setInterpolator(new LinearInterpolator());        mReverseAnimation.setDuration(250);        mReverseAnimation.setFillAfter(true);        mState = DONE;        mISRefreshable = false;    }    private void measureView(View child) {        android.view.ViewGroup.LayoutParams params = child.getLayoutParams();        System.out.println("params = " + params);        if(params == null) {            params = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);        }        System.out.println("lpWidth = " + params.width);        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, params.width);        System.out.println("childWidthSpec = " + childWidthSpec);        int lpHeight = params.height;        System.out.println("lpHeight = " + lpHeight);        int childHeightSpec;        if(lpHeight > 0) {            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);        } else {            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.UNSPECIFIED);        }        System.out.println("childHeightSpec = " + childHeightSpec);        child.measure(childWidthSpec, childHeightSpec);    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,                         int visibleItemCount, int totalItemCount) {        mFirstItemIndex = firstVisibleItem;    }    public interface OnRefreshListener {        void onRefresh();    }    private void onRefresh() {        if(mRefreshListener != null) {            mRefreshListener.onRefresh();        }    }    public void onRefreshComplete() {        mState = DONE;        changeHeaderViewByState();    }    public void setonRefreshListener(OnRefreshListener onRefreshListener) {        this.mRefreshListener = onRefreshListener;        mISRefreshable = true;    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if(mISRefreshable) {            switch (ev.getAction()) {                case MotionEvent.ACTION_DOWN:                    if(mFirstItemIndex == 0 && !mIsRecored) {                        mIsRecored = true;                        mStartY = (int) ev.getY();                    }                    break;                case MotionEvent.ACTION_UP:                    if(mState != REFRESHING && mState != LOADING) {                        if(mState == DONE) {                        }                        if(mState == PULL_TO_REFRESH) {                            mState = DONE;                            changeHeaderViewByState();                        }                        if(mState == RELEASE_TO_REFRESH) {                            mState = REFRESHING;                            changeHeaderViewByState();                            onRefresh();                        }                    }                    mIsBack = false;                    mIsRecored = false;                    break;                case MotionEvent.ACTION_MOVE:                    int tempY = (int) ev.getY();                    if(!mIsRecored && mFirstItemIndex == 0) {                        mIsRecored = true;                        mStartY = tempY;                    }                    if(mState != REFRESHING && mIsRecored && mState != LOADING) {                        if(mState == RELEASE_TO_REFRESH) {                            setSelection(0);                            if((tempY - mStartY)/RADIO < mHeadContentHeight && (tempY - mStartY) > 0) {                                mState = PULL_TO_REFRESH;                                changeHeaderViewByState();                            } else if(tempY - mStartY <= 0) {                                mState = DONE;                                changeHeaderViewByState();                            }                        }                        if(mState == PULL_TO_REFRESH) {  //下拉长度达到header的3倍高度时,进行释放刷新提示                            setSelection(0);                            if((tempY - mStartY)/RADIO >= mHeadContentHeight) {                                mState = RELEASE_TO_REFRESH;                                mIsBack = true;                                changeHeaderViewByState();                            }                        } else if(tempY - mStartY <= 0) {  //上划情况                            mState = DONE;                            changeHeaderViewByState();                        }                        if(mState == DONE) {//如果下拉重置state状态                            if(tempY - mStartY > 0) {                                mState = PULL_TO_REFRESH;                                changeHeaderViewByState();                            }                        }                        if(mState == PULL_TO_REFRESH) {//释放刷新                            mHeadView.setPadding(0, -1 * mHeadContentHeight + (tempY - mStartY)/RADIO, 0, 0);                        }                        if(mState == RELEASE_TO_REFRESH) {                            mHeadView.setPadding(0, (tempY - mStartY)/RADIO - mHeadContentHeight, 0, 0);                        }                    }                    break;                default:                    break;            }        }        return super.onTouchEvent(ev);    }    private void changeHeaderViewByState() {//control the state of header        switch (mState) {            case PULL_TO_REFRESH:                mProgressBar.setVisibility(GONE);                mTipsTextView.setVisibility(VISIBLE);                mArrowImageView.clearAnimation();                mArrowImageView.setVisibility(VISIBLE);                if(mIsBack) {                    mIsBack = false;                    mArrowImageView.clearAnimation();                    mArrowImageView.startAnimation(mReverseAnimation);                    mTipsTextView.setText("isBack is true!!!");                } else {                    mTipsTextView.setText("isBack is false!!!");                }                break;            case DONE:                mHeadView.setPadding(0, -1 * mHeadContentHeight, 0, 0);                mProgressBar.setVisibility(GONE);                mArrowImageView.clearAnimation();                mArrowImageView.setImageResource(R.drawable.upward);                mTipsTextView.setText("加载完毕");                break;            case REFRESHING:                mHeadView.setPadding(0, 0, 0, 0);                mProgressBar.setVisibility(VISIBLE);                mArrowImageView.clearAnimation();                mArrowImageView.setVisibility(GONE);                mTipsTextView.setText("努力加载中……");                break;            case RELEASE_TO_REFRESH:                mArrowImageView.setVisibility(VISIBLE);                mProgressBar.setVisibility(GONE);                mTipsTextView.setVisibility(VISIBLE);                mArrowImageView.clearAnimation();                mArrowImageView.startAnimation(mAnimation);                mTipsTextView.setText("释放刷新");                break;            default:                break;        }    }    @Override    public void setAdapter(ListAdapter adapter) {        super.setAdapter(adapter);    }}

Adapter代码:

package com.lei.diyrefresh;import android.content.Context;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.CheckBox;import android.widget.TextView;import java.util.HashMap;import java.util.List;import java.util.Map;public class RefreshListViewAdapter extends BaseAdapter {    private static String TAG="RefreshListViewAdapter";    private Context context;    private List<String> stringList;    public static Map<Integer, Boolean> isSelected;    public RefreshListViewAdapter(Context context, List<String> list){        this.context = context;        this.stringList = list;        setStart();    }    private void setStart(){        isSelected = new HashMap<Integer, Boolean>();        for (int i = 0; i < stringList.size(); i++) {            isSelected.put(i, false);        }    }    @Override    public int getCount() {        return stringList.size();    }    @Override    public Object getItem(int position) {        return stringList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        String bulb=stringList.get(position);        View view;        ViewHolder viewHolder;        if (convertView==null){            view= LayoutInflater.from(context).inflate(R.layout.item_pull_to_refresh_with_checkbox,null);            viewHolder=new ViewHolder();            viewHolder.tvName=(TextView)view.findViewById(R.id.tvRouterName);            viewHolder.tvContent=(TextView)view.findViewById(R.id.tvContent);            viewHolder.cBox=(CheckBox)view.findViewById(R.id.cBox);            view.setTag(viewHolder);//store up viewHolder        }else {            view=convertView;            viewHolder=(ViewHolder)view.getTag();        }        viewHolder.tvContent.setText("position: " + position);        viewHolder.tvName.setText(bulb);        viewHolder.cBox.setChecked(isSelected.get(position));//isSelected.get(position)        Log.i(TAG, "position: " + position + " " + isSelected.get(position));           /* if ((position%2)==1){                viewHolder.cBox.setChecked(true);//isSelected.get(position)                Log.i(TAG, "单数 " + position);            }else {                viewHolder.cBox.setChecked(false);//isSelected.get(position)                Log.i(TAG, "偶数 "+position);            }*/        return view;    }    public class ViewHolder{        TextView tvName,tvContent;        public CheckBox cBox;    }}

MainActivity:

package com.lei.diyrefresh;import android.os.AsyncTask;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.AdapterView;import android.widget.ListView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private static String TAG="MainActivity";    RefreshCheckBoxListView mRefreshCheckBoxListView;    RefreshListViewAdapter listViewAdapter;    List<String> list=new ArrayList<String>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        getData();        initView();    }    private void initView(){        mRefreshCheckBoxListView=(RefreshCheckBoxListView)findViewById(R.id.lvPull);        listViewAdapter=new RefreshListViewAdapter(this,list);        mRefreshCheckBoxListView.setAdapter(listViewAdapter);        mRefreshCheckBoxListView.setItemsCanFocus(false);        mRefreshCheckBoxListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);        mRefreshCheckBoxListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                RefreshListViewAdapter.ViewHolder vHolder = (RefreshListViewAdapter.ViewHolder) view.getTag();                //在每次获取点击的item时将对应的checkbox状态改变,同时修改map的值。                vHolder.cBox.toggle();                RefreshListViewAdapter.isSelected.put(position - 1, vHolder.cBox.isChecked());                //Log.i(TAG, "position: " + position);            }        });        mRefreshCheckBoxListView.setonRefreshListener(new RefreshCheckBoxListView.OnRefreshListener() {            @Override            public void onRefresh() {                new AsyncTask<Void, Void, Void>() {                    @Override                    protected Void doInBackground(Void... params) {                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        return null;                    }                    protected void onPostExecute(Void result) {                        listViewAdapter.notifyDataSetChanged();                        mRefreshCheckBoxListView.onRefreshComplete();                    }                }.execute();            }        });    }    private void getData(){        for (int i=0;i<20;i++){            list.add(new String("第 "+i));        }    }}
注意事项(1):因为之前代码添加head到listview中,导致listview增加了一项,所以在这里position要减1
 RefreshListViewAdapter.isSelected.put(position - 1, vHolder.cBox.isChecked());

主布局文件:

<?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:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.lei.diyrefresh.MainActivity">    <com.lei.diyrefresh.RefreshCheckBoxListView        android:id="@+id/lvPull"        android:layout_width="match_parent"        android:layout_height="wrap_content">    </com.lei.diyrefresh.RefreshCheckBoxListView></RelativeLayout>

注意事项(2):如果出现了没有记住checkbox选项的情况,不要着急,需要慢慢的分析,分析有时比实践更重要,一般是由这两个原因引起的:1 选中的值没有传到adapter中,2 忽略了head的存在,head相当于listView中的第一项,其余项自动向后延续一位


好了,思路和代码差不多就这些了,两次的编辑不可能完善,有什么问题大家可以指出来,我还会继续去细化完善



6 6
原创粉丝点击