【发布时间】:2017-07-14 15:02:51
【问题描述】:
我正在开发一个 ListView,它在屏幕之外填充数据(需要滚动)并面临数据重复的问题。通过一些研究,我实现了一个 ViewHolder,解决了重复数据的问题。但是,ListView 中的某些元素不适用于数据 - 而是定位 - 结果,每次我滚动视图并自行回收时,这些元素仍然会变得混乱。下面是 ListView 适配器和 ViewHolder 代码:
public class ListAdapter : BaseAdapter
{
private readonly Activity activity;
public ListAdapter(Activity a)
{
activity = a;
}
public override int Count
{
get { return nameTexts.Length; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
View view = convertView;
if (view == null)
{
holder = new ViewHolder();
view = activity.LayoutInflater.Inflate(Resource.Layout.Hospital_List_Item, parent, false);
holder.hospitalName = view.FindViewById<TextView>(Resource.Id.selectHospital_HospitalText);
view.Click += delegate
{
Intent intent = new Intent(activity, typeof(Request_Appointment));
intent.PutExtra("hospitalName", nameTexts[position]);
activity.StartActivity(intent);
};
// Set alternatiing background of row
if (position % 2 == 1)
{
view.SetBackgroundResource(Resource.Color._8_white);
}
view.Tag = holder;
}
else
{
holder = view.Tag as ViewHolder;
}
// Set height of row
view.LayoutParameters.Height = Select_Hospital.LIST_HEIGHT / 6;
// Row contents
holder.hospitalName.Text = nameTexts[position];
System.Diagnostics.Debug.WriteLine(position);
return view;
}
private readonly string[] nameTexts =
{
"Hospital 1",
"Hospital 2",
"Hospital 3",
"Hospital 4",
"Hospital 5",
"Hospital 6",
"Hospital 7",
"Hospital 8",
"Hospital 9",
"Hospital 10",
"Hospital 11",
"Hospital 12",
"Hospital 13",
"Hospital 14",
"Hospital 15",
"Hospital 16",
"Hospital 17",
"Hospital 18",
"Hospital 19",
"Hospital 20",
"Hospital 21",
"Hospital 22",
"Hospital 23",
"Hospital 24",
"Hospital 25"
};
}
// ViewHolder
class ViewHolder : Java.Lang.Object
{
public TextView hospitalName { get; set; }
public ToggleButton hospitalFavourites { get; set; }
}
Hospital_List_Item axml 代码:
<?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="fill_parent">
<TextView
android:id="@+id/selectHospital_HospitalText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="25dp"
android:layout_centerVertical="true"
android:textColor="@color/dark_blue" />
<ToggleButton
android:id="@+id/selectHospital_FavouritesToggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="25dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
</RelativeLayout>
初始屏幕:
滚动后:
注意:点击任意行项会显示点击行的位置,滚动后返回错误值。
不按预期工作的元素是交替背景以及点击事件。我尝试将它们移到 if (view == null) 块之外,但这使它变得更糟。非常感谢任何帮助!
-编辑-
更新代码:
public class ListAdapter : BaseAdapter
{
private readonly Activity activity;
public ListAdapter(Activity a)
{
activity = a;
}
public override int Count
{
get { return nameTexts.Length; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
View view = convertView;
int type;
if (view == null)
{
holder = new ViewHolder();
view = activity.LayoutInflater.Inflate(Resource.Layout.Hospital_List_Item, parent, false);
holder.hospitalName = view.FindViewById<TextView>(Resource.Id.selectHospital_HospitalText);
holder.hospitalFavourites = view.FindViewById<ToggleButton>(Resource.Id.selectHospital_FavouritesToggle);
holder.position = position;
System.Diagnostics.Debug.WriteLine(holder.position);
view.Click += delegate
{
Intent intent = new Intent(activity, typeof(Request_Appointment));
intent.PutExtra("hospitalName", holder.hospitalName.Text);
activity.StartActivity(intent);
};
view.Tag = holder;
}
else
{
holder = view.Tag as ViewHolder;
}
// Set height of row
view.LayoutParameters.Height = Select_Hospital.LIST_HEIGHT / 6;
// Set alternating background of row
type = GetItemViewType(holder.position);
if (type == 0)
{
view.SetBackgroundResource(Resource.Color._8_white);
}
// Row contents
holder.hospitalName.Text = nameTexts[position];
holder.hospitalFavourites.Text = position.ToString();
holder.hospitalFavourites.SetOnCheckedChangeListener(null);
holder.hospitalFavourites.Click += delegate
{
holder.hospitalFavourites.Text = position.ToString();
};
return view;
}
// Number of different rows
public override int ViewTypeCount
{
get
{
return 2;
}
}
// To alternate rows
public override int GetItemViewType(int position)
{
return position % 2 == 1 ? 0 : 1;
}
private readonly string[] nameTexts =
{
"Hospital 1",
"Hospital 2",
"Hospital 3",
"Hospital 4",
"Hospital 5",
"Hospital 6",
"Hospital 7",
"Hospital 8",
"Hospital 9",
"Hospital 10",
"Hospital 11",
"Hospital 12",
"Hospital 13",
"Hospital 14",
"Hospital 15",
"Hospital 16",
"Hospital 17",
"Hospital 18",
"Hospital 19",
"Hospital 20",
"Hospital 21",
"Hospital 22",
"Hospital 23",
"Hospital 24",
"Hospital 25"
};
}
class ViewHolder : Java.Lang.Object
{
public TextView hospitalName { get; set; }
public ToggleButton hospitalFavourites { get; set; }
public int position { get; set; }
}
-EDIT 2- (OnClick lambda)
public class RecyclerAdapter : RecyclerView.Adapter
{
private readonly Activity activity;
public event EventHandler<int> ItemClick;
public RecyclerAdapter(Activity a)
{
activity = a;
}
public override int ItemCount
{
get
{
return nameTexts.Length;
}
}
private void OnClick (int position)
{
ItemClick?.Invoke(this, position);
}
private void OnItemClick(object sender, int position)
{
int buttonNum = position + 1;
Toast.MakeText(activity, "This is button number " + buttonNum, ToastLength.Short).Show();
}
public override long GetItemId(int position)
{
return position;
}
public override int GetItemViewType(int position)
{
return position % 2 == 1 ? 0 : 1;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
ViewHolder vh = holder as ViewHolder;
// Set height of row
vh.ItemView.LayoutParameters.Height = Select_Hospital.LIST_HEIGHT / 6;
// Set alternating background of row
int type = GetItemViewType(position);
if (type == 0)
{
vh.ItemView.SetBackgroundResource(Resource.Color._8_white);
}
vh.hospitalName.Text = nameTexts[position];
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.sublayout_Hospital_List_Item, parent, false);
ViewHolder holder = new ViewHolder(view, OnClick);
holder.ItemView.Click += delegate
{
Intent intent = new Intent(activity, typeof(Request_Appointment));
intent.PutExtra("hospitalName", holder.hospitalName.Text);
activity.StartActivity(intent);
};
ItemClick += OnItemClick;
return holder;
}
private readonly string[] nameTexts =
{
"Hospital 1",
"Hospital 2",
"Hospital 3",
"Hospital 4",
"Hospital 5",
"Hospital 6",
"Hospital 7",
"Hospital 8",
"Hospital 9",
"Hospital 10",
"Hospital 11",
"Hospital 12",
"Hospital 13",
"Hospital 14",
"Hospital 15",
"Hospital 16",
"Hospital 17",
"Hospital 18",
"Hospital 19",
"Hospital 20",
"Hospital 21",
"Hospital 22",
"Hospital 23",
"Hospital 24",
"Hospital 25"
};
}
class ViewHolder : RecyclerView.ViewHolder
{
public TextView hospitalName { get; set; }
public ToggleButton hospitalFavourites { get; set; }
public ViewHolder (View view, Action<int> listener) : base(view)
{
hospitalName = view.FindViewById<TextView>(Resource.Id.selectHospital_HospitalText);
hospitalFavourites = view.FindViewById<ToggleButton>(Resource.Id.selectHospital_FavouritesToggle);
hospitalFavourites.Click += (sender, e) => listener(AdapterPosition);
}
}
【问题讨论】:
-
你应该为不同的listView项目有不同的布局
-
@AyushKhare 抱歉,您能详细说明一下吗?
-
你有不同颜色的行,你应该实现getItemViewType(),计数为2。看看这个tutorial
-
@AyushKhare 谢谢!这解决了背景的问题。我仍然有点击方法的问题。
标签: android listview xamarin adapter