08讀書筆記之創建自定義控件

#最常用和最難用的控件----ListView

ListView絕對是稱得上Android中最常用的控件之一。幾乎所有應用程序都會用到它。
ListView允許用戶通過手指上下滑動的方式將屏幕外的數據滾動到屏幕內,同時屏幕上原有的數據則會滾動出屏幕。
不過比起先前學的幾種控件,ListView的用法也相對複雜了很多。

新建項目ListViewTest



一個ListView通常有兩個職責。
(1)將數據填充到佈局。
(2)處理用戶的選擇點擊等操作。
一個ListView的創建需要三個元素
(1)ListView中的每一列的View
(2)填入View的數據或圖片等。
(3)連接數據與ListView的適配器。
也就是說,要使用ListView,首先要了解什麼是適配器。
適配器是一個連接數據和AdapterView(ListView就是一個典型的AdapterView)
的橋樑,通過它能有效地實現數據與AdaterView的分離設置,使AndroidView與數據的綁定更加簡便,修改更加方便。
Android中提供了很多的Adapter

Adapter 含義

ArrayAdapter 用來綁定一個數組,支持泛型操作

SimpleAdapter 用來綁定在xml中定義的控件對應的數據

SimpleCursorAdapter 用來綁定遊標得到的數據

BaseAdapter 通用的基礎適配器

其實適配器還有很多,要注意的是,各種Adapter只不過是轉換的方式和能力不一樣而已。

package net.nyist.lenovo.listviewtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity {

private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
        "Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(
            MainActivity.this,android.R.layout.simple_list_item_1,data);
    ListView listView= (ListView)findViewById(R.id.list_view);
    listView.setAdapter(adapter);
}
}

既然ListView是用於展示大量數據的,那我們就應該先將數據提供好。這些數據可以是從網上下載的,也可以是從數據庫中讀取的,應該視具體的應用程序場景而定。這裏我就使用了一個簡單的data數組來測試,裏面包含了許多水果的名稱。
不過,數組中的數據時無法直接傳遞給ListView的,我們還需要藉助適配器來完成。
ArrayAdpter有多個構造函數的重載,應該根據實際情況選擇合適的一種。
由於我們提供的數據都是字符串,因此將ArrayAdapter的泛型指定爲String,然後在ArrayAdapter的構造函數中一次傳入當前上下文、LitView子項佈局的id,以及要適配的數據。注意,我們使用了android.R.layout.simple_list_item_1作爲ListView子項佈局的id,這是一個Android內置的佈局文件,裏面只有一個TextView,可用於簡單地顯示一段文本。這樣適配器對象就構建好了。
最後,還需要調用ListView的setAdapter()方法,將構建好的適配器對象傳遞進去,這樣ListView和數據之間的關聯就建立完成了。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0I9U22qy-1587024879884)(http://i.imgur.com/xBKRLfV.png)]
#定製ListView的界面
只能顯示一段文本的ListView實在是太單調了,我們現在就來對ListView的界面進行定製,讓它可以顯示更加豐富的內容。
首先需要準備好一組圖片。
接着定義一個實體類,作爲ListView適配器的適配類型。新建Fruit,代碼如下:

package net.nyist.lenovo.listviewtest;
public class Fruit {
private String name;

private int imageId;

public Fruit(String name ,int imageId){
    this.name = name;
    this.imageId = imageId;
}

public int getImageId() {
    return imageId;
}

public String getName() {
    return name;
}
}

Fruit類中只有兩個字段,name表示水果的名字,imageId表示水果對應圖片的資源id。
然後需要爲ListView的子項指定一個我們自定義的佈局,在layout目錄下新建fruit_item.xml.代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
    android:id="@+id/fruit_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/fruit_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:layout_marginLeft="10dp"
    />
</LinearLayout>

在這個佈局中,我們定義了一個ImageView用於顯示水果的圖片,有定義了一個TextView用於顯示水果的名稱,並讓TextView在垂直方向上居中顯示。

接下來需要創建一個自定義的適配器,這個適配器繼承自ArrayAdapter,並將泛型指定爲Fruit類。新建類FruitAdapter,代碼如下所示:

package net.nyist.lenovo.listviewtest;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class FruitAdapter extends ArrayAdapter<Fruit>{

private int resourceId;

public FruitAdapter(Context context, int textViewResourceId, List<Fruit>objects){
    super(context,textViewResourceId,objects);
    resourceId = textViewResourceId;
}


@Override
public View getView(int position,  View convertView,  ViewGroup parent) {
    Fruit fruit = getItem(position);//獲取當前項的Fruit實例
    View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
    ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
    TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);
    fruitImage.setImageResource(fruit.getImageId());
    fruitName.setText(fruit.getName());
    return view;
}
}

//加載佈局管理器,將xml佈局轉換爲view對象
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
//利用view對象,找到佈局中的組件
ImageView fruitImage = (ImageView)view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView)view.findViewById(R.id.fruit_name);

FruitAdapter
重寫了父類的一組構造函數,用於將上下文,ListView子項佈局的id和數據都傳遞進來。
另外又重寫了getView()方法這個方法,這個方法在每個子項被滾動到屏幕內的時候會被調用。在getView()方法中,首先通過getItem()方法得到當前項的Fruit實例,然後使用LayoutInflater來爲這個子項加載我們傳入的佈局。
這裏LayoutInflater的inflate()方法接收三個參數,前兩個參數我們已經知道是什麼意思了,第三個參數指定成false,表示只讓我們在父佈局中聲明的layout屬性生效,但不爲這個View添加父佈局,因爲一旦View有了父佈局之後,他就不能再添加到ListView中了。
接下來調用View的findViewById()方法分別獲取到ImageView和TextView的實例。
並分別調用它們的setImageResource()和setText()方法來設置顯示的圖片和文字,,最後將佈局返回,這樣定義的適配器就完成了。
下面修改MainActivity中的代碼,如下所示:
package net.nyist.lenovo.listviewtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

private List<Fruit>fruitList = new ArrayList<>();



private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
        "Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initFruits();//初始化水果數據
    FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
    ListView listView= (ListView)findViewById(R.id.list_view);
    listView.setAdapter(adapter);
}
private void initFruits(){
    for (int i  = 0;i < 2;i++){
        Fruit apple = new Fruit("Apple",R.drawable.apple_pic);
        fruitList.add(apple);
        Fruit banana = new Fruit("Banana",R.drawable.banana_pic);
        fruitList.add(banana);
        Fruit orange = new Fruit("Orange",R.drawable.orange_pic);
        fruitList.add(orange);
        Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon_pic);
        fruitList.add(watermelon);
        Fruit pear = new Fruit("Pear",R.drawable.pear_pic);
        fruitList.add(pear);
        Fruit grape = new Fruit("Grape",R.drawable.grape_pic);
        fruitList.add(grape);
        Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple_pic);
        fruitList.add(pineapple);
        Fruit strawberry = new Fruit("Strawberry",R.drawable.strawberry_pic);
        fruitList.add(strawberry);
        Fruit cherry = new Fruit("Cherry",R.drawable.cherry_pic);
        fruitList.add(cherry);
        Fruit mango = new Fruit("Mango",R.drawable.mango_pic);
        fruitList.add(mango);

    }
}
}

這裏添加一個initFruits()方法,用於初始化所有的水果數據。在Fruit類的構造函數中將水果的名字和對應的圖片id傳入,然後把創建好的對象添加到水果列表中,另外我們使用了一個for循環將所有的水果數據添加了兩遍,這是因爲如果只添加一遍的話,數據量還不足以充滿整個屏幕,接着在onCreate()方法中創建了FruitAdpter對象,並將FruitAdapter作爲適配器傳遞給ListView,這樣定製ListView界面的任務就做好了。

這裏寫圖片描述

#ListView的點擊事件
話說回來,ListView的滾動畢竟只是滿足了我們視覺上的效果,可是如果ListView中的子項不能點擊的話,這個控件就沒有什麼實際的用途了。因此,本小節我們就來學習一下ListView如何才能響應用戶的點擊事件。
修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

private List<Fruit>fruitList = new ArrayList<>();
private String[] data = {"Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
        "Apple","Banana","Orange","Watermelon","Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initFruits();//初始化水果數據
    FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
    ListView listView= (ListView)findViewById(R.id.list_view);
    listView.setAdapter(adapter);
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Fruit fruit = fruitList.get(position);
            Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
        }
    });
}

可以看到,我們使用setOnItemClickListener()方法爲ListView註冊了一個監聽器,當用戶點擊了ListView中的任何一個子項時,就會回調onItemClick()方法。在這個方法中可以通過position參數判斷出用戶點擊的是哪一個子項,然後獲取到響應的水果,並通過Toast將水果的名字顯示出來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章