1. 程式人生 > >Android 自定義介面卡

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;
        }
    }
}