我正在尝试创建一个列表,显示一个不确定的进度条作为最后一个条目,同时获取更多数据。我可以显示条形图并获取/添加数据,但在加载时向上和向下滚动会导致显示多个进度条。
我有一个使用ArrayAdapter的ListActivity。每行的布局如下。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:background="@drawable/textlines" android:padding="2dip">
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="@+id/rowContent">
<TextView android:height="20sp" android:text=""
android:id="@+id/search_display" android:layout_width="fill_parent"
android:textSize="16sp" android:layout_height="20sp" android:gravity="left" />
</LinearLayout>
<LinearLayout android:layout_height="wrap_content"
android:layout_width="fill_parent" android:id="@+id/rowSpinner"
android:padding="3px" android:gravity="center" android:visibility="gone">
<ProgressBar android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/progress"
android:indeterminate="true" />
</LinearLayout>
</RelativeLayout>
ListView有一个带有以下onScroll方法的OnScrollListener。
public void onScroll(final AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
// detect if last item is visible
if ((visibleItemCount < totalItemCount)
&& (firstVisibleItem + visibleItemCount == totalItemCount))
{
if (false == scrollTaskRunning)
{
scrollTaskRunning = true;
getMoreData(totalItemCount);
}
}
}
getMoreData调用AsyncTask,它可以获取更多数据以添加到适配器。在onPreExecute中,我调用showSpinner() -
private void showSpinner()
{
// nothing to do if there's already a spinner visible
if (isSpinVisible == true) return;
// hide the progress spinner
if (0 < lvList.getChildCount())
{
View vRow = lvList.getChildAt(lvList.getChildCount() - 1);
vRow.findViewById(R.id.rowContent).setVisibility(View.GONE);
vRow.findViewById(R.id.rowSpinner).setVisibility(View.VISIBLE);
}
isSpinVisible = true;
}
并在其onPostExecute / onCancelled中调用hideSpinner(),它是相同的代码,除了以另一种方式检查isSpinVisible标志,并且GONE和VISIBLE交换。据我所知,交换代码只会被调用一次,但如果你上下滚动,最后会显示多个条目并显示进度条。
我尝试这样做而不是hideSpinner() -
private void hideSpinner()
{
// nothing to do if there's no spinner visible
if (isSpinVisible == false) return;
// show the progress spinner
int iChildCount = lvList.getChildCount();
if (0 < lvList.getChildCount())
{
for (int i = 0; i < iChildCount; i++)
{
View vRow = lvList.getChildAt(iChildCount);
if (null != vRow)
{
vRow.findViewById(R.id.rowContent).setVisibility(View.VISIBLE);
vRow.findViewById(R.id.rowSpinner).setVisibility(View.GONE);
}
}
}
else if (null != pbSearch)
{
pbSearch.setVisibility(View.GONE);
}
isSpinVisible = false;
}
但vRow为null,某些进度条仍然显示。我该如何解决?或者,有更好的方法吗? (我想我可以用我的ArrayAdapter的getView()
方法做一些事情,但我无法解决它。)
ETA :这answer似乎解释了我遇到的问题,但知道这并没有帮助我找到解决方法。
ETA2 :我试过这样做:
final LayoutInflater mInflater = (LayoutInflater)
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
aapSearchResults = new ArrayAdapter<ParsedXML>(this, R.layout.search_row, saData)
{
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row;
// get the view
if (null == convertView)
{
row = mInflater.inflate(R.layout.search_row, null);
}
else
{
row = convertView;
}
// bind the data to the view
TextView tv = (TextView) row.findViewById(R.id.search_display);
tv.setText(getItem(position).name);
// show data, hide spinner
row.findViewById(R.id.rowContent).setVisibility(View.VISIBLE);
row.findViewById(R.id.rowSpinner).setVisibility(View.GONE);
// if the current position is the last, and a task is running,
// show the progress bar
if (taskRunning && (position == this.getCount()-1))
{
row.findViewById(R.id.rowContent).setVisibility(View.GONE);
row.findViewById(R.id.rowSpinner).setVisibility(View.VISIBLE);
}
return row;
}
};
lvList.setAdapter(aapSearchResults);
但我显然仍然犯了一个逻辑错误,因为有时上下滚动会让我感到空白。 (这是因为计数已经改变了吗?)
答案 0 :(得分:2)
一般来说,你不应该直接触摸ListView
的孩子。事实上,在他们离开你的适配器的getView()
巢之后,你应该认为它们是完全独立的并且完全脱离你的直接控制。您可以控制它们的唯一方法是调用notifyDataSetChanged()
并让ListView创建新的。
要解决您的问题,请执行以下操作:
public class MyAdapter extends ArrayAdapter[…]{
//[…]
private boolean mIsLoading = false;
public void setIsLoading(boolean isLoading){
if (mIsLoading != isLoading){
mIsLoading = isLoading;
notifyDataSetChanged();
}
}
@Override
public int getCount(){
return super.getCount() + (isLoading ? 1 : 0);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mIsLoading && position == (getCount() - 1)){
//return your progress view goes here. Ensure that it has the ID R.id.progress;
}else{
if (convertView != null && convertView.getId() == R.id.progress){
convertView = null;
}
return super.getView(position, convertView, parent);
}
}
}
答案 1 :(得分:0)
我建议你改用BaseAdapter。当显示列表中的最后一个元素时,它会自动加载更多元素。