1. 程式人生 > >第一行程式碼第二版ListView的使用(listView複用遇到的坑)

第一行程式碼第二版ListView的使用(listView複用遇到的坑)

這個複雜又好用的控制元件,說不清是愛是恨。開始學習它吧。
首先當然是建立專案啊,然後修改一下activity_main的佈局檔案,內容如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
>
<ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>

這裡就注意讓它佔滿全屏就好了,按照之前控制元件的邏輯呢,現在只要去MainActiviry裡邊findViewById就行,這個不行,為啥?開頭說了,它比較複雜嘛….這個控制元件呢需要一個介面卡,,我們可以在介面卡裡面幫它繫結資料,方便它來展示
新建一個layout,,程式碼如下

<?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="wrap_content">

    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="50dp"
        android:layout_height
="50dp" android:src="@drawable/apple" />
<TextView android:id="@+id/fruit_text" android:layout_width="90dp" android:layout_height="50dp" android:layout_marginLeft="10dp" android:gravity="center_vertical" android:text="Apple" android:textSize="18dp" /> </LinearLayout>

這個也很簡單,我們想讓這個listView顯示什麼樣式呢,就在這個裡面做就行,現在我做的,就是左邊一個水果圖片,右邊一個名字。然後,我們寫一個方便呼叫的工具類,程式碼如下


/**
 * 工具類
 */

public class Fruits {

    private String name;

    private int imageId;

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

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
}

接下來就是重頭戲了,介面卡,listview的介面卡有很多種,這本書裡使用的是ArrayAdapter,所以,我也是,看程式碼

/**
 * 介面卡
 */

public class FruitAdapter extends ArrayAdapter<Fruits> {

    private int resourceId;

    /**
     * 重寫方法,方便之後呼叫
     * @param context 上下文
     * @param textViewResourceId 要繫結的佈局檔案
     * @param objects 佈局檔案裡面要使用的資料,(函式)
     */
    public FruitAdapter(Context context, int textViewResourceId, List<Fruits> objects) {
        super(context,  textViewResourceId, objects);
        this.resourceId = textViewResourceId;
    }


    /**
     * 重寫getView方法,在這個方法裡面做資料的繫結等操作
     * @param position 當前的item
     * @param convertView 快取的資料
     * @param parent 父佈局
     * @return
     */
    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruits fruits = getItem(position); //獲取當前的item的例項
        View view;
        final ViewHoder viewHoder; //為了優化listview建立的一個內部類,可以不用每次都重新建立item的例項
        //如果快取為空的話,就建立view,,否則,就複用快取的view(這麼做的前提是,每個view的佈局都一樣)
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHoder = new ViewHoder();
            viewHoder.fruitText = (TextView) view.findViewById(R.id.fruit_text);
            viewHoder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            viewHoder.fruitText.setText(fruits.getName());
            viewHoder.fruitImage.setImageResource(fruits.getImageId());
            view.setTag(viewHoder);//將viewHolder的例項儲存在view裡面
        }else {
            view = convertView;
            viewHoder = (ViewHoder) view.getTag();//如果沒有快取就取出來
            viewHoder.fruitText.setText(fruits.getName());
            viewHoder.fruitImage.setImageResource(fruits.getImageId());
        }
        return view;
    }

    private class ViewHoder {
        TextView fruitText;
        ImageView fruitImage;
    }
}

很麻煩是吧,我在這遇到了一個坑,大家可以看到,在 if 和 else 裡面有兩行相同的程式碼,是給圖片和名字賦值的。這時候有人問了,既然viewHolder的例項已經儲存在view裡邊了,為什麼還要再次賦值呢?思維盲點啊,我也想半天啊,它儲存的是例項啊,不重新賦值的話,拿到的值每次都不一樣的啊。

  viewHoder.fruitText.setText(fruits.getName());  viewHoder.fruitImage.setImageResource(fruits.getImageId());

我試了一下,不再次賦值,也能成功執行。但是,每次出現的資料都不同的。想要資料正確,請千萬記得重新賦值。好吧,我這個腦子容易出這種亂七八糟的錯誤,如果有同樣錯的。希望能幫到你。
對了,還有最後MainActivity的程式碼:

public class MainActivity extends AppCompatActivity {

    //建立一個集合,待會要放資料的
    private List<Fruits> fruitList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //這個方法裡邊全是資料
        initFruit();
        //介面卡,要記得繫結你定樣式的那個佈局檔案
        FruitAdapter adapter = new FruitAdapter(MainActivity.this,
                R.layout.fruit_item, fruitList);
        ListView listView = (ListView) findViewById(R.id.list_view);

        listView.setAdapter(adapter);
    }

    //寫了個for迴圈,資料太少,不迴圈的話不夠滑動頁面的
    private void initFruit() {
        for (int i = 0; i < 5; i++) {
            Fruits apple = new Fruits("Apple", R.drawable.apple);
            fruitList.add(apple);
            Fruits banana = new Fruits("Banana", R.drawable.banana);
            fruitList.add(banana);
            Fruits cherry = new Fruits("Cherry", R.drawable.cherry);
            fruitList.add(cherry);
            Fruits grape = new Fruits("Grape", R.drawable.grape);
            fruitList.add(grape);
            Fruits orange = new Fruits("Orange", R.drawable.orange);
            fruitList.add(orange);
            Fruits pear = new Fruits("Pear", R.drawable.pear);
            fruitList.add(pear);
            Fruits watermelon = new Fruits("WatermeIon", R.drawable.watermelon);
            fruitList.add(watermelon);
        }
    }
}

嗯,基本就這樣了