android.R.layout.simple_list_item_1和android.R.layout.simple_list_item_2之间有什么区别?

26
有人能解释一下在Android中的`android.R.layout.simple_list_item_1`和`android.R.layout.simple_list_item_2`在ArrayAdapter中的作用吗?
我知道`android.R.layout.simple_list_item_1`和`android.R.layout.simple_list_item_2`是由Android自己定义的布局。
`android.R.layout.simple_list_item_1`只包含一个`TextView`,而`android.R.layout.simple_list_item_2`则包含两个`TextView`。
我想要一个关于`android.R.layout.simple_list_item_2`的示例。如何使用适配器在ListView中显示两个TextView?
我的代码是:
package com.app.listview;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class ExampleListViewActivity extends Activity {

    private String[] nameArr = new String[] {"Arun", "Anil", "Ankit", "Manoj"};
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        ListView listView = (ListView) findViewById(R.id.lv);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                                                                android.R.layout.simple_list_item_1,
                                                                android.R.id.text1,
                                                                nameArr);
        listView.setAdapter(adapter);
    }
}
6个回答

16

我认为这是回答你问题最简单的方式:

ArrayAdapter adapter = new ArrayAdapter(context, android.R.layout.simple_list_item_2, android.R.id.text1, list) {
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View view = super.getView(position, convertView, parent);
    TextView text1 = (TextView) view.findViewById(android.R.id.text1);
    TextView text2 = (TextView) view.findViewById(android.R.id.text2);

    text1.setText(person[position].getName());
    text2.setText(person[position].getAge());
    return view;
  }
};

如果你没有注意到的话:诀窍是向ArrayAdapter提供android.R.id.text1作为(原则上不必要的)参数,否则调用super会引发异常。

此外,这个解决方案不需要一个Inflater或者使用TwoLineListItem,后者在API 17中被弃用了。


我注意到传入android.R.id.text1还是.text2似乎没有关系。但是,如果我输入0,它就会崩溃,而方法名称似乎表明它正在测量某些放置的东西。我猜我可以读源代码,但这应该在文档中澄清。 - Michael Rogers

15
区别如下。 simple_list_item_1 只包含一个 TextView,而 simple_list_item_2 包含两个在 RelativeLayout 的子类中。这两个都来自 Jelly Bean。
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>

简单列表项2
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2006 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="?android:attr/listPreferredItemHeight"
    android:mode="twoLine"
>

    <TextView android:id="@android:id/text1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    android:layout_marginLeft="?android:attr/listPreferredItemPaddingLeft"
    android:layout_marginTop="8dip"
        android:textAppearance="?android:attr/textAppearanceListItem"
    />

    <TextView android:id="@android:id/text2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@android:id/text1"
    android:layout_alignLeft="@android:id/text1"
        android:textAppearance="?android:attr/textAppearanceSmall"
    />

</TwoLineListItem>

根据ArrayAdapter的文档
默认情况下,该类期望提供的资源ID引用单个TextView。
因此,默认情况下,ArrayAdapter不会自动填充多个TextView实例。但是,您可以重写getView()方法并填充出现在R.layout.simple_list_item_2中的两个TextView。

第一次尝试编程时,我感到困扰的正是这个问题。当我发现许多适配器不使用附加视图时,我意识到许多适配器只是用来被子类化的... :) - Shark
当我需要为列表创建特定的外观时,通常会子类化BaseAdapter,并在我的getView()实现中填充自定义布局(或回收传递进来的布局),并根据需要填充内容。 - wsanville
基本上就是我在下面回答中说的那样 ;) 附带示例代码。 - Shark
没错,我想详细阐述一下原帖中询问的这两种布局之间的区别。 - wsanville

4

正如您所注意到的,layout_1只有一个textView,并且它是默认要使用的。 layout_2有两个文本视图-另一个用作子文本。

但这里有个诀窍-并不是所有的适配器都使用子文本;)

我发现编写一个特定目的的自定义适配器对任何事情都更容易(不会说是必须的)...

例如,这是一个自定义适配器,将使用simple_list_item_2显示名称及其状态

不是复制/粘贴代码,但您可以通过进行一些调整来修复它...

 public class BuddyArrayAdapter extends ArrayAdapter<Buddy>
 {

private static final String tag         = "BuddyArrayAdapter";
private Context             context;

private TextView            buddyName;
private TextView            buddyStatus;
private List<Buddy>         buddies     = new ArrayList<Buddy>();

/**
 * The default constructor which is invoked to create the buddy array
 * adapter.
 * <p>
 * The adapter is needed to 'translate' data into a viewable item / widget.
 * 
 * @param context
 *            the application context
 * @param objects
 *            the backing array populated by Buddy objects to be displayed.
 * @see {@link ArrayAdapter}<T>
 */

public BuddyArrayAdapter(Context context, int textViewResourceId, List<Buddy> objects)
{
    super(context, textViewResourceId, objects);
    this.context = context;
    this.buddies = objects;
    Collections.sort(buddies);
}

/**
 * The method used for determining how many views are in this list or in
 * other words, how many views are managed by this adapter.
 * 
 * @return the number of items this adapter controls.
 */
@Override
public int getCount()
{
    return this.buddies.size();
}


/**
 * Get the data item associated with the specified position in the data set.
 * 
 * @param index
 *            Position of the item whose data we want within the adapter's
 *            data set.
 * @return the Buddy object data at the specified position.
 */
@Override
public Buddy getItem(int index)
{
    if (index <= getCount())    //IndexOutOfBoundsException fix
        return this.buddies.get(index);
    return this.buddies.get(getCount() - 1);
}

/**
 * Get a View that displays the data at the specified position in the data
 * set. You can either create a View manually or inflate it from an XML
 * layout file. When the View is inflated, the parent View (GridView,
 * ListView...) will apply default layout parameters unless you use
 * inflate(int, android.view.ViewGroup, boolean) to specify a root view and
 * to prevent attachment to the root.
 * <p>
 * This method is used to generate views to be used in the ListView. This
 * the method that defines how data will look and be represented throughout
 * the UI.
 * 
 * @param position
 *            The position of the item that is being placed / The position
 *            of the item within the adapter's data set of the item whose
 *            view we want.
 *            <p>
 * @param convertView
 *            The old view to reuse, if possible. Note: You should check
 *            that this view is non-null and of an appropriate type before
 *            using. If it is not possible to convert this view to display
 *            the correct data, this method can create a new view.
 *            Heterogeneous lists can specify their number of view types, so
 *            that this View is always of the right type (see
 *            getViewTypeCount() and getItemViewType(int))
 *            <p>
 * @param parent
 *            The parent that this view will eventually be attached to.
 * @return the view that defines how this Buddy object is represented in the
 *         ListView / A View corresponding to the data at the specified
 *         position.
 * 
 * @see {@link BaseAdapter#getView(int, View, ViewGroup)}
 */
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    View row = convertView;

    if (row == null)
    {
        // ROW INFLATION
        LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        row = inflater.inflate(R.layout.simple_list_item_2, parent, false);
    }

    // Get item
    Buddy buddy = getItem(position);
    buddy.refresh();

    buddyName = (TextView) row.findViewById(R.id.buddy_name);   //change this to textField1  from simple_list_item_2
    buddyName.setText(buddy.toString());

    buddyStatus = (TextView) row.findViewById(R.id.buddy_mood); //change this to textField2 from simple_list_item_2
    buddyStatus.setText(buddy.getMood());
    //      Log.d(tag, buddy.getIdentity()+"'s mood is "+buddyStatus.getText());



    return row;
}

我建议您扩展构造函数,添加一个包含子文本的额外ArrayList,然后使用它们来替换buddy.getMood()调用。
最后,实例化此适配器并将其设置为listView的适配器。完成,您会看到两个文本都显示出来了 ;)
为了进一步改进,可以创建一个包含两个textViews的XML文件,如下所示。
 <?xml version="1.0" encoding="utf-8"?>
 <com.skype.widget.CheckableLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<CheckedTextView
    android:id="@+id/buddy_name"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:checkMark="?android:attr/textCheckMark"
    android:gravity="center_vertical"
    android:paddingLeft="6dip"
    android:paddingRight="6dip"
    android:text="@string/buddy_name"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView
    android:id="@+id/buddy_mood"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/empty_string"
    android:layout_marginLeft="-350dp"
    android:layout_marginTop="16dp"
    android:gravity="center_vertical|bottom"
    android:textAppearance="?android:attr/textAppearanceSmall" />

而不是

  row = inflater.inflate(R.layout.simple_list_item_2, parent, false);

做。
 row = inflater.inflate(R.layout.buddy_list_item, parent, false);

现在你知道如何让适配器与自定义XML和列表视图一起使用了。


2

messages - 是一个List<Map<String, String>>, title和data是map的键。

SimpleAdapter adapter = new SimpleAdapter(this, messages,
            android.R.layout.simple_list_item_2,
            new String[] {"title", "data"},
            new int[] {android.R.id.text1,
        android.R.id.text2,
    });
list.setAdapter(adapter);

这就是你所需要的全部。


1

ArrayAdapter 只知道如何处理每行一个 TextView。如果你想让它处理更多的 TextView,你需要通过子类化 ArrayAdapter 并覆盖 getView() 方法来自己处理。

根据你创建数组的方式,可能还有另一个答案。

如果数组是从数据库创建的(你展示了硬编码的字符串数组,但就我所知,那可能只是作为示例),并且你没有被其他因素限制到数组中,那么你可以考虑使用 CursorAdapter。它们已经设置好了处理多个 TextView 而无需子类化适配器,这将节省你将数据库数据转换为数组所需的处理能力。


不,你为什么要为了一个该死的文本字段而改变整个数据组织结构呢? - Shark
我只是说如果可能的话。很多人(出于某种原因)从数据库中获取数据并将其转换为数组,因为他们不理解游标适配器。他们浪费了处理能力在不需要完成的事情上。如果这是情况,我只是提到了它。我认为我的回答没有任何值得被踩的地方,但无论如何。 - Barak
LOL,一直都是这样,我并不是特别脆弱,我的回答可能(显然)被误解。 - Barak
是的,一旦你详细阐述了它(并将其添加到答案中),它就有意义了。 - Shark

0

我也用基本项以编程方式完成了这个:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:layout_marginLeft="3dp"
    android:id="@+id/linearLayoutBasicItem"
     >

    <ImageView
        android:id="@+id/imageViewBasicItem"
        android:layout_marginTop="3dp"
        android:layout_width="80dp"
        android:layout_height="100dp"
        android:src="@drawable/blockbreaker3"
        android:background="#b3b3b3"
         />
    <RelativeLayout 
        android:id="@+id/relativeLayoutInsideBasicItem"
        android:layout_width="fill_parent"
        android:layout_marginTop="3dp"
        android:layout_height="100dp"
        android:background="#b3b3b3"
        >
        <TextView
            android:id="@+id/textViewBasicItem"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="Affronta livelli ancora più complessi che ti porteranno al di là di un semplice schermo pieno di mattoncini."
            android:textSize="10dp"
            android:textColor="#000000"
            android:gravity="top"
            android:ems="10" />

        <TextView
          android:id="@+id/textViewPlatformItem"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@+id/textViewBasicItem"
          android:layout_marginTop="3dp"
          android:text="Platform: "
          android:textSize="8dp"
          android:textColor="#000000"
          android:gravity="top"
          android:ems="10" />
        <TextView
          android:id="@+id/textViewTypeItem"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@+id/textViewPlatformItem"
          android:layout_marginTop="3dp"
          android:text="Genere: "
          android:textSize="8dp"
          android:textColor="#000000"
          android:gravity="top"
          android:ems="10" />
        <TextView
          android:id="@+id/textViewDateItem"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@+id/textViewTypeItem"
          android:layout_marginTop="3dp"
          android:text="Data di lancio: "
          android:textSize="8dp"
          android:textColor="#000000"
          android:gravity="top"
          android:ems="10"
          android:layout_marginBottom="3dp"
           />
        <TextView
          android:id="@+id/textViewPriceItem"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentBottom="true"
          android:layout_alignParentRight="true"
          android:text="Gratis    "
          android:gravity="right"
          android:textSize="15dp"
          android:textColor="#0096ff"
          android:ems="10"
           />

    </RelativeLayout>

</LinearLayout>

通过在我的主活动中的垂直线性布局中添加这个层。
...
<ScrollView 
        android:id="@+id/scrollViewStep1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"        
        android:layout_below="@+id/textViewStep1"
        android:layout_marginTop="35dp"
        android:layout_marginRight="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginBottom="32dp"
        android:background="#e8e8e8"
        android:orientation="vertical" >

        <LinearLayout 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:id="@+id/collector"
            ></LinearLayout>


    </ScrollView>
...

在活动中添加并修改内容的代码如下:

public void listViewTailer(int rootId, int itemId){

        LinearLayout collector = (LinearLayout) findViewById(rootId);    
        LinearLayout inflatedView;


        for(int i = 0; i < listFeeder.size(); i++){


            inflatedView = (LinearLayout) View.inflate(this, itemId, null);
            TextView description = (TextView) inflatedView.findViewById(id.textViewBasicItem);
            description.setText(listFeeder.getGameList().get(i).getPrdDescription());
            TextView platform = (TextView) inflatedView.findViewById(id.textViewPlatformItem);
            platform.setText(platform.getText() + "" + listFeeder.getGameList().get(i).getPrdPlatform());
            TextView type = (TextView) inflatedView.findViewById(id.textViewTypeItem);
            type.setText(type.getText() + "" + listFeeder.getGameList().get(i).getPrdType());
            TextView date = (TextView) inflatedView.findViewById(id.textViewDateItem);
            date.setText(date.getText() + "" + listFeeder.getGameList().get(i).getPrdDateAvailability());
            TextView price = (TextView) inflatedView.findViewById(id.textViewPriceItem);
            price.setText(listFeeder.getGameList().get(i).getPrdPrice() + "    ");

            collector.addView(inflatedView);

          ImageView imageView = (ImageView) inflatedView.findViewById(id.imageViewBasicItem);
          imageView.setImageResource(listFeeder.getGameList().get(i).getPrdImage());

        }

    } 

其中rootId是收集器布局,itemId是添加到垂直线性布局的基本项。

希望这可以帮助到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接