zoukankan      html  css  js  c++  java
  • Android开发进阶 -- 通用适配器 CommonAdapter

          在Android开发中,我们经常会用到ListView 这个组件,为了将ListView 的内容展示出来,我们会去实现一个Adapter来适配,将Layout中的布局以列表的形式展现到组件中。

        比如,像 GGTalk 安卓版的查找用户功能,会把符合条件的用户都列在下面:

          

          为了达到这个效果,我们需要实现一个自定义的Adapter,而其它地方的ListView也要实现一个Adapter,这些Adapter会有很多重复的代码,非常繁琐,现在我就将重复代码封装到了一个通用的适配器CommonAdapter中,这样,在使用时只要继承CommonAdapter就可以了,如此就避免了大段代码的重复,让代码更简洁易懂。我们先来看看CommonAdapter的定义。  

    一.CommonAdapter 实现

    public abstract class CommonAdapter<T> extends BaseAdapter {
    
        private List<T> dataList;
        protected Context context;
        protected int item_layoutId=0;
        protected HashMap<Integer,Integer> layoutIdMap; //多种itemView时用到。 第一个int对应type类型,第二个int对应 itemlayoutId
    
        /**
         * 设置单个子模版VIew,
         * @param context
         * @param datas 绑定的对象集合
         * @param item_layoutId 被绑定的视图layoutID
        * */
        public CommonAdapter(Context context, List<T> datas, int item_layoutId)
        {
            this.context=context;
            this.dataList=datas;
            this.item_layoutId=item_layoutId;
        }
    
        /**
         *设置多个子模版VIew, 并配合重写 getItemViewType(int position)来确定是设置哪个模版
         * @param context
         * @param datas 绑定的对象集合
         * @param layoutIdMap 多种itemViewID Map 第一个int对应type类型,第二个int对应 itemlayoutId
        */
        public CommonAdapter(Context context, List<T> datas, HashMap<Integer,Integer> layoutIdMap)
        {
            this.context=context;
            this.dataList=datas;
            this.layoutIdMap=layoutIdMap;
        }
    
        @Override
        public int getViewTypeCount() {
            if(this.layoutIdMap==null)
            {
                return 1;
            }
            return this.layoutIdMap.size();
        }
    
    
        @Override
        public int getCount() {
            return this.dataList.size();
        }
    
        @Override
        public Object getItem(int position) {
            return this.dataList.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            int type = getItemViewType(position);
            return getConvertView(position,convertView,type);
        }
    
        private View getConvertView(int position,View convertView,int itemViewType)
        {
            if(convertView==null)
            {
                int layoutId =0;
                if(this.item_layoutId!=0)
                {
                    layoutId=this.item_layoutId;
                }
                if (this.layoutIdMap != null) {
                    layoutId = this.layoutIdMap.get(itemViewType);
                }
                convertView = LayoutInflater.from(context).inflate(layoutId, null);
            }
            T t = this.dataList.get(position);
            this.setConvertView(convertView,t,itemViewType);
            return convertView;
        }
    
        /**
         * 局部更新数据,调用一次getView()方法;Google推荐的做法
         *
         * @param parent  要更新的listview
         * @param position 要更新的位置
         */
        public void onOneItemChanged(ListView parent, int position) {
            /**第一个可见的位置**/
            int firstVisiblePosition = parent.getFirstVisiblePosition();
            /**最后一个可见的位置**/
            int lastVisiblePosition = parent.getLastVisiblePosition();
    
            /**在看见范围内才更新,不可见的滑动后自动会调用getView方法更新**/
            if ((position >= firstVisiblePosition && position <= lastVisiblePosition)) {
    
                /**获取指定位置view对象**/
                View view = parent.getChildAt(position - firstVisiblePosition);
                getView(position, view, parent);
            }
        }
    
        /**
         * 需要去实现的对item中的view的设置操作
         *
         * @param convertView 转换后的试图
         * @param t Model对象
         * @param itemViewType 试图类型。对应layoutIdMap中的key
         */
        protected abstract void setConvertView(View convertView, T t,int itemViewType);
    }

     说明如下:

    (1)泛型参数<T>就是我们要绑定数据Model对象的class类型。

    (2)getViewTypeCount()方法会根据HashMap是否为空来识别是传入的单一模版还是多模版.

    (3)CommonAdapter还重写了getCount(),getItem(int position),getView,getConvertView等BaseAdapter 的方法,这些方法的代码都基本每个Adapter都是一样的,我们只需关心 setConvertView 这个抽象方法,在子类中重写它,将具体的逻辑和数据的绑定在此即可。

    二.使用CommonAdapter

    1. 先建一个类继承CommonAdapter,在构造函数中调用父类的构造方法以初始化数据。实现 setConvertView 方法,将对象的数据绑定到模版上 即可
      public class SearchFriendAdapter extends CommonAdapter<OrayUser> {
            /**
           * 设置单个子模版VIew,
           * @param context
           * @param datas 绑定的对象集合
           * @param item_layoutId 被绑定的视图layoutID
          * */
         public SearchFriendAdapter(Context context,List<OrayUser> datas,int item_layoutId)
         {
             super(context,datas,item_layoutId);
         }
        @Override
        protected void setConvertView(View view, OrayUser orayUser,int itemViewType)
        {
          ...具体将对象的数据绑定到模版上
        }
      } 
    2. Activity中使用时new 一个Adapter,然后将adapter绑定到 ListView
      adapter = new SearchFriendAdapter(this,this.userList,R.layout.friend_child);
      listView.setAdapter(adapter);
    3. 更新数据源中的数据同步到View
      //有2种方式将数据源同步到View
      adapter.notifyDataSetChanged();//全部刷新
      adapter.onOneItemChanged(ListView parent, int position);//刷新指定位置的数据 

    三. 让CommonAdapter支持多模板

          当然CommonAdapter还支持多模版的应用,我们只需将第一步中的Adapter实现稍稍做改动即可

    public class ListViewAdapter extends CommonAdapter<ListViewItemModel> {
        /**
         *设置多个子模版VIew, 并配合重写 getItemViewType(int position)来确定是设置哪个模版
         * @param context
         * @param datas 绑定的对象集合
         * @param layoutIdMap 多种itemViewID Map 第一个int对应type类型,第二个int对应 itemlayoutId
        */
        public ListViewAdapter(Context context, List<ListViewItemModel> datas, HashMap<Integer,Integer> layoutIdMap)
        {
            super(context,datas,layoutIdMap);
        }
        @Override
        public int getItemViewType(int position)
        {
            ListViewItemModel model=  (ListViewItemModel)super.getItem(position);
            if(model.floatRight)
            {
                return 1;
            }
            return 0;
        }
        @Override
        protected void setConvertView(View view, ListViewItemModel listViewItemModel,int itemViewType) {
        //根据itemViewType 的值来识别是哪个模版,以对应给模版绑定数据       
        }
    }

    如上图我们将构造函数的最后一个参数从单一的layoutID 换成了 模版集合的HashMap,再就是多加了 getItemViewType(int position) 方法来返回 具体Model对应的是哪一个模版类型(即hashMap 中的key值),使用时更新数据源中的数据同步到View和上面的单一模版一样使用。(同上2种更新方法)

            HashMap<Integer,Integer> layoutMap=new HashMap<>();
            layoutMap.put(0,R.layout.listview_item);//key值最好从0开始向上递增,否则可能会找不到key的BUG
            layoutMap.put(1,R.layout.listview_right_item);
            adapter=new ListViewAdapter(this,models,layoutMap);
            listView.setAdapter(adapter);

     四.综合实例

          最后我们还是以本文开头的查找用户的例子,来更全面地说明CommonAdapter的使用。页面截图如下:

          

     1.模版布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/selector_item"
        android:descendantFocusability="blocksDescendants"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:padding="4dp">
    
        <ImageView
            android:id="@+id/ct_photo"
            android:layout_width="@dimen/headImageSize"
            android:layout_height="@dimen/headImageSize"
            android:layout_margin="5dp"
            android:src="@drawable/plus"
            />
    
        <ImageView
            android:id="@+id/ct_status"
            android:layout_width="11dip"
            android:layout_height="11dip"
            android:layout_marginLeft="@dimen/headImageSize"
            android:layout_marginTop="@dimen/headImageSize"
            android:src='@drawable/status_2' />
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:layout_alignTop="@id/ct_photo"
            android:layout_toRightOf="@id/ct_photo"
            >
    
            <TextView
                android:id="@+id/ct_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:paddingBottom="5dp"
                android:paddingTop="0dp"
                android:text="name"
                android:textColor="@color/dimgrey"
                android:textSize="16sp"
                android:textStyle="bold" />
    
            <TextView
                android:id="@+id/ct_describe"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@id/ct_name"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:paddingBottom="5dp"
                android:paddingTop="0dp"
                android:text="describe"
                android:textColor="@color/dimgrey"
                android:textSize="14sp"
                android:visibility="gone" />
        </LinearLayout>
        <TextView
            android:id="@+id/ct_sign"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@id/ct_photo"
            android:layout_toRightOf="@id/ct_photo"
            android:paddingLeft="5dp"
            android:text="sign"
            android:singleLine="true"
            android:ellipsize="start"
            android:textColor="@color/dimgrey"
            android:textSize="12sp" />
    
    </RelativeLayout>
    

    2.具体继承CommonAdapter实现子类

    public class SearchFriendAdapter extends CommonAdapter<OrayUser> {
       public SearchFriendAdapter(Context context,List<OrayUser> datas,int item_layoutId)
       {
           super(context,datas,item_layoutId);
       }
    
        @Override
        protected void setConvertView(View view, OrayUser orayUser,int itemViewType) {
            try{
                SearchFriendAdapter.ViewHolder holder;
                if(view.getTag()==null)
                {
                    holder = new SearchFriendAdapter.ViewHolder(view);
                    view.setTag(holder);
                }
                else {
                    holder = (SearchFriendAdapter.ViewHolder) view.getTag();
                }
                HeadImgHelper.setUserHeadImg(holder.headImg,orayUser);
                if(orayUser.getName().equals(orayUser.getCommentName()))
                {
                    holder.userName.setText(orayUser.getName());
                }
                else {
                    holder.userName.setText(orayUser.getCommentName()+"("+ orayUser.getName()+")");
                }
                String catalogName= ClientGlobalCache.getInstance().getCurrentUser().getCatalogNameByFriend(orayUser.getUserID());
                if(!StringHelper.isNullOrEmpty(catalogName))
                {
                    holder.describe.setText("[ "+ catalogName+" ]");
                    holder.describe.setVisibility(View.VISIBLE);
                }
                else
                {
                    holder.describe.setText("");
                    holder.describe.setVisibility(View.GONE);
                }
                holder.orgName.setText(orayUser.getUserID());
            }catch (Exception ex){ex.printStackTrace();}
        }
    
        private class ViewHolder
        {
            public ImageView headImg;
            public TextView userName;
            public TextView describe;
            public TextView orgName;
    
            public ViewHolder(View view)
            {
                this.headImg = (ImageView) view.findViewById(R.id.ct_photo);
                ImageView statusImg=(ImageView) view.findViewById(R.id.ct_status);
                statusImg.setVisibility(View.GONE);
                this.userName=(TextView) view.findViewById(R.id.ct_name);
                this.orgName=(TextView) view.findViewById(R.id.ct_sign);
                this.describe=(TextView) view.findViewById(R.id.ct_describe);
            }
        }
    }

    3. Activity类 核心代码

    public class SearchFriendActivity extends Activity implements TextView.OnEditorActionListener{
        private DrawableEditText input;
        private ListView listView;
        private TextView search_resultStr;
        private List<OrayUser> userList=new ArrayList<OrayUser>() ;
        private SearchFriendAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_search_friend);
            this.initView();
        }
    
        private void initView()
        {
            TextView pageTitle=(TextView)findViewById(R.id.headerText);
            pageTitle.setText("查找用户");
            search_resultStr =(TextView) findViewById(R.id.search_resultStr);
            listView=(ListView)findViewById(R.id.listview_user);
            listView.setOnItemClickListener(this);
            adapter = new SearchFriendAdapter(this,this.userList,R.layout.friend_child);
            listView.setAdapter(adapter);       
    
        }   /**
         * 执行点击搜索指令
         * */
        private void action_search(String idOrName)
        {
            List<OrayUser> temp_users=Manager.getInstance().doSearchUser(idOrName);
            search_resultStr.setText("没有找到符合条件的用户或群组");
            this.setSearchResult(temp_users);
        }
    
        private void setSearchResult(List<OrayUser> temp_users)
        {
            this.userList.clear();
            if(temp_users==null||temp_users.size()==0)
            {
                search_resultStr.setVisibility(View.VISIBLE);
            }
            else
            {
                for (OrayUser orayUser :temp_users) {
                    if(orayUser.getUserID().equals(ClientGlobalCache.getInstance().getCurrentUser().getUserID()))
                    {
                        temp_users.remove(orayUser);
                        break;
                    }
                }
                this.userList.addAll(temp_users) ;
                search_resultStr.setVisibility(View.GONE);
            }
            this.adapter.notifyDataSetChanged();
        }
    }
  • 相关阅读:
    一种flink 作业提交失败的情况描述与原因排查
    Linux中对管道命令中的任意子命令进行返回码校验
    优化算法与特征缩放
    优化算法
    mvn-dependencies-vs-dependencyManagement
    Caused by java.lang.Exception Failed to send data to Kafka Expiring
    学习ArrayList的扩容机制
    SpringBoot多数据源配置
    idea内存不足或过大闪退
    利用csv文件批量编辑更新sql
  • 原文地址:https://www.cnblogs.com/justnow/p/12096752.html
Copyright © 2011-2022 走看看