我有一个使用操作栏的选项卡功能托管多个片段的活动。其中一个片段包含一个 ListView。选择此选项卡后,我想选择某个项目。
要以编程方式执行此操作,我使用以下代码(其中调用是 ListView)
private void selectItem(int position)
{
long itemId = calls.GetItemIdAtPosition(position);
calls.PerformItemClick(calls, position, itemId);
}
如果这个 ListView 已经被渲染,并且我正在调用它,那么没问题。但是,如果我从 onResume 调用它,则代码会执行,但最后没有选择任何内容。我认为这是因为在我调用 selectItem 时,尚未呈现 ListView 的所有项目。但是,如果我启动一个后台线程,休眠几百毫秒,然后运行相同的代码(当然是在 ui 线程中),一切都很好,但这是一个丑陋的 hack。
现在您可能想知道,“他为什么不使用calls.setSelection”?问题是,我正在使用执行扩展的自定义布局 - 所以我需要实际单击我想要选择的项目(这反过来会触发所选项目的布局扩展)。但是,我可以直接调用在 PerformItemClick 上执行的代码,结果是一样的(不执行布局扩展)。
有没有什么办法让我及时捕捉到“Listview 已完成渲染所有可查看项目”的时间点,然后在那时执行我的 selectItem 调用?在 ASP.NET 中,我在每个 UI 项目上都有一个事件,告诉我它何时完成渲染,所以我在那时进行项目选择,但我没有找到任何东西。
问候斯蒂芬
这是我正在使用的适配器
public class ActiveCallsAdapter: ObservableAdapter<Call>
{
public ActiveCallsAdapter(Activity activity, ObservableCollection<Call> calls)
: base(activity, calls)
{
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
var view = (convertView ?? context.LayoutInflater.Inflate(Resource.Layout.Call, parent, false)) as LinearLayout;
//View view = convertView;
//if (view == null) // no view to re-use, create new
// view = context.LayoutInflater.Inflate(Resource.Layout.Call, null);
SetTextView(view, Resource.Id.CallerName, item.CallerName);
SetTextView(view, Resource.Id.CallerNumber, item.CallerNumber);
SetTextView(view, Resource.Id.CallStatus, item.State.ToString());
SetTextView(view, Resource.Id.CallDuration, item.Duration);
return view;
}
public void Update(LinearLayout view, Call item)
{
SetTextView(view, Resource.Id.CallerName, item.CallerName);
SetTextView(view, Resource.Id.CallerNumber, item.CallerNumber);
string identifier = "callState_" + item.State.ToString();
int resourceId = Application.Context.Resources.GetIdentifier(identifier, "string", Application.Context.PackageName);
string callStateString = item.State.ToString();
if (resourceId != 0)
{
try
{
callStateString = Application.Context.Resources.GetString(resourceId);
}
catch (Exception e)
{
AndroidLogModel.Model.AddLogMessage("ActiveCallsAdapter", "Unable to find call state string with resource id " + resourceId + " state string: " + identifier, 3);
}
}
SetTextView(view, Resource.Id.CallStatus, callStateString);
//SetTextView(view, Resource.Id.CallDuration, item.Duration);
}
public void UpdateDuration(LinearLayout view, Call item)
{
SetTextView(view, Resource.Id.CallDuration, item.Duration);
}
}
以及那个适配器的基类
public class ObservableAdapter<T>: BaseAdapter<T>
{
protected readonly Activity context;
protected readonly ObservableCollection<T> items;
public ObservableAdapter(Activity context, ObservableCollection<T> collection)
{
this.context = context;
this.items = collection;
//this.collection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collection_CollectionChanged);
this.items.CollectionChanged += (sender, e) => NotifyDataSetChanged();
}
void collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
NotifyDataSetChanged();
}
public override T this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
var view = (convertView ?? context.LayoutInflater.Inflate(Resource.Layout.Call, parent, false)) as LinearLayout;
// configure view here
return view;
}
protected void SetTextView(LinearLayout view, int id, string text)
{
var textView = view.FindViewById<TextView>(id);
if (textView != null)
textView.SetText(text, TextView.BufferType.Normal);
}
}