美文网首页@IT·互联网程序员Android开发经验谈
封装一个通用的 listview/gridview Adapt

封装一个通用的 listview/gridview Adapt

作者: 夏至的稻穗 | 来源:发表于2017-06-21 20:11 被阅读0次

    作者: 夏至 欢迎转载,也请保留这段申明
    http://blog.csdn.net/u011418943/article/details/73555178

    最近在开发一个新项目,由于是给平板用的,且公司平台用 recyclerview 比较麻烦,索性就用listview,毕竟也不用太多复杂布局;但由于用到比较多的listview,那么要每个多写吗?当然不用,我们可以写一个基类,然后继承即可。

    参考鸿洋大神的文章 :http://blog.csdn.net/lmj623565791/article/details/38902805/

    先看效果图:


    这里写图片描述

    再附上张图片:

    Paste_Image.png

    上述的listview 只要几行代码就可以了:

    mAdapter = new CommonAdapter<RunAppInfo>(SpeedUpActivity.this, datas, R.layout.listview_item) {
                        @Override
                        public void convert(ViewHolder viewHolder, RunAppInfo data) {
                            viewHolder.setText(R.id.app_name,data.getName());
                            viewHolder.setText(R.id.app_size,data.getMemery());
                            viewHolder.setDrawable(R.id.app_icon,data.getIcon());
                        }
                    };
                    mListView.setAdapter(mAdapter);
    

    1、 常用listview的 baseadapter写法

    public class AppContentAdapter extends BaseAdapter{
        private Context mContext;
        private List<AppContent> mList;
        @SuppressWarnings("deprecation")
        public AppContentAdapter(Context context,List<AppContent> list){
            
            mContext = context;
            mList = list;
    
        }
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mList.size();
        }
        @Override
        public Object getItem(int arg0) {
            // TODO Auto-generated method stub
            return mList.get(arg0);
        }
        @Override
        public long getItemId(int arg0) {
            // TODO Auto-generated method stub
            return arg0;
        }
        
        class ViewHolder{
            
            TextView appname;
        }
        @Override
        public View getView(int arg0, View contentView, ViewGroup arg2) {
            ViewHolder viewHolder = null;
            if (contentView == null) {
                contentView = LayoutInflater.from(mContext).inflate(R.layout.appcontent, null);
                viewHolder = new ViewHolder();
                viewHolder.appname = (TextView) contentView.findViewById(R.id.app_name);
                contentView.setTag(viewHolder);
            }else{
                viewHolder = (ViewHolder) contentView.getTag();
            }
            
            
            viewHolder.appname.setText(mList.get(arg0).getName());
    
             
            return contentView;
            
        }   
    }
    

    相信你已经对它很熟悉了,但是加入,我们一个项目要用到很多的 listview 我们其实是在做重复功,那我们能不能把这个listview 给封装起来呢?

    2、通用的viewholder

    当然可以,首先,我们先从getview来封装,注意到这是个 viewholder,那我们就先封装个 viewholder好了。首先,我们通过 setTag 和 getTag 这种方式来获取 view 的。那么实体类首先如下所示,getViewHolder 表示viewholder的实例:

    public class ViewHolder {
          /**
         * 可以理解成单例吧,获取一个viewholder
         * @param context
         * @param converView
         * @param layout
         * @param parent
         * @param position
         * @return
         */
        public static ViewHolder getViewHolder(Context context, View converView, int layout,
                                               ViewGroup parent,int position){
            if (converView ==null){ //当为空时,我们需要实例化viewholder
                //注意这里,其实跟baseadapter的判断是一致的,其中settag也是在viewholder里
                ViewHolder viewholder = new  ...
                return  viewholder;
            }else{
                ViewHolder holder = (ViewHolder) converView.getTag();
      
                return holder;
            }
        }
    }
    

    在 getViewHolder 中,就是用来获取 viewholder 的,当然这里我们并未写实例化,只写了 getTag 而传递的参数我们也是比较熟悉,接着完善一下,提供一下setTag,代码如下:

    public class ViewHolder {
        private Context mContext;
        private View mConverView;
        private static int mPosition;
        public ViewHolder(Context context, int layout, ViewGroup parent,int position){
            mContext = context;
            mConverView = LayoutInflater.from(mContext).inflate(layout,parent,false);
            mConverView.setTag(this);
            mPosition = position; //防止滑动导致item的position错误
        }
        /**
         * 可以理解成单例吧,获取一个viewholder
         * @param context
         * @param converView
         * @param layout
         * @param parent
         * @param position
         * @return
         */
        public static ViewHolder getViewHolder(Context context, View converView, int layout,
                                               ViewGroup parent,int position){
            if (converView ==null){
                //注意这里,其实跟baseadapter的判断是一致的,其中settag也是在viewholder里
                return  new ViewHolder(context,layout,parent,position);
            }else{
                ViewHolder holder = (ViewHolder) converView.getTag();
                mPosition = position;
                return holder;
            }
        }
        /**
         * 返回一个viewholder
         * @return
         */
        public View getConverView() {
            return mConverView;
        }
    }
    

    可以看到,当我们在用的时候,其实用 getViewHolder 这种类似单例的方式的,而在实例中,加载 layout;ok,既然 viewholder 的setTag 和getTag 已经写好,接着就是通过 viewholder 来获取 view 了,那么就是一个 id 对应一个 view 了,我们可以用 sparsearray 来达到我们的效果,由于我们不知道TextView 、ImageView 等等,所以这里用泛型来写,顺便,我们也把一些常用方法写上,改良之后的代码如下:

    public class ViewHolder {
        private Context mContext;
        private View mConverView;
        private static int mPosition;
        private SparseArray<View> mViewSparseArray;
        public ViewHolder(Context context, int layout, ViewGroup parent,int position){
            mContext = context;
            mConverView = LayoutInflater.from(mContext).inflate(layout,parent,false);
            mViewSparseArray = new SparseArray<>();
            mConverView.setTag(this);
            mPosition = position;
        }
        /**
         * 可以理解成单例吧,获取一个viewholder
         * @param context
         * @param converView
         * @param layout
         * @param parent
         * @param position
         * @return
         */
        public static ViewHolder getViewHolder(Context context, View converView, int layout,
                                               ViewGroup parent,int position){
            if (converView ==null){
                //注意这里,其实跟baseadapter的判断是一致的,其中settag也是在viewholder里
                return  new ViewHolder(context,layout,parent,position);
            }else{
                ViewHolder holder = (ViewHolder) converView.getTag();
                mPosition = position;
                return holder;
            }
        }
        /**
         * 返回一个viewholder
         * @return
         */
        public View getConverView() {
            return mConverView;
        }
        /**
         * key-value 通过sparseArray来获取view,属性不同,这里用一个泛型来实现
         * @param viewid
         * @param <T>
         * @return
         */
        public <T extends View> T getView(int viewid){
            View view = mViewSparseArray.get(viewid);
            if (view == null){
                view = mConverView.findViewById(viewid);
                mViewSparseArray.put(viewid,view);
            }
            return (T) view;
        }
        /**
         * 设置text
         * @param viewid
         * @param msg
         */
        public void setText(int viewid,String msg){
            TextView tv = (TextView) mConverView.findViewById(viewid);
            tv.setVisibility(View.VISIBLE);
            tv.setText(msg);
        }
        /**
         * 设置drawable
         * @param viewid
         * @param drawable
         */
        public void setDrawable(int viewid, Drawable drawable){
            ImageView iv = (ImageView) mConverView.findViewById(viewid);
            iv.setImageDrawable(drawable);
        }
        /**
         * 设置checkbox
         * @param viewid
         * @param status
         */
        public void setCheckbox(int viewid,boolean status){
            CheckBox cb = (CheckBox) mConverView.findViewById(viewid);
            cb.setVisibility(View.VISIBLE);
            cb.setChecked(status);
        }
        /**
         * 设置itemview 的背景
         * @param viewid
         * @param status
         */
        public void setItemBackground(int viewid,int resourid){
            View view = mConverView.findViewById(viewid);
            //Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(),resourid);
            view.setBackgroundResource(resourid);
        }
    }
    

    这样,我们的一个通用viewholder就可以了。但我们的工作还没有完成,viewholder封装好了,但是 adapter呢?所以,我们封装后的adapter 如下:

    public abstract class CommonAdapter<T> extends BaseAdapter {
        protected Context mContext;
        protected List<T> mDatas;
        private int mLayoutId;
        public CommonAdapter(Context context, List<T> datas,int layoutid) {
            mContext = context;
            mDatas = datas;
            mLayoutId = layoutid;
        }
        @Override
        public int getCount() {
            return mDatas.size();
        }
        @Override
        public T getItem(int i) {
            return mDatas.get(i);
        }
        @Override
        public long getItemId(int i) {
            return i;
        }
        public abstract void convert(ViewHolder viewHolder,T data);
        /**
         * 这里把布局什么的,都在getview中,设置好,其中viewholder是我们的通用的adapter
         * 然后把需要实现的逻辑用抽象方法公布出去,自己去实现
         * @param i
         * @param view
         * @param viewGroup
         * @return
         */
        @Override
        public  View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder = ViewHolder.getViewHolder(mContext,view,mLayoutId,viewGroup,i);
            convert(viewHolder,getItem(i));
            return viewHolder.getConverView();
        };
    }
    

    可以看到,我们的 listview 基本都是用一个实体类来实现的,所以在初始化的时候,用一个泛型来表示,接着,我们在 getView 中,初始化上面封装好的 ViewHolder,把要实例化itemview 的方法公布出来,让用户自己去定制。这样,在是用的就可以这样用了:

    //采用通用listview封装adapter
                    mAdapter = new CommonAdapter<RunAppInfo>(SpeedUpActivity.this, datas, R.layout.listview_item) {
                        @Override
                        public void convert(ViewHolder viewHolder, RunAppInfo data) {
                            viewHolder.setText(R.id.app_name,data.getName());
                            viewHolder.setText(R.id.app_size,data.getMemery());
                            viewHolder.setDrawable(R.id.app_icon,data.getIcon());
                        }
                    };
                    mListView.setAdapter(mAdapter);
    

    封装好的代码,是不是比以前整洁好看多了;当然,这里我们只用了一次,并不能体现它的好处,加入我还要用多一个 listview 呢?就不用再去写多一个 listview ,直接这样使用即可:

     CommonAdapter<StorageInfo> adapter = new CommonAdapter<StorageInfo>(DeepClearActivity.this,
                    mScanDatas,R.layout.listview_detail_item) {
                @Override
                public void convert(ViewHolder viewHolder, StorageInfo data) {
                    viewHolder.setDrawable(R.id.list_icon,data.getIcon());
                    viewHolder.setText(R.id.list_name,data.getName());
                    viewHolder.setText(R.id.list_path,data.getPath());
                    viewHolder.setText(R.id.list_size,Formatter.formatFileSize(DeepClearActivity.this,data.getSize()));
                    int status = data.getStatus();
                    String statustext = null;
                    if (status != ToolUtils.UNINSTALLED){
                        statustext = getString(R.string.installed);
                    }else{
                        statustext = getString(R.string.clickinstall);
                    }
                    viewHolder.setText(R.id.list_status,statustext);
                }
            };
            mDeepDetailListview.setAdapter(adapter);
    

    3、listview 动画

    上面的效果图中,我们是有效果图的,那么怎么做呢? listview 是一个 viewground,所以,它也支持 setLayoutAnimation ,所以,我们的动画可以这样写
    listview 进入 :

    //设置listview 进入动画
            Animation translate = new TranslateAnimation(800,0,0,0);
            translate.setDuration(300);
            translate.setInterpolator(new DecelerateInterpolator());
            LayoutAnimationController lac = new LayoutAnimationController(translate);
            lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
            mDeepDetailListview.setLayoutAnimation(lac);
            mDeepDetailListview.startLayoutAnimation();
    

    退出动画

    //设置listview 退出动画
                    Animation translate = new TranslateAnimation(0,800,0,0);
                    translate.setDuration(300);
                    translate.setInterpolator(new DecelerateInterpolator());
                    translate.setFillAfter(true);
                    LayoutAnimationController lac = new LayoutAnimationController(translate);
                    lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
                    mDeepDetailListview.setLayoutAnimation(lac);
                    mDeepDetailListview.startLayoutAnimation();
    

    非常简单,就是一个简单的补件动画

    相关文章

      网友评论

        本文标题:封装一个通用的 listview/gridview Adapt

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