Android:在onResume中选择ListView项

时间:2012-09-30 16:52:20

标签: android android-listview

我有一个Activity,它使用操作栏的标签功能托管多个片段。其中一个片段包含ListView。选中此选项卡后,我想选择某个项目。

为了以编程方式执行此操作,我使用以下代码(其中调用是ListView)

private void selectItem(int position)
{
    long itemId = calls.GetItemIdAtPosition(position);
    calls.PerformItemClick(calls, position, itemId);
}

如果已经渲染了这个ListView,我正在调用它,没问题。但是,如果我从onResume调用它,那么代码会执行但最后没有选择任何内容。我想这是因为在我调用selectItem的时候,并没有渲染ListView的所有项目。然而,如果我开始一个后台线程,睡眠几百毫秒,然后运行相同的代码(当然在ui线程中),一切都很好,但这是一个丑陋的黑客。

现在你可能想知道,“他为什么不使用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);
    }
}

2 个答案:

答案 0 :(得分:2)

我的单声道技能有限,所以我不知道我是否完全理解你的适配器,无论如何我已经改编了一些旧代码并制作了一个适配器,可以在单击时扩展单个项目,同时也会移动{{1} } ListView到期望的位置:

onResume

private static class CustomAdapter extends BaseAdapter { // the data private ArrayList<String> mData; // an int pointing to a position that has an expanded layout, // for simplicity I assume that you expand only one item(otherwise use // an array or list) private int mExpandedPosition = -1; // -1 meaning no expanded item private LayoutInflater mInflater; public CustomAdapter(Context context, ArrayList<String> items) { mInflater = LayoutInflater.from(context); mData = items; } public void setExpandedPosition(int position) { // if the position equals mExpandedPosition then we have a click on // the same row so simply toggle the row to be gone again if (position == mExpandedPosition) { mExpandedPosition = -1; } else { // else change position of the row that was expanded mExpandedPosition = position; } // notify the adapter notifyDataSetChanged(); } @Override public int getCount() { return mData.size(); } @Override public String getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = mInflater.inflate(R.layout.ad_expandedelement, parent, false); } ((TextView) convertView.findViewById(R.id.textView1)) .setText(getItem(position)); // see if there is an expanded position and if we are at that // position if (mExpandedPosition != -1 && mExpandedPosition == position) { // if yes simply expand the layout convertView.findViewById(R.id.button1).setVisibility( View.VISIBLE); } else { // this is required, we must revert any possible changes // otherwise the recycling mechanism will hurt us convertView.findViewById(R.id.button1).setVisibility(View.GONE); } return convertView; } } 只会是:

onListItemClick

并且在@Override protected void onListItemClick(ListView l, View v, int position, long id) { // set the expanded(or collapsed if it's a click on the same row that // was previously expanded) row in the adapter ((CustomAdapter) getListView().getAdapter()) .setExpandedPosition(position); } 中会有:

onResume

@Override protected void onResume() { super.onResume(); // set the position to the desired element ((CustomAdapter) getListView().getAdapter()).setExpandedPosition(15); // set the selection to that element so we can actually see it // this isn't required but has the advantage that it will move the // ListView to the desired // position if not visible getListView().setSelection(15); } 是一个简单的垂直R.layout.ad_expandedelementLinearLayout,最初隐藏(知名度设置为已消失)TextView。对于此Button,我更改了可见性,以模拟在Button中展开/折叠行。您应该能够理解我的代码,如果您愿意,我可以在github上发布完整的样本。

答案 1 :(得分:1)

虽然我不确定C#/ Mono中的确切等效内容,但Android框架会在名为Activity的{​​{1}}上提供一个回调,指示与onWindowFocusChanged()关联的时间段给定Window对用户可见。你可能有更好的运气等到你的选择方法,直到那个时候,因为Activity应该被测量和布置。在Java中,它将是这样的:

ListView

你可能需要更多逻辑,这个回调与窗口焦点直接相关,并不是真正的生命周期方法。如果您正在显示对话框或执行其他类似操作,我可以多次调用。