代码之家  ›  专栏  ›  技术社区  ›  Georgy Gobozov

自定义列表视图和上下文菜单。怎么弄?

  •  16
  • Georgy Gobozov  · 技术社区  · 14 年前

    在我的活动中,我试图注册forContextMenu(getListView())并重写两个方法

      @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;
            }
    

    主.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>
    

    项目.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>
    

    这一切都不管用。可能是因为线性布局?我也发现类似的话题 Android: Context menu doesn't show up for ListView with members defined by LinearLayout? 但我有更复杂的列表项。

    在我的活动中,我还有内部类扩展ArrayAdapter。在getView方法中的这个类中,我可以在每个视图上设置OnCreateContextMenuListener,在上下文菜单出现之后,但是我不知道如何处理项单击。如果我在onContextItemSelected方法中尝试执行此操作,item.getMenuInfo()对象始终为空,并且无法从中获取某些信息。

    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);
                        }
                    });
    

    谢谢。希望你能帮忙。

    6 回复  |  直到 8 年前
        1
  •  33
  •   Georgy Gobozov    14 年前

    我找到了解决办法,我的朋友帮了我!希望这些信息对某人有帮助。

       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
            }
    
        }
    }
    

    如果有人能找到更好的方法,请告诉我。谢谢!

        2
  •  7
  •   David Salgado    13 年前

    下面的代码段来自嵌套类ComplexObjectAdapter,列在Georgy Gobozov的答案中,实际上并不需要:

        @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
    }
    

    它之所以工作,是因为在类视图中的函数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;
    }
    

        @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>
    
        3
  •  1
  •   chopper    11 年前

    实际上,您只需要通过调用

    v.setLongClickable(true);
    

    不需要设置dummy setOnCreateContextMenuListener ,因为它就是这样-set是一个可长时间点击的项目。

        4
  •  0
  •   Greg Giacovelli    14 年前

        5
  •  0
  •   Richard Vowles    14 年前

    基本问题是第二个item.xml布局正在绘制项,因此根元素(LinearLayout)是长时间按下的元素,而不是原始ListView提供的元素。因此,在扩展item.xml布局时,需要调用setOnCreateContextMenuListener,正如在第二个示例中所做的那样。问题是item.xml中的布局(这是一个线性布局)无法与所选位置的活动进行通信。这是因为LinearLayout不重写getContextMenuInfo()方法,该方法在ListView中返回AdapterView.AdapterContextMenuInfo(因为每个人似乎都将其ContextMenuInfo强制为)。

    因此,理想情况下,您需要创建自己的LinearLayout子体,使getContextMenuInfopublic公开,如果没有,则创建一个伪子体,并且当在自定义适配器中调用onCreateContextMenu时,它将从自定义LinearLayout中获取该子体,并将位置/id放在其中,活动可以将其拉出。

        6
  •  0
  •   iflorit    11 年前

    我现在不知道为什么,有必要在每个列表行上设置一个空的OnCreateContextMenuListener(除了registerForContextMenu(…),并实现onCreateContextMenu(…)和onContextItemSelected(…)