1. 程式人生 > >安卓Intent、Bundle的使用以及RecyclerView、ListView的應用

安卓Intent、Bundle的使用以及RecyclerView、ListView的應用

一、實驗題目

Intent、Bundle的使用以及RecyclerView、ListView的應用

二、實現內容

本次實驗模擬實現一個健康食品列表,有兩個介面,第一個介面用於呈現食品列表 如下所示 此處輸入圖片的描述 資料在"manual/素材"目錄下給出。 點選右下方的懸浮按鈕可以切換到收藏夾 img2 上面兩個列表點選任意一項後,可以看到詳細的資訊: 此處輸入圖片的描述

三、課堂實驗結果

(1)實驗截圖

1、主介面 此處輸入圖片的描述

2、點選一個食品進入詳情介面 此處輸入圖片的描述

3、點選收藏按鈕 此處輸入圖片的描述

4、進入收藏夾欄 此處輸入圖片的描述

5、長按收藏欄夾中食品 此處輸入圖片的描述

6、點選確定 此處輸入圖片的描述

7、點選星星 此處輸入圖片的描述

8、長按食品欄刪除

(2)實驗步驟以及關鍵程式碼

1、設定主介面,由一個RecyclerView和一個ListView以及一個FloatingActionButton組成。一開始啟動介面為RecyclerView,暫時設定ListView屬性為gone。

  <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:visibility="gone"
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

2、設定RecyclerView。首先獲取設定RecyclerView,使用setLayoutManager設定佈局屬性。然後要先自定義RecyclerView.ViewHolder。ViewHolder通常出現在介面卡裡,為的是listview滾動的時候快速設定值,而不必每次都重新建立很多物件,從而提升效能。使用一個SparseArray陣列儲存listItem中的子View。

 private SparseArray<View> views;
    private View view;

    public MyViewHolder(Context _context, View _view, ViewGroup _viewGroup){
        super(_view);
        view = _view;
        views = new SparseArray<View>();
    }

注意ViewHolder尚未將子View快取到SparseArray陣列中時,仍然需要通過findViewById()建立View物件,如果已快取,直接返回即可。

 public <T extends View> T getView(int _viewId) {
        View _view = views.get(_viewId);
        if (_view == null) {
            // 建立view
            _view = view.findViewById(_viewId);
            // 將view存入views
            views.put(_viewId, _view);
        }
        return (T)_view;
    }

之後需要自定義一個adapter。Adapter扮演著兩個角色,一是根據不同ViewType建立與之相應的Item-Layout,二是訪問資料集合並將資料繫結到正確的View上。因此需要重寫一下兩個函式。 public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)建立Item檢視,並返回相應的ViewHolder。 public void onBindViewHolder(final MyViewHolder holder, int position)繫結資料到正確的Item檢視上。 convert函式是一個抽象方法,在宣告adapter時需要實現它。作用是將資料繫結到RecyclerView的各個控制元件中。

final MyRecyclerViewAdapter myAdapter = new MyRecyclerViewAdapter<Map<String,String>>(MainActivity.this, R.layout.items, data) {
            @Override
            public void convert(MyViewHolder holder, Map<String,String> s) {
                TextView name = holder.getView(R.id.name);
                name.setText(s.get("name"));
                TextView first = holder.getView(R.id.ID);
                first.setText(s.get("ID"));
            }
        };

RecyclerView沒有OnItemClickListener方法,需要在Adapter中實現。方法為:在Adapter中設定一個監聽器,當itemView被點選時,呼叫該監聽器並且將itemView的position作為引數傳遞出去。先新增介面

public interface OnItemClickListener{
        void onClick(int position);
        void onLongClick(int position);
    }

    public void setOnItemClickListener(OnItemClickListener _onItemClickListener) {
        this.onItemClickListener = _onItemClickListener;
    }

然後在onBindViewHolder()中新增重寫函式。 3、設定ListView。ListView的原理和RecyclerView類似。這裡使用了simpleadapter 構造一個SimpleAdapter,需要以下的引數:

1.Context context:上下文,這個是每個元件都需要的,它指明瞭SimpleAdapter關聯的View的執行環境,也就是我們當前的Activity。

2.List<? extends Map

先建立一個simpleAdapter

    simpleAdapter = new SimpleAdapter(this,data,R.layout.shoplist,
           new String[] {"icon","itemname"},new int[]{R.id.Icon,R.id.Name});

然後用setAdapter函式設定adapter 之後要給listview設定點選函式,分別為單擊和長按事件。

4、現在要在點選函式中加上頁面跳轉以及資料傳遞。在recycleview中繫結的是一個List<Map<String,String>>連結串列,分別儲存了標籤和名稱。我這裡傳遞的資料是該列表項所處的位置以及名稱。所有的資訊儲存為一個string陣列,然後檢測該列表項的名稱匹配陣列中的位置,將該位置和名稱新建一個bundle,再通過intent傳入。

               Bundle bundle = new Bundle();
               bundle.putInt("position",index);
               bundle.putString("name",_name);
               intent.putExtras(bundle);
               startActivityForResult(intent,1);

5、在詳情頁面內,使用getIntent()函式來接收資訊,用getExtra獲取bundle,然後判斷該位置屬於哪個食品,再繫結資訊到各個控制元件中。

Intent intent=getIntent();
        Bundle bundle =intent.getExtras();
        String na=bundle.getString("name");

6、之後要進行詳情頁面的佈局設計。我這裡選擇的是LinearLayout,把整個佈局分為三塊RelativeLayout。要設定頂部佔三分之一,需要將整個LinearLayout的weightSum設為3,把頂部的RelativeLayout的layout_weight設為1.使用layout_alignParentLeft設定左對齊,底部對齊同理。要使得垂直居中需要設定layout_centerVertical屬性為true。介面底部的listview的使用方法和之前類似,就不再詳談了。 7、現在要建立收藏的事件。和之前類似,依然使用一個bundle儲存該食品的名稱和位置。

  Intent intent1 = new Intent(Info.this,MainActivity.class);
              Bundle bundle1 = new Bundle();
              bundle1.putInt("position",tag);
              bundle1.putString("name",name[tag]);
              intent1.putExtras(bundle);

值得一提的是,在之前的主介面中需要新增onActivityResult函式,來處理返回的值,也就是將收藏的值新增進之前建的List < Map < String,String>> 收藏列表中去。

 protected void onActivityResult(int requestCode, int resultCode, Intent data1) {
        super.onActivityResult(requestCode, resultCode, data1);
        // RESULT_OK,判斷另外一個activity已經結束資料輸入功能,Standard activity result:
        // operation succeeded. 預設值是-1


        if (resultCode == 1) {
            if (requestCode == 1) {

                Bundle bundle=data1.getExtras();

                int tag = bundle.getInt("position");
                Map<String,String>temp = new LinkedHashMap<>();
              temp.put("icon",ID[tag]);
              temp.put("itemname",name[tag]);


                data.add(temp);
                 simpleAdapter.notifyDataSetChanged();


            }
        }
    }

8、星標的轉換需要給該imagebutton加一個tag,再根據tag來setImageResource。

   Star.setOnClickListener((view) ->{
            int index=(Integer) view.getTag();
            if (index==0)
            {
                Star.setTag(1);
                Star.setImageResource(R.mipmap.full_star);
            }
            else
            {
                Star.setTag(0);
                Star.setImageResource(R.mipmap.empty_star);
            }




        });

9、點選長按事件需要設定onItemLongClick函式。在recycleview中需要刪除陣列元素,並且將繫結的arraylist中也刪除掉。在listview中需要獲取所點選的view,然後獲取名稱。

  LinearLayout layout = (LinearLayout)view;
               TextView status = (TextView) layout.findViewById(R.id.Name);
               String _name=status.getText().toString();

再通過判斷位置來刪除該收藏。 10、接下來還有懸浮窗的設計。新增依賴implementation

'com.android.support:design:27.1.1’設定佈局檔案 <android.support.design.widget.FloatingActionButton android:id="@+id/btn" android:layout_width=“wrap_content” android:layout_height=“wrap_content” android:src="@mipmap/colletions" android:backgroundTint="@color/colorWhite" android:backgroundTintMode=“src_atop” app:layout_constraintBottom_toBottomOf=“parent” app:layout_constraintRight_toRightOf=“parent” android:layout_margin=“25dp” />

之後設定點選函式。判斷兩個view的可見狀態,然後分別改變可視狀態,並且改變懸浮窗圖片。 11、新增RecyclerView動畫。這裡使用的預設動畫。使用DefaultItemAnimator函式

DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
        defaultItemAnimator.setAddDuration(1000);
        defaultItemAnimator.setRemoveDuration(1000);
        recyclerView.setItemAnimator(defaultItemAnimator);

這裡要注意的是,如果要採用預設動畫,資料更新時不能使用Adapter.notifyDataSetChanged();而是要用Adapter.notifyItemChanged(int position)。

(3)實驗遇到的困難以及解決思路

1、長按recycleview中控制元件刪除時出現錯誤,提示陣列超出範圍。 解決思路:經過除錯發現此時長按卻進入了onclick函式,此時的positon為-1,陣列name[position]自然不存在。經查閱後得知點選事件和長按點選事件是可以同時發生的。而此時可能處於一個兩者之間的時間值。解決方法就是講onLongClick中的返回引數改為true,使長點選事件成為一個獨佔事件。 2、recycleview一直無法匯入依賴 解決思路:無法找到所對應版本的recycleview,因此直接從dependency中搜索相近版本的recycleview,加入進去。 3、佈局不知道怎麼使頂部佔整體的三分之一 解決思路:令整個介面的weightSum為3,然後把頂部介面的RelativeLayout的layout_weight設為1. 4、傳遞頁面時發現如果刪除了一個列表項裡的食品,則進入詳情頁面後與點選時的食品不匹配。 解決思路:刪除食品時只是刪除了adapter繫結的資料,並沒有刪除外部的字元陣列的元素。應該將字串的陣列刪除乾淨。 5、設定垂直居中時控制元件無法處在正確的位置 解決思路:因為垂直居中會使得控制元件處於整個父控制元件的中間,因為一開始我設定的整個中部空間為一個RelativeLayout,所以使得收藏夾按鈕位於整個中間位置。經過修改後把收藏夾一行單獨設為一個RelativeLayout,這樣就可以垂直居中了。

四、實驗思考及感想

1、這次實驗主要涉及了頁面之間的跳轉和listview、recycleview的繫結。其中頁面之間的跳轉是安卓應用開發的重中之重,畢竟一個app不可能永遠只有一個頁面。頁面跳轉時需要注意傳遞的資訊是否符合需要。還要注意在新的頁面如何接收資訊。recycleview等控制元件的繫結可以幫助我們更好地處理成批的資訊,可以更方便之後的修改。 2、recycleview中自定義ViewHoler和adapter可以幫助我們實現許多新奇的效果。它具有低耦合高類聚的特性,過設定不同的LayoutManager,以及結合ItemDecoration , ItemAnimator,ItemTouchHelper,可以實現非常炫酷的效果。同時RecyclerView封裝了viewholder的回收複用,也就是說RecyclerView標準化了ViewHolder,編寫Adapter面向的是ViewHolder而不再是View了,複用的邏輯被封裝了,寫起來更加簡單。直接省去了listview中convertView.setTag(holder)和convertView.getTag()這些繁瑣的步驟。 3、我們再注入依賴時必須注意自己的版本號,如果版本號不匹配,將無法build,甚至於去掉該依賴後仍然會有報錯。有時候需要重啟一下as才行。如果實在不能匹配,可以考慮直接從project structure中的dependencies裡新增依賴。 4、佈局時要熟悉各種佈局的形式與效果,儘量嘗試每一種佈局,這樣到真正使用時可以根據需求更好地選擇正確的佈局方式。