web-dev-qa-db-ja.com

カスタムリストビューとコンテキストメニュー。入手方法は?

アプリに2つのレイアウトファイルがあります。また、ActivityはListActivityを拡張しています。このアクティビティのすべてのアイテムは、item.xmlレイアウトファイルを考慮しているように見えます。アイテムを長押しするとコンテキストメニューを取得しようとしていますが、表示されません。

私のアクティビティでは、registerForContextMenu(getListView())を実行し、2つのメソッドをオーバーライドしようとしています

  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = this.getIntent().getExtras();
        registerForContextMenu(getListView());
        new PopulateAdapterTask().execute(ACTION_SELECT);   
     }

    @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
        }


        @Override
        public boolean onContextItemSelected(MenuItem item) {
            AdapterView.AdapterContextMenuInfo info;
            try {
                info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
            } catch (ClassCastException e) {
                return false;
            }
            long id = getListAdapter().getItemId(info.position);
            Log.d(TAG, "id = " + id);
            return true;
        }

Main.xml

    <?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:Android="http://schemas.Android.com/apk/res/Android"
         Android:id="@Android:id/tabhost"
         Android:layout_width="fill_parent"
         Android:layout_height="fill_parent">
    <LinearLayout
            Android:orientation="vertical"
            Android:layout_width="fill_parent"
            Android:layout_height="fill_parent"
            Android:padding="5dp">
        <TabWidget
                Android:id="@Android:id/tabs"
                Android:layout_width="fill_parent"
                Android:layout_height="wrap_content"/>
        <FrameLayout
                Android:id="@Android:id/tabcontent"
                Android:layout_width="fill_parent"
                Android:layout_height="fill_parent"
                Android:padding="5dp">
            <ListView
                    Android:id="@+id/list"
                    Android:layout_width="fill_parent"
                    Android:layout_height="fill_parent"
                    />

        </FrameLayout>

    </LinearLayout>

</TabHost>

Item.xml

<?xml version="1.0" encoding="utf-8"?>
     <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
              Android:layout_width="fill_parent"
              Android:layout_height="wrap_content"
        >
    <ImageView
            Android:id="@+id/icon"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            />
    <TextView
            Android:id="@+id/info"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:padding="10dp"
            Android:textSize="15sp"
            Android:singleLine="true"
            Android:ellipsize="Marquee"
            Android:scrollHorizontally = "true"
            Android:maxWidth="200dp"
            />


    <LinearLayout
             Android:layout_width="fill_parent"
             Android:layout_height="fill_parent"
             Android:gravity="right"
            >
        <ImageButton
                Android:id="@+id/button"
                Android:layout_width="wrap_content"
                Android:layout_height="fill_parent"
                Android:background="@null"
                Android:paddingRight="10dp"                
                Android:paddingLeft="10dp"


                />
    </LinearLayout>

</LinearLayout>

これはすべて機能しません。たぶん理由はLinearLayoutにありますか?同様のトピックもあります Android:LinearLayoutで定義されたメンバーを持つListViewのコンテキストメニューは表示されませんか? しかし、より複雑なリストアイテムがあります。

私の場合、コンテキストメニューを取得するにはどうすればよいですか?

また、私のアクティビティでは、内部クラスがArrayAdapterを拡張しています。 getViewメソッドのこのクラスでは、コンテキストメニューが表示された後、すべてのビューにOnCreateContextMenuListenerを設定できますが、アイテムのクリックを処理する方法がわかりません。メソッドonContextItemSelectedでこれを実行しようとすると、item.getMenuInfo()オブジェクトは常にnullになり、そこから情報を取得できません。

private class ChannelAdapter extends ArrayAdapter<Channel> {

        private List<Channel> channels;

        public ChannelAdapter(Context context, int textViewResourceId, List<Channel> objects) {
            super(context, textViewResourceId, objects);
            this.channels = objects;
        }


        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.station_item, null);
            }


                v.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
                    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                        MenuInflater inflater = getMenuInflater();
                        inflater.inflate(R.menu.context_menu, menu);
                    }
                });

ありがとう。あなたの助けを願っています。

16
Georgy Gobozov

私は解決策を得ました、私の友人は私を助けました!この情報が誰かに役立つことを願っています。これは、ArrayAdapterと複雑なリストレイアウトおよびコンテキストメニューを備えた完全なクラスコードです。

   public class ComplexListActivity extends ListActivity {
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setListAdapter(new ComplexObjectAdapter(this, R.layout.item, getComplexObjects()));
        registerForContextMenu(getListView());
    }

    private List getComplexObjects() {
        List<ComplexObject> list = new ArrayList<ComplexObject>();
        list.add(new ComplexObject("1", "1", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("2", "2", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("3", "3", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("4", "4", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("5", "5", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("6", "6", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("7", "7", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("8", "8", getResources().getDrawable(R.drawable.icon)));
        list.add(new ComplexObject("9", "9", getResources().getDrawable(R.drawable.icon)));
        return list;
    }


    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.context_menu, menu);
    }


    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo info;
        try {
            info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        } catch (ClassCastException e) {
            Log.e("", "bad menuInfo", e);
            return false;
        }
        long id = getListAdapter().getItemId(info.position);
        Log.d("", "id = " + id);
        Toast.makeText(this, "id = " + id, Toast.LENGTH_SHORT).show();
        return true;
    }

    private class ComplexObjectAdapter extends ArrayAdapter<ComplexObject> implements View.OnCreateContextMenuListener {

        private List<ComplexObject> objects;

        public ComplexObjectAdapter(Context context, int textViewResourceId, List<ComplexObject> objects) {
            super(context, textViewResourceId, objects);
            this.objects = objects;
        }


        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = convertView;
            if (v == null) {
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = vi.inflate(R.layout.item, null);
            }
            final ComplexObject o = objects.get(position);
            if (o != null) {

                TextView textlInfo = (TextView) v.findViewById(R.id.info);
                textlInfo.setText(o.getName());

                ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
                channelIcon.setAdjustViewBounds(true);
                channelIcon.setMaxHeight(30);
                channelIcon.setMaxWidth(30);
                channelIcon.setImageDrawable(o.getLogo());


                ImageButton button = (ImageButton) v.findViewById(R.id.button);
                button.setImageResource(R.drawable.icon);
                v.setOnCreateContextMenuListener(this);

            }
            return v;
        }

         public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
          // empty implementation
        }

    }
}

誰かがより良いアプローチを見つけるかどうか私に知らせてください。ありがとう!

33
Georgy Gobozov

Georgy Gobozovの回答にリストされている、ネストされたクラスComplexObjectAdapterの次のコードセグメントは、実際には必要ありません。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.item, null);
        }
        final ComplexObject o = objects.get(position);
        if (o != null) {

            TextView textlInfo = (TextView) v.findViewById(R.id.info);
            textlInfo.setText(o.getName());

            ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
            channelIcon.setAdjustViewBounds(true);
            channelIcon.setMaxHeight(30);
            channelIcon.setMaxWidth(30);
            channelIcon.setImageDrawable(o.getLogo());


            ImageButton button = (ImageButton) v.findViewById(R.id.button);
            button.setImageResource(R.drawable.icon);
            // NOT NEEDED
            v.setOnCreateContextMenuListener(this);

        }
        return v;
    }

// NOT NEEDED
public void onCreateContextMenu(ContextMenu contextMenu, View view,  ContextMenu.ContextMenuInfo contextMenuInfo) {
            // empty implementation
}

クラスViewの関数setOnCreateContextMenuListener()内で、関数setLongClickable(true)を呼び出すため、これは機能します。

/**
 * Register a callback to be invoked when the context menu for this view is
 * being built. If this view is not long clickable, it becomes long clickable.
 *
 * @param l The callback that will run
 *
 */
public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) {
    if (!isLongClickable()) {
        setLongClickable(true);
    }
    mOnCreateContextMenuListener = l;
}

これは、作成後に各子アイテムのLongClickableプロパティを設定することで問題を解決できることを意味します。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.item, null);
            // SET LONG CLICKABLE PROPERTY
            v.setLongClickable(true);
        }
        final ComplexObject o = objects.get(position);
        if (o != null) {

            TextView textlInfo = (TextView) v.findViewById(R.id.info);
            textlInfo.setText(o.getName());

            ImageView channelIcon = (ImageView) v.findViewById(R.id.icon);
            channelIcon.setAdjustViewBounds(true);
            channelIcon.setMaxHeight(30);
            channelIcon.setMaxWidth(30);
            channelIcon.setImageDrawable(o.getLogo());


            ImageButton button = (ImageButton) v.findViewById(R.id.button);
            button.setImageResource(R.drawable.icon);
            // NOT NEEDED
            // v.setOnCreateContextMenuListener(this);

        }
        return v;
    }

または、リストビューの子要素のXMLレイアウトファイルでこのプロパティを設定することで解決することもできます。次に例を示します。

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
 Android:longClickable="true">

    <!-- Child elements -->

</LinearLayout>
7
David Salgado

実際には、電話をかけてビューを長くクリック可能にする必要があります

v.setLongClickable(true);

ダミーのsetOnCreateContextMenuListenerを設定する必要はありません。それはまさにそれを行うからです-setはアイテムを長くクリック可能です。

1
user2663241

理由はわかりませんが、すべてのリスト行にnullのOnCreateContextMenuListenerを設定する必要があります(registerForContextMenu(...)に加えて、onCreateContextMenu(...)とonContextItemSelected(...)を実装します)

0
iflorit

基本的な問題は、アイテムが2番目のitem.xmlレイアウトによって描画されていることです。したがって、ルート要素(LinearLayout)は、元のListViewが提供したものではなく、長押しされているものです。そのため、item.xmlレイアウトを拡張するときは、2番目の例で実際に行ったように、setOnCreateContextMenuListenerを呼び出す必要があります。これに伴う問題は、item.xml(LinearLayout)からのレイアウトが、選択された位置をアクティビティに戻す方法がないことです。これは、LinearLayoutがgetContextMenuInfo()メソッドをオーバーライドしないためです。このメソッドはListViewでAdapterView.AdapterContextMenuInfoを返します(誰もがContextMenuInfoを強制しているようです)。

したがって、理想的には、getContextMenuInfoを公開し、偽の子孫がない場合は偽の子孫を作成し、カスタムアダプターでonCreateContextMenuが呼び出されると、カスタムのLinearLayoutからそれを取得して、位置を配置する独自のLinearLayout子孫を作成する必要があります。/idがそこにあり、アクティビティから引き出すことができます。

これは私が自分のアプリケーションで行ったことであり、非常にうまく機能し、一般的なソリューションです。実際、ContextMenuInfoインターフェイス(単なるマーカーインターフェイス)を実装している限り、好きなものをそこに入れることができます。

0
Richard Vowles

特定のlistViewアイテムにコンテキストメニューを添付したくないと思います。 registerForContextMenu(getListView())を呼び出すことにより、その機能を無料で入手できます。アダプターコードからcontextMenuフックを削除し、onCreateContextMenu()内にブレークポイントを設定した後、アプリケーションをデバッガーにフックします。私の疑惑はそれが呼ばれているということですが、膨らんでいるレイアウトはあなたが期待するものではありません。

0
Greg Giacovelli