在android中使用listview時需要了解listview加載數據的原理,為了避免listview由於列表項過多每次需要進行new造成性能低下的問題,android中的listview使用了控件復用從而避免了每次進行new控件的問題。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder = null;
if(convertView==null)
{
viewHolder = new ViewHolder();
view = getLayoutInflater().inflate(R.layout.list_item, null);
viewHolder.btn = (Button)view.findViewById(R.id.buttonid);
viewHolder.textView = (TextView)view.findViewById(R.id.textid);
viewHolder.radioBtn = (CheckBox)view.findViewById(R.id.radioid);
view.setTag(viewHolder);
}
else
{
view = convertView;
viewHolder = (ViewHolder)view.getTag();
}
自定義adapter時重寫getView方法時只有當converView為空時才需要創建控件,只需要創建屏幕上剛好可以放下的那幾條控件即可。
在listview item上使用checkbox等空間時需要注意的問題是,checkbox選中的狀態會錯亂,如選中了第一條數據當滾動列表時該選中的狀態可能會跑到其他條目上去,這個問題就是listview復用造成的。
目前該問題的解決我是通過,將選中的checkbox id放入hashmap中,
Map<Integer, Boolean> isCheckMap = new HashMap<Integer, Boolean>();
當滾動listview時判斷該條目位置是否在這個hashmap中,如果在表示之前選中了,如果不在表示未選中將checkbox狀態設為false。
//找到需要選中的條目
if(isCheckMap!=null && isCheckMap.containsKey(position))
{
viewHolder.checkBtn.setChecked(isCheckMap.get(position));
}
else
{
viewHolder.checkBtn.setChecked(false);
}
為了獲取到checkbox的選中事件,還需要實現checkbox的setOnCheckedChangeListener
viewHolder.checkBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int radiaoId = Integer.parseInt(buttonView.getTag().toString());
if(isChecked)
{
//將選中的放入hashmap中
isCheckMap.put(radiaoId, isChecked);
}
else
{
//取消選中的則剔除
isCheckMap.remove(radiaoId);
}
}
});
另外需要注意的一個問題是,由於列表項布局文件使用了checkbox,Button等控件,如果不做設置的話這些控件的監聽事件會優先於listview的setOnItemClickListener事件響應,所以即使listview實現了這個監聽,在點擊item的時候也捕獲不到事件。解決辦法如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- android:descendantFocusability="blocksDescendants"表示覆蓋子空間獲取焦點,解決itemclick無效的問題-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageid"
style="@style/baseLayout"
android:layout_alignParentLeft="true"
android:background="@drawable/sym_keyboard_delete"
/>
<TextView
android:id="@+id/textid"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_toLeftOf="@+id/radioid"
android:text="sdfa" />
<CheckBox
style="@style/baseLayout"
android:id="@+id/radioid"
android:layout_height="50dp"
android:layout_toLeftOf="@+id/buttonid"
/>
<Button
style="@style/baseLayout"
android:layout_height="50dp"
android:id="@+id/buttonid"
android:layout_alignParentRight="true"
android:background="@drawable/sym_keyboard_done"
/>
</RelativeLayout>
</LinearLayout>
在listview item布局頁面的根位置添加android:descendantFocusability="blocksDescendants" 表示覆蓋子控件獲取焦點,解決itemclick無效的問題。
完整的代碼如下:
Activity類
package com.example.sf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
public class listViewActivity extends BaseActivity{
private ListView listView;
private List<HashMap<String, Object>> listData;
private Handler handler = null;
Map<Integer, Boolean> isCheckMap = new HashMap<Integer, Boolean>();
final List<HashMap<String, Integer>> isCheckList = new ArrayList<HashMap<String, Integer>>();
@Override
public int getContentViewId() {
return R.layout.list_main;
}
@Override
public void init() {
handler = new Handler();
listView = (ListView)findViewById(R.id.listid);
listData = getData();
listView.setAdapter(new myAdapter());
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.e("scrollState",scrollState+"");
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if(firstVisibleItem+visibleItemCount<totalItemCount)//判斷是否需要加載數據
{
new Thread(new Runnable() {
@Override
public void run() {
handler.postDelayed(new Runnable() {
@Override
public void run() {
}
},10);
}
}).start();
}
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
Toast.makeText(getApplicationContext(), view.getTag()+"", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 數據封裝
* @return
*/
private List<HashMap<String, Object>> getData()
{
List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
for(int i=0;i<20;i++)
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("radioid", i);
map.put("textview", "本元素的上邊緣"+i);
list.add(map);
}
return list;
}
/**
* 自定義Adapter
* @author Administrator
*
*/
public class myAdapter extends BaseAdapter
{
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int position) {
return listData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
ViewHolder viewHolder = null;
if(convertView==null)
{
viewHolder = new ViewHolder();
view = getLayoutInflater().inflate(R.layout.list_item, null);
viewHolder.btn = (Button)view.findViewById(R.id.buttonid);
viewHolder.textView = (TextView)view.findViewById(R.id.textid);
viewHolder.checkBtn = (CheckBox)view.findViewById(R.id.radioid);
view.setTag(viewHolder);
}
else
{
view = convertView;
viewHolder = (ViewHolder)view.getTag();
}
viewHolder.textView.setText(listData.get(position).get("textview").toString());
viewHolder.checkBtn.setTag(listData.get(position).get("radioid").toString());
//找到需要選中的條目
if(isCheckMap!=null && isCheckMap.containsKey(position))
{
viewHolder.checkBtn.setChecked(isCheckMap.get(position));
}
else
{
viewHolder.checkBtn.setChecked(false);
}
viewHolder.btn.setTag(listData.get(position).get("radioid").toString());
viewHolder.btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "點擊了"+v.getTag(), Toast.LENGTH_LONG).show();
}
});
viewHolder.checkBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int radiaoId = Integer.parseInt(buttonView.getTag().toString());
if(isChecked)
{
//將選中的放入hashmap中
isCheckMap.put(radiaoId, isChecked);
}
else
{
//取消選中的則剔除
isCheckMap.remove(radiaoId);
}
}
});
return view;
}
}
public class ViewHolder
{
private TextView textView;
private CheckBox checkBtn;
private Button btn;
}
}
復制代碼
listview item布局文件
復制代碼
<?xml version="1.0" encoding="utf-8"?>
<!-- android:descendantFocusability="blocksDescendants"表示覆蓋子空間獲取焦點,解決itemclick無效的問題-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageid"
style="@style/baseLayout"
android:layout_alignParentLeft="true"
android:background="@drawable/sym_keyboard_delete"
/>
<TextView
android:id="@+id/textid"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_toLeftOf="@+id/radioid"
android:text="sdfa" />
<CheckBox
style="@style/baseLayout"
android:id="@+id/radioid"
android:layout_height="50dp"
android:layout_toLeftOf="@+id/buttonid"
/>
<Button
style="@style/baseLayout"
android:layout_height="50dp"
android:id="@+id/buttonid"
android:layout_alignParentRight="true"
android:background="@drawable/sym_keyboard_done"
/>
</RelativeLayout>
</LinearLayout>