我正在开发一个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>
初始屏幕:
滚动后:
注意:单击任何行项都会显示单击行的位置,滚动后会返回错误的值。
不按预期工作的元素是交替背景以及click事件。我尝试在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);
}
}
答案 0 :(得分:1)
hospitalFavourites ToggleButton未在GetView方法中分配
view.Click委托应该从视图中检索标记,而不是访问nameTexts [position]。您可以在ViewHolder中添加位置作为属性,以便在单击列表项时可以访问它。
== EDITED ==
使用以下代码修改您要执行的操作。
using System;
using Android.App;
using Android.Views;
using Android.Widget;
namespace ListAdapterSample.Droid
{
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);
System.Diagnostics.Debug.WriteLine(holder.position);
view.Click += delegate(object sender, EventArgs e)
{
var senderView = sender as View;
if (senderView != null)
{
var senderHolder = senderView.Tag as ViewHolder;
if (senderHolder != null)
{
Toast.MakeText(activity, senderHolder.position.ToString(), ToastLength.Short).Show();
}
}
};
holder.hospitalFavourites.Click += delegate (object sender, EventArgs e)
{
var senderView = sender as View;
if (senderView != null)
{
var rowHolder = ((View)senderView.Parent).Tag as ViewHolder;
rowHolder.hospitalFavourites.Text = rowHolder.position.ToString();
};
};
view.Tag = holder;
}
else
{
holder = view.Tag as ViewHolder;
}
// Set height of row
view.LayoutParameters.Height = 200;
// Set alternating background of row
type = GetItemViewType(position);
if (type == 0)
{
//view.SetBackgroundResource(Resource.Color._8_white);
view.SetBackgroundColor(Android.Graphics.Color.AliceBlue);
}
// Row contents
holder.position = position;
holder.hospitalName.Text = nameTexts[position];
holder.hospitalFavourites.Text = position.ToString();
holder.hospitalFavourites.SetOnCheckedChangeListener(null);
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; }
}
}
答案 1 :(得分:1)
不应该是你的getItem()
:
public override Java.Lang.Object GetItem(int position){
return nameTexts[position];
}
答案 2 :(得分:1)
它可以是适配器中的Delegate,有时可能是许多问题的来源。使用方法委托而不是匿名委托。并在正确设置之前将onclick事件设置为null。
这是因为对象被回收并且click方法可以被调用两次,所以你不需要if(view == null)。
我希望你了解我,我无法提供经过验证的示例代码,但它应该如下:
.
.
.
view.Click -= customOnClickMethod;
view.Click += customOnClickMethod;
.
.
.
void customOnClickMethod(object sender, EventArgs e){
//implement onclick function
}
希望这有帮助。
答案 3 :(得分:0)
使用以下代码管理解决它:
class RecyclerViewAdapter_SelectHospital : RecyclerView.Adapter
{
private readonly Context context;
private List<Hospital> list;
public event EventHandler<int> ItemClick;
public RecyclerViewAdapter_SelectHospital(Context c, List<Hospital> l)
{
context = c;
list = l;
}
public override int ItemCount
{
get
{
return list.Count;
}
}
private void OnClick(int position)
{
ItemClick?.Invoke(this, position);
}
private void OnItemClick(object sender, int position)
{
if (list[position].favourited == false)
{
list[position].favourited = true;
}
else
{
list[position].favourited = false;
}
}
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)
{
SelectHospital_ViewHolder vh = holder as SelectHospital_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 = list[position].name;
vh.hospitalFavourites.Checked = list[position].favourited;
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.sublayout_Hospital_List_Item, parent, false);
SelectHospital_ViewHolder holder = new SelectHospital_ViewHolder(view, OnClick);
holder.ItemView.Click += delegate
{
Intent intent = new Intent(context, typeof(Request_Appointment));
intent.PutExtra("hospitalName", holder.hospitalName.Text);
context.StartActivity(intent);
};
ItemClick -= OnItemClick;
ItemClick += OnItemClick;
return holder;
}
}
class SelectHospital_ViewHolder : RecyclerView.ViewHolder
{
public TextView hospitalName { get; set; }
public ToggleButton hospitalFavourites { get; set; }
public SelectHospital_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);
}
}