Android 自定义适配器

1. BaseAdapter:是所有适配器类的父类,可以对列表项进行最大限度的定制
  1.1 自定义适配器中的方法
      getCount
      getView
      getItem
      getItemId
  1.2 LayoutInflater(布局解析器)
      --LayoutInflater有三种获得方式,资料中有详细介绍
      用来把layout布局文件解析成一个View对象,不可以new,需要使用系统服务获得
      inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

案例一:ListView的使用及优化
2. ListView优化
  2.1 使用ConvertView重用组件
      即拖动时被遮住、看不见的控件,重用它,而非每次创建一个新的对象

  2.2 使用内部类ViewHolder+ConvertView.setTag()保存控件,而不用每次查找
      ViewHolder(视图的持有者)

  2.3 使用分页查询(PullToRefresh)
      2.3.2 使用AsyncTask(异步任务)加载数据,最少要重写以下这两个方法
            doInBackground
              后台执行
            onPostExecute
              在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
              关键代码:
              myListViewAdapter.notifyDataSetChanged();// 通知适配器数据已改变
          ptrlv_main_1.onRefreshComplete();// 通知控件数据已经加载完毕


  2.4 事件监听的优化
      假设Item中有三个按钮,要为三个按钮定义事件,如果是下面这样
      btn1.setOnclickListener(new View.onClickListener(){
         public void onClick(View view){
             //...
         }
      });
      btn2.setOnclickListener(new View.onClickListener(){
         public void onClick(View view){
             //...
         }
      });
      btn3.setOnclickListener(new View.onClickListener(){
         public void onClick(View view){
             //...
         }
      });
      如果每屏显示10个Item,那一共创建了30个listener对象在内存中。
      如果,你是在Adapter创建时,只创建一个Listener,并将其定义成全局属性,
      然后通过按钮的ID来进行判断是哪个事件应该触发,
      class MyAdapter extends BaseAdapter{
         View.onClickListener myListener = new View.onClickListener(){
           public void onClick(View view){
             if(view.getId() == R.id.btn1){
               //...
             }else if(view.getId() == R.id.btn2){
               //...
             }else if(view.getId() == R.id.btn3){
               //...
             }
           }
         });
        }

        //注册监听器
        btn1.setOnclickListener(myListener);
        btn2.setOnclickListener(myListener);
        btn3.setOnclickListener(myListener);

  2.5 另外,真实开发中,图片肯定是通过网络下载,也需要通过线程异步下载进行优化等等,但由于还涉及到android网络编程,
      这部分的内容会在之后的课程中介绍

3. 第三方控件:上拉加载、下拉刷新控件
  3.1 导入第三方插件库
      Android-PullToRefresh-master.zip

  3.2 在布局文件中使用第三方插件
      com.handmark.pulltorefresh.library.PullToRefreshListView 
    
  3.3 自定义适配器(BaseAdapter)提供数据
      
  3.4 异步任务查询数据(AsyncTask)
    3.4.1 AsyncTask定义了三种泛型类型 Params,Progress和Result。
          Params 启动任务执行的输入参数,比如HTTP请求的URL。
          Progress 后台任务执行的百分比。
          Result 后台执行任务最终返回的结果,比如String
    3.4.2 异步加载数据最少要重写以下这两个方法
          doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里
          onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI
            --注:此方法中再通知适配器和控件
            myBaseAdapter.notifyDataSetChanged();// 通知适配器数据已改变
        plv_main_plv1.onRefreshComplete();// 通知控件数据已经加载完毕
      
  3.5 给PullToRefreshListView设置相关属性
      plv_main_1.setMode(Mode.BOTH);// 设置刷新模式
      Mode.BOTH:同时支持上拉下拉
      Mode.PULL_FROM_START:只支持下拉Pulling Down 
      Mode.PULL_FROM_END:只支持上拉Pulling Up 

      plv_main_1.getLoadingLayoutProxy().setPullLabel("上拉刷新...");// 刚下拉时,显示的提
      plv_main_1.getLoadingLayoutProxy().setRefreshingLabel("正在载入...");// 刷新时
      plv_main_1.getLoadingLayoutProxy().setReleaseLabel("放开刷新...");// 下来达到一定距离时,显示的提示


  3.6 给PullToRefreshListView设置适配器

  3.7 给PullToRefreshListView设置监听器
      监听器有二种:第一种上拉和下拉刷新的效果是一样的,要想实现上拉和下拉刷新效果不一样就要使用第二种
      setOnRefreshListener/PullToRefreshBase.OnRefreshListener
        
      setOnRefreshListener2/PullToRefreshBase.OnRefreshListener2
      

  
核心:
    1、listview控件、项资源、自定义适配器准备好
    2、向服务端拿数据
    3、初始化自定适配器(获取视图解析器、得到项资源的view控件、获取所有的子控件,给子控件赋值、返回view)
    4、绑定适配器
 

package com.example.t212_a08;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private List<Book> data;
    private ListView lv_main_lv1;
    private MyBaseAdapter myBaseAdapter;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv_main_lv1 = this.findViewById(R.id.lv_main_lv1);

        this.data = new BookDao().list();
        myBaseAdapter = new MyBaseAdapter((LayoutInflater) getSystemService(this.LAYOUT_INFLATER_SERVICE));
        lv_main_lv1.setAdapter(myBaseAdapter);
    }

    //定义一个自定义适配器
    public class  MyBaseAdapter extends BaseAdapter{

        //用来存储控件的内部类
        public class ViewHolder{
            //定义属性
            ImageView iv_listviewitem_image;
            TextView tv_listviewitme_title;
            TextView tv_listviewitme_author;
            TextView tv_listviewitme_price;
            TextView tv_listviewitme_publish;
            TextView tv_listviewitme_remark;
            ImageButton bt_listviewitme_btn1;
            ImageButton bt_listviewitme_btn2;
        }

        //定义一个解析器
        private LayoutInflater inflater;
        //定义一个有参
        public MyBaseAdapter(LayoutInflater inflater) {
            this.inflater = inflater;
        }

        /**
         * 数据的长度
         * @return
         */
        @Override
        public int getCount() {
            return data.size();
        }

        /**
         * 获取第几个项
         * @param i
         * @return
         */
        @Override
        public Object getItem(int i) {
            return data.get(i);
        }

        /**
         * 返回下标
         * @param position
         * @return
         */
        @Override
        public long getItemId(int position) {
            return position;
        }

        /**
         *
         * @param position      循环到的下标
         * @param convertView   被遮挡的视图
         * @param parent
         * @return
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            //将资源文件转为 View视图
            View v = convertView;
            ViewHolder viewHolder;
            if(v==null){//当没有视图被遮挡        (相当于当前创建的视图还不够占满屏幕)
                Log.i("test","position"+position);
                v = inflater.inflate(R.layout.listview_item,null);

                //实例化一个控件
                viewHolder = new ViewHolder();
                //获取控件
                viewHolder.iv_listviewitem_image =  v.findViewById(R.id.iv_listviewitem_image);
                viewHolder.tv_listviewitme_title = v.findViewById(R.id.tv_listviewitme_title);
                viewHolder.tv_listviewitme_author  = v.findViewById(R.id.tv_listviewitme_author);
                viewHolder.tv_listviewitme_price = v.findViewById(R.id.tv_listviewitme_price);
                viewHolder.tv_listviewitme_publish = v.findViewById(R.id.tv_listviewitme_publish);
                viewHolder.tv_listviewitme_remark = v.findViewById(R.id.tv_listviewitme_remark);

                //给视图里放控件
                v.setTag(viewHolder);
            }else {//当当前创建的视图足够用了时    为了优化只需要把新的视图把原来的视图覆盖
                v = convertView;
            }


            //往控件里赋值
            //根据下标获取对象
            ViewHolder vh = (ViewHolder) v.getTag();
            Book book = data.get(position);
            vh.iv_listviewitem_image.setImageResource(book.getImage());
            vh.tv_listviewitme_title.setText(book.getTitle());
            vh.tv_listviewitme_author.setText(book.getAuthor());
            vh.tv_listviewitme_price.setText(book.getPrice()+"");
            vh.tv_listviewitme_publish.setText(book.getPublish());
            vh.tv_listviewitme_remark.setText(book.getRemark());

            return v;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41915592/article/details/82728427