android學習八(ListView的高級使用)

ListView在android開放中用的比較多,所以接下來就進行ListView的使用的講解。

首先創建一個android項目,項目名為ListViewTest.

ListView的簡單使用

修改佈局文件,修改後代碼如下:

 

修改MainActivity的代碼:

 

package com.wj.listviewtest;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

	private String [] data={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 adapter=new ArrayAdapter(
				MainActivity.this,android.R.layout.simple_list_item_1,
				data);
		ListView listView=(ListView) findViewById(R.id.list_view);
		listView.setAdapter(adapter);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

 

運行程序結果如下:

 

ListView是用於顯示大量數據的,這些數據我們可以事先準備好,也可以從網上或者數據中中讀取。

android.R.layout.simple_list_item_1是作為ListView子項佈局的id,這是android內置的佈局文件裡面隻有一個TextView,可用於簡單地顯示一段文本。

 

2.定制ListView的界面

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

接著定義一個實體類,作為ListView適配器的適配類型,新建Fruit類,代碼如下:

 

package com.wj.listviewtest;

public class Fruit {

	private String name;//水果名
	private int imageId;//水果圖片的資源id
	
	//無參構造函數
	public Fruit(){}
	//有參構造函數
	public Fruit(String name,int imageId){
		this.name=name;
		this.imageId=imageId;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getImageId() {
		return imageId;
	}
	public void setImageId(int imageId) {
		this.imageId = imageId;
	}
	
}

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

 

 



    

    
    

 

這個佈局中我們定義瞭一個ImageView用於顯示水果的圖片,又定義瞭一個TextView用於顯示水果的名稱。

接著我們要創建一個自定義的適配器,這個適配器繼承自ArrayAdapter,並將泛型指定為Fruit。新建一個類FruitAdapter代碼如下:

 

package com.wj.listviewtest;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class FruitAdapter extends ArrayAdapter {

	private int resourceId;
	public FruitAdapter(Context context, int textViewResourceId,
			List objects) {
		super(context, textViewResourceId, objects);
		// TODO Auto-generated constructor stub
		/*
		 * 重寫瞭父類的構造函數,用於將上下文,ListView子項佈局的id和數據都傳進來。
		 * */
		resourceId=textViewResourceId;
	}
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		//return super.getView(position, convertView, parent);
		/*
		 * 重寫getView方法,這個方法在每個子項被滾動到屏幕內的時候會被調用,在getView方法中
		 * ,首先通過getItem方法得到當前項的Fruit實例,然後使用LayoutInflater來為這個子項加載
		 * 我們傳入的佈局,接著調用View的findViewById方法分別獲取到ImageView和TextView的實例,
		 * 並分別調用他們的setImageResource和setText方法來設置顯示的圖片和文字,最後返回佈局
		 * */
		Fruit fruit=getItem(position);//獲取當前項的Fruit實例
		//初始話ListView的子項佈局
		View view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		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;
	}
	
	
	

}

修改MainActivity的代碼如下:

 

 

package com.wj.listviewtest;

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

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

	/*private String [] data={apple,banana,orange,
			watermelon,pear,grape,pineapple,strawberry,
			cherry,mango};*/
	private List fruitList=new ArrayList();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		/*//創建適配器
		ArrayAdapter adapter=new ArrayAdapter(
				MainActivity.this,android.R.layout.simple_list_item_1,
				data);
		ListView listView=(ListView) findViewById(R.id.list_view);
		listView.setAdapter(adapter);*/
		initFruits();//初始化水果
		FruitAdapter adapter=new FruitAdapter(MainActivity.this,
				R.layout.fruit_item, fruitList);
		ListView listView=(ListView) findViewById(R.id.list_view);
		//設置適配器
		listView.setAdapter(adapter);
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	public void initFruits(){
		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);
	}
	
	

}

運行程序,結果如下:

 

 

這是一個簡單的界面,不過更加復雜的界面也可以通過修改fruit_item.xml文件來實現更加復雜的ListView。

 

 

下面我們來提示下ListView的運行效率。

目前我們的ListView的運行效率是很低的,因為在FruitAdapter的getView方法中每次都要將佈局重寫加載瞭一遍,當ListView快速滾動的時候這就會成為性能的瓶頸。仔細觀察,getView方法中還有一個convertView參數,這個參數用於將之前加載好的佈局進行緩存,以便之後可以進行重用,修改FruitAdapter中的代碼,帶入如下所示:

 

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		//return super.getView(position, convertView, parent);
		/*
		 * 重寫getView方法,這個方法在每個子項被滾動到屏幕內的時候會被調用,在getView方法中
		 * ,首先通過getItem方法得到當前項的Fruit實例,然後使用LayoutInflater來為這個子項加載
		 * 我們傳入的佈局,接著調用View的findViewById方法分別獲取到ImageView和TextView的實例,
		 * 並分別調用他們的setImageResource和setText方法來設置顯示的圖片和文字,最後返回佈局
		 * */
		Fruit fruit=getItem(position);//獲取當前項的Fruit實例
		View view;
		/*
		 * 在getView()方法中進行判斷,如果convertView為空,則使用LayoutInflater去加載佈局,
		 * 如果不為空,則直接對convertView進行重用。這樣可以大大提升ListView的效率,在快速滾動的時候
		 * 也可以表現更好的性能。
		 * */
		if(convertView==null){
			//初始話ListView的子項佈局
			view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		}else{
			view=convertView;
		}
		/*//初始話ListView的子項佈局
		View view=LayoutInflater.from(getContext()).inflate(resourceId, null);*/
		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方法中還是會調用View的view.findViewById()方法來獲取一次控件的實例。我們可以借助一個ViewHolder來對這部分性能進行優化,修改FruitAdapter中的代碼,如下所示:

 

 

package com.wj.listviewtest;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

public class FruitAdapter extends ArrayAdapter {

	private int resourceId;
	public FruitAdapter(Context context, int textViewResourceId,
			List objects) {
		super(context, textViewResourceId, objects);
		// TODO Auto-generated constructor stub
		/*
		 * 重寫瞭父類的構造函數,用於將上下文,ListView子項佈局的id和數據都傳進來。
		 * */
		resourceId=textViewResourceId;
	}
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		//return super.getView(position, convertView, parent);
		/*
		 * 重寫getView方法,這個方法在每個子項被滾動到屏幕內的時候會被調用,在getView方法中
		 * ,首先通過getItem方法得到當前項的Fruit實例,然後使用LayoutInflater來為這個子項加載
		 * 我們傳入的佈局,接著調用View的findViewById方法分別獲取到ImageView和TextView的實例,
		 * 並分別調用他們的setImageResource和setText方法來設置顯示的圖片和文字,最後返回佈局
		 * */
		Fruit fruit=getItem(position);//獲取當前項的Fruit實例
		View view;
		ViewHolder viewHolder;
		/*
		 * 在getView()方法中進行判斷,如果convertView為空,則使用LayoutInflater去加載佈局,
		 * 如果不為空,則直接對convertView進行重用。這樣可以大大提升ListView的效率,在快速滾動的時候
		 * 也可以表現更好的性能。
		 * */
		if(convertView==null){
			//初始話ListView的子項佈局
			view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		    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
		}
		/*//初始話ListView的子項佈局
		View view=LayoutInflater.from(getContext()).inflate(resourceId, null);*/
		/*ImageView fruitImage=(ImageView) view.findViewById(R.id.fruit_image);
		TextView fruitName=(TextView) view.findViewById(R.id.fruit_name);*/
		viewHolder.fruitImage.setImageResource(fruit.getImageId());
		viewHolder.fruitName.setText(fruit.getName());
		return view;
	}
	
	
	class ViewHolder{
		ImageView fruitImage;
		TextView  fruitName;
	}

}

通過上面兩步優化後,ListView的運行效率已經不錯瞭。

 

 

ListView的點擊事件

修改代碼如下:

 

package com.wj.listviewtest;

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

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {

	/*private String [] data={apple,banana,orange,
			watermelon,pear,grape,pineapple,strawberry,
			cherry,mango};*/
	private List fruitList=new ArrayList();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		/*//創建適配器
		ArrayAdapter adapter=new ArrayAdapter(
				MainActivity.this,android.R.layout.simple_list_item_1,
				data);
		ListView listView=(ListView) findViewById(R.id.list_view);
		listView.setAdapter(adapter);*/
		initFruits();//初始化水果
		FruitAdapter adapter=new FruitAdapter(MainActivity.this,
				R.layout.fruit_item, fruitList);
		ListView listView=(ListView) findViewById(R.id.list_view);
		//設置適配器
		listView.setAdapter(adapter);
		/*
		 * setOnItemClickListener()方法來為ListView註冊一個監聽器,當用戶點擊瞭ListView
		 * 中的任何一個子項時就會回調nItemClick()方法,在這個方法中可以通過position參數判斷出用戶點擊
		 * 的是哪一個子項,然後獲取相應的水果,並通過Toast將水果的名字顯示出來。
		 * */
		listView.setOnItemClickListener(new OnItemClickListener(){

			@Override
			public void onItemClick(AdapterView parent, View view, int position,
					long id) {
				// TODO Auto-generated method stub
				Fruit fruit=fruitList.get(position);
				Toast.makeText(MainActivity.this, 
						fruit.getName(), Toast.LENGTH_SHORT).show();
				
			}
			
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	public void initFruits(){
		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);
	}
	
	

}

 

運行結果如下;

 

好瞭ListView的使用就總結到這裡瞭。

單位和尺寸

px是像素的意思,即屏幕中可以顯示的最小單位,我們應用裡任何可見的東西都是由一個個像素點組成的。

pt是磅數的意思,1磅等於1/72英寸,一般pt都會作為字體的單位來使用。

dp是密度無關的像素的意思,也被稱作為dip,和px相比,它在不同密度的屏幕中的顯示比例保持一致。

sp是可伸縮像素的意思,它采用瞭和dp同樣的設計理念,解決瞭文字大小的適配問題。

android中的密度就是屏幕每英寸所包含的像素數,通常以dpi為單位。

根據android的規定,在160dpi的屏幕上,1dp等於1px,而在320dpi的屏幕上,1dp就等於2px。因此,使用dp來指定控件的寬和高,就可以保證控件在不同密度的屏幕中的顯示比例保存一致。所以dp可以理解為顯示比例(像素除以英寸)

在編寫android程序的時候,盡量將控件或佈局的大小指定成match_parent或wrap_content,如果必須要指定一個固定的值,則使用dp來作為單位,指定文字的大小的時候使用sp。

轉載請註明來著:https://blog.csdn.net/j903829182/article/details/40683293

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。