1. 程式人生 > ><Android基礎>(五) UI開發 Part 2

<Android基礎>(五) UI開發 Part 2

每一個 itemclick new imageview str his () 取出 out

ListView

1)ListView的簡單用法

2)定制ListView界面

3)提升ListView的運行效率

4)ListView的點擊事件

3.5 ListView

3.5.1 ListView的簡單用法

1.新建項目,修改activity_main.xml中的代碼,插入<ListView>控件

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

2.

修改MainActivity中的代碼

public class MainActivity extends AppCompatActivity {

    private String[] data = new String[]{"gareen","teemo","shana","annie",
            "gareen","teemo","shana","annie","gareen","teemo","shana","annie","gareen","teemo","shana","annie",
            "gareen","teemo","shana","annie",};
    @Override
    
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity_layout); 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); } }

a.提供好數據,用一組字符串數組data來測試。

b.數組中數據無法直接傳遞給ListView,需要借助適配器來完成。

ArrayAdapter通過泛型來指定要適配的數據類型,然後在構造函數中把要適配的數據傳入。

將ArrayAdapter的泛型指定為String,在構造函數中依次上傳當前上下文、ListView子項布局的id、以及要適配的數據。

運行程序的結果

技術分享圖片

3.5.2 定制ListView的界面

對ListView界面進行定制,讓顯示更豐富的內容,實現讓英雄名稱旁邊都有各自對應的英雄頭像

1.準備好一組圖片存在drawable-hdpi

2.定義一個實體類,作為ListView適配器的適配類型。新建類Hero

public class Hero {
    private String name;
    private int imageId;

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

    public String getName() {


        return name;
    }
    public int getImageId(){
        return imageId;
    }
}

name表示英雄名字,imageId表示對應的圖片資源id

3.在layout目錄下新建hero_item.xml為ListView指定自定義的布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

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

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

</LinearLayout>

4.創建一個自定義的適配器,繼承自ArrayAdapter,並將泛型指向Hero類。

新建類HeroAdapter。

HeroAdapter重寫了父類的一組構造方法,用於將上下文,ListView子項布局的id和數據都傳遞進來。

另外又重寫了getView()方法。首先通過getItem()方法得到當前項的Hero實例,然後使用LayoutInflater來為這個子項加載傳入的布局。inflate()方法接受3個參數,第三個參數指定成false,表明只讓在父布局中聲明layout屬性生效,但不會為這個View添加父布局。

接下來調用View的findViewById()方法分別獲取ImageView和TextView的實例,並分別調用它們的setImageResource()和setText()方法來設置顯示的圖片和文字,最後將布局返回。

import android.content.Context;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
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 HeroAdapter extends ArrayAdapter<Hero> {
    private int resourceId;

    public HeroAdapter(Context context, int textViewResoureced,
                        List<Hero> objects){
        super(context, textViewResoureced, objects);
        resourceId = textViewResoureced;
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Hero hero = getItem(position);
        View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        ImageView heroImage = (ImageView) view.findViewById(R.id.hero_image);
        TextView heroName = (TextView)view.findViewById(R.id.hero_name);
        heroImage.setImageResource(hero.getImageId());
        heroName.setText(hero.getName());
        return view;
    }
}

5.修改MainActivity中的代碼

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<Hero> heroList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initHeros();
        HeroAdapter adapter = new HeroAdapter(MainActivity.this,
                R.layout.hero_item,heroList);
        ListView listView = (ListView) findViewById(R.id.list_view);
        listView.setAdapter(adapter);
    }

    private void initHeros(){
        for(int i = 0 ; i < 2 ; i ++){
            Hero gareen = new Hero("gareen",R.drawable.gareen);
            heroList.add(gareen);
            Hero annie = new Hero("annie",R.drawable.annie);
            heroList.add(annie);
            Hero teemo = new Hero("teemo",R.drawable.teemo);
            heroList.add(teemo);
            Hero shana = new Hero("shana",R.drawable.shana);
            heroList.add(shana);
        }
    }
}

initHeros()方法用於初始化所有的英雄數據。

在Hero類的構造函數中將水果的名字和對應的圖片id傳入,然後把創建好的對象添加到英雄列表中。

接著在onCreat()方法中創建了HeroAdapter對象,並將HeroAdapter作為適配器傳遞給ListView。

運行程序。

技術分享圖片

定制界面完成。

3.5.3 提升ListView的運行效率

getView()方法中有一個convertView參數,這個參數用於將之前加載好的布局進行緩存,以便之後可以重用。

1.HeroAdapter的gatView()方法中每次都將布局重新加載一邊,當ListView快速滾動時,就有可能成為性能的瓶頸。

修改HeroAdapter中的代碼

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Hero hero = getItem(position);
        View view;
        if(convertView == null){
            view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        }else{
            view = convertView;
        }
        ImageView heroImage = (ImageView) view.findViewById(R.id.hero_image);
        TextView heroName = (TextView)view.findViewById(R.id.hero_name);
        heroImage.setImageResource(hero.getImageId());
        heroName.setText(hero.getName());
        return view;
    }

 if(convertView == null){
            view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
        }else{
            view = convertView;
        }

表示對convertView進行判斷,如果為null,則使用LayoutInflater去加載布局,如果不為null則直接對convertView直接重用。

2. 每次在getView()中會調用View的findViewById()方法來獲取一次控件的實例。可以用ViewHolder來對這部分進行優化。

修改HeroAdapter中的代碼。

  @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Hero hero = getItem(position);
        View view;
        ViewHolder viewHolder;
        if(convertView == null){
            view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.heroImage = (ImageView)view.findViewById(R.id.hero_image);
            viewHolder.heroName = (TextView)view.findViewById(R.id.hero_name);
            view.setTag(viewHolder);
        }else{
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();//重新獲取ViewHolder
        }
        viewHolder.heroImage.setImageResource(hero.getImageId());
        viewHolder.heroName.setText(hero.getName());
        return view;
    }
    
    class ViewHolder{
        ImageView heroImage;
        TextView heroName;
    }

     View view;
        ViewHolder viewHolder;
        if(convertView == null){
            view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.heroImage = (ImageView)view.findViewById(R.id.hero_image);
            viewHolder.heroName = (TextView)view.findViewById(R.id.hero_name);
            view.setTag(viewHolder);
        }else{
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();//重新獲取ViewHolder
        }
        viewHolder.heroImage.setImageResource(hero.getImageId());
        viewHolder.heroName.setText(hero.getName());

  class ViewHolder{
        ImageView heroImage;
        TextView heroName;
    }

提供一個內部類ViewHolder,用於對控件進行緩存。當convertView為null時,創建一個ViewHolder對象,並將控件的實例都存放在ViewHolder中,然後調用setTag()方法,將ViewHolder對象儲存在VIew中。當convertView不為null時,則調用View的getTag()方法,把ViewHolder重新取出。

所有控件實例都緩存在VIewHolder中,就沒有必要每次通過findViewById()方法來獲取控件實例了。

3.5.4 ListView的點擊事件

給每一個Item添加Toast,修改MainActivity中的代碼。

     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) {
                Hero hero = heroList.get(position);
                Toast.makeText(MainActivity.this, hero.getName(), Toast.LENGTH_SHORT).show();
            }
        });

技術分享圖片

用setOnItemClikListener()方法為ListView註冊一個監聽器,當用戶點擊了ListView中的任何一個子項時,就會回調onItemClick()方法。在該方法中即可通過position參數判斷出用戶點擊的是哪一個子項,然後獲得相應的name,通過Toast展現出來。

<Android基礎>(五) UI開發 Part 2