Android: ListView 和 RecyclerView 對比(一)

1、ListView

由於手機屏幕空間有限,能夠一次性在屏幕上顯示的內容並不多,當程序中有大量的數據需要展示的時候,就可以藉助 ListView 來實現。ListView 允許用戶通過手指上下滑動的方式將屏幕外的數據滾動到屏幕內。

(1)ListView 的簡單用法

首先新建一個項目,修改 activity_main.xml 中的代碼,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</LinearLayout>

然後修改 MainActivity 中代碼,如下:

public class MainActivity extends AppCompatActivity {
    private String[] data = {"Apple1", "Apple2", "Apple3", "Apple4", "Apple5", "Apple6",
            "Apple7", "Apple8", "Apple9", "Apple10", "Apple11", "Apple12", "Apple13", "Apple14",
            "Apple15", "Apple16", "Apple17", "Apple18", "Apple19", "Apple20"};
    @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 的,我們還需要藉助適配器來完成,這裏我們使用 ArrayAdapter。它可以使用泛型來指定要適配的數據類型,然後再構造函數中把要適配的數據傳入。這裏我們提供的數據是字符串,因此將 ArrayAdapter 的泛型指定爲 String,然後再 ArrayAdapter 的構造函數中依次傳入當前上下文、ListView 子項佈局的id,以及要適配的數據。

注意 android.R.layout.simple_list_item_1 作爲 ListView 子項佈局的id,這是一個 Android 內置的佈局文件,裏面只包含一個 TextView。

最後,調用 ListView 的 setAdapter() 方法,將構建好的適配器對象傳遞進去。

(2)定製 ListView 的界面

準備一組圖片,分別對應上面提供的每一種水果。

首先新建一個實體類,作爲 ListView 適配器的適配類型。新建類 Fruit,Fruit 只包含兩個字段,name 表示名稱,imageId表示水果對應圖片的資源id,如下:

public class Fruit {
    private String name;
    private int imageId;
    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }
    public String getName() {
        return name;
    }
    public int getImageId() {
        return imageId;
    }
}

然後爲 ListView 的子項指定一個我們自定義的佈局,新建 fruit_item.xml,在這個佈局中我們定義了一個 ImageView 來顯示水果圖片,定義了一個 TextView 用於顯示水果的名稱。代碼如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    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>

接下來創建一個自定義的適配器,這個適配器繼承自 ArrayAdapter,並將泛型真得 Fruit 類。新建類 FruitAdapter,如下:

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

FruitAdapter 重寫了父類的一組構造函數,用於將上下文、ListView 子項佈局的id和數據都傳遞進來。另外重寫了 getView() 方法。這個方法在每個子項被滾到屏幕內的時候會被調用。在 getView() 方法中,首先通過 getItem() 方法得到當前項的 Fruit 實例,然後使用 LayoutInflater 來爲這個子項加載我們傳入的佈局。
然後修改 MainActivity 中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

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

    @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 對象,然後把創建好的對象添加到水果列表中。接着在 onCreate() 方法中創建了 FruitAdapter 對象,並將 FruitAdapter 作爲適配器傳遞給 ListView。

(3)提升ListView 的運行效率

在使用 ListView 時有很多細節可以優化,其中運行效率就是很重要的一點。目前我們 ListView 的運行效率是很低的,因爲在 FruitAdapter 的 getView() 方法中,每次都將佈局重新加載了一遍,當 ListView 快速滾動的時候,這就會成爲性能的瓶頸。
在 getView() 方法中有一個 convertView 參數,這個參數用於將之前加載喊得佈局進行緩存,以便之後可以進行重用,修改 FruitAdapter,如下所示:

public class FruitAdapter extends ArrayAdapter<Fruit> {
    ...
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = getItem(position); // 獲取當前項的Fruit實例
        View view;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        } else {
            view = convertView;
        }
        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;
    }
}

在getView()方法中進行了判斷,如果 convertView 爲null,則使用 LayoutInflater 去加載佈局,如果不爲null則直接對 convertView 進行重用。這樣就大大提高了 ListView 的運行效率,在快速滾動的時候也可以表現出更好的性能。

目前雖然已經不會再重複去加載佈局,但是每次在 getView() 方法中還是會調用 View 的 findViewById() 方法來獲取一次控件的實例。我們可以藉助一個 ViewHolder 來對這部分性能進行優化修改代碼,修改代碼,如下如下:

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;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage = (ImageView) view.findViewById (R.id.fruit_image);
            viewHolder.fruitName = (TextView) view.findViewById (R.id.fruit_name);
            view.setTag(viewHolder); // 將ViewHolder存儲在View中
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); // 重新獲取ViewHolder
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }
    class ViewHolder {

        ImageView fruitImage;

        TextView fruitName;
    }
}

我們新增了一個內部類 ViewHolder ,用於對控件的實例進行緩存。當 convertView 爲null時,創建 ViewHolder 對象,並將控件的實例存放在 ViewHolder 裏,然後調用 View 的 setTag() 方法,將 ViewHolder 對象存儲在View 中。當 convertView 部null的時候,則調用View的 getTag() 方法,把 ViewHolder 重新取出。這樣所有控件的實例緩存在了 ViewHolder 裏,就不用每次都通過 findViewById() 方法來獲取控件的實例了。

(4)ListView 的點擊事件

修改 MainActivity 中的 onCreate() 方法,如下:

    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 參數判斷出用戶點擊的是哪一個子項。

2、RecyclerView

RecyclerView 可以說是一個增強版的ListView,不僅可以輕鬆實現和 ListView 同樣的效果,還優化了 ListView 中存在的各種不足之處。

(1)RecyclerView 的基本用法

和百分比佈局類似,RecyclerView 也屬於新增控件,爲了讓 RecyclerView 在所有 Android 版本上都能使用,將 RecyclerView 定義在了 support 庫當中。因此首先要在項目的 build.gradle 中添加相應的依賴庫才行。

dependencies {
    ...
    implementation 'com.android.support:recyclerview-v7:24.2.1'
}

然後修改 antivity_main.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">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

將之前的 Fruit 類和 fruit_item.xml 也複製過來。然後爲 RecyclerView 準備一個適配器,新建 FruitAdapter 類,讓這個適配器繼承自 RecyclerView.Adapter,並將泛型指定爲 FruitAdapter.ViewHolder。其中 ViewHolder 是我們在 FruitAdapter 中定義的一個內部類,代碼如下:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            fruitName = (TextView) view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

這裏首先定義了一個內部類 ViewHolder ,ViewHolder 要繼承自 RecyclerView.ViewHolder,然後 ViewHolder 的構造函數中要傳入一個 View 參數,這個參數通常就說 RecyclerView 子項的最外層佈局,那麼我們就可以通過 findViewById() 方法來獲取到佈局中的ImageView和TextView的實例了。

在 FruitAdapter 的構造函數中用於將要展示的數據源傳進來,並賦值給一個全局變量 mFruitList。由於 FruitAdapter 繼承自 RecyclerView.ViewHolder 的,就必須重寫 onCreateViewHolder()、onBindViewHolder()、getItemCount()這3個方法。

onCreateViewHolder() 方法用於創建 ViewHolder 實例,我們在這個方法中將 fruit_item 佈局加載進來,然後創建一個 ViewHolder 實例,並把加載出來的佈局傳入到構造函數當中,最後將 ViewHolder 實例返回。onBindViewHolder() 方法是用於對RecyclerView子項的數據進行賦值的,會在每個子項被滾動到屏幕內的時候執行,這裏我們通過 position 參數得到當前 Fruit 實例,然後再將數據設置到 ViewHolder 的 ImageView 和 TetView 中。getItemCount() 返回數據源的長度。

修改 MainActivity 中的代碼:

public class MainActivity extends AppCompatActivity {

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.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() 方法,用於初始化數據。然後在 onCreate() 方法中,我們先獲取到 RecyclerView 的實例,然後創建了一個 LinearLayoutManager 對象,並將它設置到 RecyclerView 當中。 LayoutManager 用於指定 RecyclerView 的佈局方式,LinearLayoutManager 是線性佈局的意思,可以實現和 ListView 類似的效果。接下來創建了 FruitAdapter 實例,並將數據傳入到其構造函數中,最後調用 RecyclerView 的 setAdapter() 方法來完成適配器設置。

(2)、實現橫向滾動和瀑布流佈局

使用 RecyclerView 實現橫向滾動。因爲目前這個佈局裏的元素是水平排列的,適用於縱項滾動的場景,如果需要實現橫向滾動的話,應該把 fruit_item 裏的元素改爲成垂直排列。修改 fruit_item.xml 中的代碼:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp" />
</LinearLayout>

接下來修改 MainActivity 中的代碼

public class MainActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //新增
        layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }
    ...
}

MainActivity 中加入了一行代碼,調用 LinearLayoutManager 的 setOrientation() 方法來設置佈局的排列方向,默認爲縱向排列,LinearLayoutManager.HORIZONTAL 表示橫向排列。

RecyclerView 能實現 ListView 很難或者根本不能實現的效果主要是因爲 ListView 的佈局排列是由自身去管理的,而 RecyclerView 則將這個工作交給了 LayoutManager ,LayoutManager 中定製了一套可擴展的佈局排列接口,子類只要按照接口的規範來實現,就能定製出各種不同排列方式的佈局了。

使用 RecyclerView 實現瀑布流佈局。除了 LinearLayoutManager 之外 RecyclerView 還提供了 GridLayoutManager 用於實現網格佈局,StaggeredGridLayoutManager 用於實現瀑布流佈局。下面實現瀑布流佈局,修改 fruit_item.xml 中的部分屬性 :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp">
    <ImageView
        android:id="@+id/fruit_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    <TextView
        android:id="@+id/fruit_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:layout_marginTop="10dp" />
</LinearLayout>

接着修改 MainActivity 中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initFruits();
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        StaggeredGridLayoutManager layoutManager = new
                StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        FruitAdapter adapter = new FruitAdapter(fruitList);
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit(getRandomLengthName("Apple"), R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit(getRandomLengthName("Banana"), R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit(getRandomLengthName("Orange"), R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit(getRandomLengthName("Watermelon"), R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit(getRandomLengthName("Pear"), R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit(getRandomLengthName("Grape"), R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit(getRandomLengthName("Pineapple"), R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit(getRandomLengthName("Strawberry"), R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit(getRandomLengthName("Cherry"), R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit(getRandomLengthName("Mango"), R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }

    private String getRandomLengthName(String name) {
        Random random = new Random();
        int length = random.nextInt(20) + 1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(name);
        }
        return builder.toString();
    }
}

在 onCreate() 方法中,創建了一個 StaggeredGridLayoutManager 的實例。StaggeredGridLayoutManager 的構造函數接收兩個參數,第一個參數用於指定佈局的列數,傳入3表示3列;第二個參數用於指定佈局的排列方向,StaggeredGridLayoutManager.VERTICAL 表示縱向佈局。不過由於瀑布流佈局需要各個子項高度不一致才能看出想過,所以修改 initFruits() 方法。

使用 RecyclerView 實現網格佈局。修改 MainActivity 中的代碼

GridLayoutManager layoutManager=new GridLayoutManager(this,3);

可以看到GridLayoutManager需要傳遞兩個參數,一個是上下文對象,另一個是一行顯示幾列的參數常量。通過效果圖能夠很清晰的看出網格佈局與瀑布流佈局直接的差別。

 

(3)RecyclerView 的點擊事件

不同與 ListView 的是,RecyclerView 並沒有提供類似與 setOnItemClickListener() 這樣的註冊監聽方法,而是需要我們自己給子項具體的 View 去註冊監聽事件。

修改 FruitAdapter 中的代碼:

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        View fruitView;
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitView = view;
            fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            fruitName = (TextView) view.findViewById(R.id.fruit_name);
        }
    }

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.fruit_item, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        holder.fruitView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"View "+ fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });
        holder.fruitImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = holder.getAdapterPosition();
                Fruit fruit = mFruitList.get(position);
                Toast.makeText(v.getContext(),"Image  "+ fruit.getName(),Toast.LENGTH_LONG).show();
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }
}

我們先修改了 ViewHolder,在 ViewHolder 中添加了 fruitView 變量來保存子項最外層的實例,然後在 onCreateViewHolder() 方法中註冊點擊事件就行了。這裏分別爲最外層佈局和 ImagView 都註冊了點擊事件。

RecyclerView 可以輕鬆實現子項任意控件或佈局的點擊事件。在點擊事件中,先獲取用戶點擊的 position ,然後通過 position 獲取Fruit的實例。當然,也可以自己再這個FruitAdapter裏面寫個interface接口,寫一個或者幾個方法,外部傳入interface實例,實現方法。點擊事件的onclick裏面直接調用方法即可。

發佈了81 篇原創文章 · 獲贊 15 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章