2012-09-30 118 views
1

我有一个使用操作栏的选项卡功能托管多个片段的Activity。其中一个片段包含一个ListView。在选中此选项卡后,我想选择某个项目。Android:在onResume中选择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); 
    } 
} 
+0

如果你需要使用'PerformItemClick'(单声道),我认为你不能没有延迟的行动。在hack类别中,你还可以在'ListView'上发布一个'postn'发布的'Runnable'(并在那里调用'PerformItemClick')。如果我在您的位置,我只需更改适配器以使其具有扩展项目并直接调用的方法。 – Luksprog

+0

正如你从我不完整的代码清理中猜到的,我正在使用Mono4Android。 – user1537915

+0

我不熟悉Mono for Android(所以可能有一些限制,我不知道),但我会改变适配器,就像我上面说的,而不是使用'performClick'方法。 – Luksprog

回答

2

我的单声道的技能是有限的,所以我不知道如果我完全理解你的适配器,反正我已经适应了一些旧代码,并提出,扩大单个项目时的点击,也将在onResume移动ListView适配器到期望的位置:

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_expandedelement是一个简单的垂直LinearLayoutTextView和初始隐藏(可见性设置为离去)Button。对于此Button我将可见性更改为模拟在ListView中展开/折叠一行。你应该能够理解我的代码,如果你想我可以在github上发布完整的示例。

+0

谢谢 - 我将不得不重写我的片段代码的大部分内容,但我已经成功实现了这种方法的基础知识,并且它的工作就像一个魅力。 – user1537915

1

。虽然我不知道确切的当量为C#/ Mono,Android框架在Activity上提供了一个名为onWindowFocusChanged()的回调函数,表示期间与给定的Activity关联的对用户可见。在此之前,您可能有更好的运气等待您的选择方法,因为ListView应该在那个时间点进行测量和布局。在Java中,这将是这样的:

@Override 
public void onWindowFocusChanged (boolean hasFocus) { 
    if (hasFocus) { 
     selectItem(position); 
    } 
} 

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

+0

哦,这就是所谓的相同,只是使用C#符号。但(我怀疑我应该把它放在原始问题中),活动托管片段标签(使用操作栏)..所以可见性不直接耦合到已经呈现的列表视图。实际上,我在onWindowFocusChanged时触发了一次标签活动加载(它从一个不同的片段开始,而不是具有listview的那个片段),然后如果我用ListView交换到标签,我不会一起开启onWindowFocusChanged 。 – user1537915