1

アクションバーのタブ機能を使用して複数のフラグメントをホストするアクティビティがあります。それらのフラグメントの1つに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);
    }
}
4

2 に答える 2

2

私の Mono スキルは限られているため、アダプターを完全に理解したかどうかはわかりませんが、古いコードをいくつか適応させ、クリックすると単一のアイテムを展開するアダプターを作成しました。また、目的の位置に移動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_expandedelement単純な縦型LinearLayoutTextView、最初は hidden(visibility set to gone)Buttonです。このためButtonに、可視性を変更して、行の展開/折りたたみをシミュレートしListViewます。必要に応じて、完全なサンプルを github に投稿できます。

于 2012-10-02T19:46:34.047 に答える
1

C#/Mono で正確に同等かどうかはわかりませんが、Android フレームワークは、特定の に関連付けられた がユーザーに表示される期間を示すActivityコールバックを提供します。その時点までに を測定して配置する必要があるため、その時点まで選択メソッドを呼び出すのを待つ方がよいかもしれません。Java では、次のようになります。onWindowFocusChanged()WindowActivityListView

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

もう少しロジックが必要な場合があります。このコールバックはウィンドウ フォーカスに直接関連付けられており、真のライフサイクル メソッドではありません。ダイアログを表示している場合や、他の同様の操作を行っている場合は、複数回呼び出される可能性があります。

于 2012-10-02T18:04:20.390 に答える