有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Android ListView头文件

我有一个ListView,上面有一些事件。事件是按天排序的,我希望每天都有一个带有日期的标题,然后听下面的事件

下面是我如何填充该列表的:

ArrayList<TwoText> crs = new ArrayList<TwoText>();

crs.add(new TwoText("This will be header", event.getDate()));

for (Event event : events) {
    crs.add(new TwoText(event.getStartString() + "-" + event.getEndString(), event.getSubject()));
}

arrayAdapter = new TwoTextArrayAdapter(this, R.layout.my_list_item, crs);
lv1.setAdapter(arrayAdapter);

这就是我的课文的样子:

public class TwoText {
    public String classID;
    public String state;

    public TwoText(String classID, String state) {
        this.classID = classID;
        this.state = state;
    }
}

这就是我的TwoTextArrayAdapter类的外观:

import java.util.ArrayList;
import 安卓.app.Activity;
import 安卓.content.Context;
import 安卓.view.LayoutInflater;
import 安卓.view.View;
import 安卓.view.ViewGroup;
import 安卓.widget.ArrayAdapter;
import 安卓.widget.TextView;

public class TwoTextArrayAdapter extends ArrayAdapter<TwoText> {

    private ArrayList<TwoText> classes;
    private Activity con;
    TextView seperator;

    public TwoTextArrayAdapter(Activity context, int textViewResourceId, ArrayList<TwoText> classes) {
        super(context, textViewResourceId, classes);
        this.con = context;
        this.classes = classes;

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {

            LayoutInflater vi = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            v = vi.inflate(R.layout.my_list_item, null);

        }

        TwoText user = classes.get(position);

        if (user != null) {

            TextView content1 = (TextView) v.findViewById(R.id.list_content1);

            TextView content2 = (TextView) v.findViewById(R.id.list_content2);

            if (content1 != null) {

                content1.setText(user.classID);
            }   
            if(content2 != null) {

                content2.setText(user.state);
            }
        }
        return v;
    }
}

这是我的清单。xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    安卓:layout_width="match_parent"
    安卓:layout_height="match_parent"
    安卓:orientation="vertical" >

    <TextView
        style="?安卓:attr/listSeparatorTextViewStyle"
        安卓:id="@+id/separator"
        安卓:text="Header"
        安卓:layout_width="fill_parent"
        安卓:layout_height="wrap_content"
        安卓:background="#757678"
        安卓:textColor="#f5c227" />

    <LinearLayout
        xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
        安卓:layout_width="match_parent"
        安卓:layout_height="match_parent"
        安卓:orientation="horizontal" >

        <TextView
            安卓:id="@+id/list_content1"
            安卓:layout_width="wrap_content"
            安卓:layout_height="match_parent"
            安卓:layout_margin="5dip"
            安卓:clickable="false"
            安卓:gravity="center"
            安卓:longClickable="false"
            安卓:paddingBottom="1dip"
            安卓:paddingTop="1dip"
            安卓:text="sample"
            安卓:textColor="#ff7f1d"
            安卓:textSize="17dip"
            安卓:textStyle="bold" />

        <TextView
            安卓:id="@+id/list_content2"
            安卓:layout_width="wrap_content"
            安卓:layout_height="match_parent"
            安卓:layout_margin="5dip"
            安卓:clickable="false"
            安卓:gravity="center"
            安卓:linksClickable="false"
            安卓:longClickable="false"
            安卓:paddingBottom="1dip"
            安卓:paddingTop="1dip"
            安卓:text="sample"
            安卓:textColor="#6d6d6d"
            安卓:textSize="17dip" />
    </LinearLayout>

</LinearLayout>

我现在所做的是,我添加的标题只是作为常规列表对象,但我希望它作为标题,在我的情况下,它有一个日期

我的xml文件头中有以下代码:

<TextView
        style="?安卓:attr/listSeparatorTextViewStyle"
        安卓:id="@+id/separator"
        安卓:text="Header"
        安卓:layout_width="fill_parent"
        安卓:layout_height="wrap_content"
        安卓:background="#757678"
        安卓:textColor="#f5c227" />

我试着在不必要的时候隐藏它,在必要的时候显示它,但是我把剩下的代码搞乱了。我尝试了更多的教程,但它们也有同样的效果

有谁能指导我如何用这种简单的方法吗


共 (5) 个答案

  1. # 1 楼答案

    Here is a sample project,基于antew详细而有用的回答,它实现了一个带有多个标题的ListView,其中包含视图持有者,以提高滚动性能

    在这个项目中,ListView中表示的对象是类HeaderItem或类RowItem的实例,两者都是抽象类Item的子类。Item的每个子类对应于自定义适配器ItemAdapter中的不同视图类型。ItemAdapter上的方法getView()将每个列表项的视图的创建委托给HeaderItemRowItem上的个体化getView()方法,具体取决于在传递给适配器上getView()方法的位置使用的Item子类。每个Item子类都提供自己的视图持有者

    视图持有者的实现如下所示。Item子类上的getView()方法检查传递给ItemAdapter上的getView()方法的View对象是否为空。如果是这样的话,适当的布局会膨胀,视图持有者对象会被实例化,并通过View.setTag()与膨胀的视图关联。如果View对象不为空,则视图持有者对象已经与视图关联,并且通过View.getTag()检索视图持有者。视图持有者的使用方式可以在HeaderItem的以下代码片段中看到:

    @Override
    View getView(LayoutInflater i, View v) {
        ViewHolder h;
        if (v == null) {
            v = i.inflate(R.layout.header, null);
            h = new ViewHolder(v);
            v.setTag(h);
        } else {
            h = (ViewHolder) v.getTag();
        }
        h.category.setText(text());
        return v;
    }
    
    private class ViewHolder {
        final TextView category;
    
        ViewHolder(View v) {
            category = v.findViewById(R.id.category);
        }
    }
    

    下面是ListView的完整实现。以下是Java代码:

    import android.app.ListActivity;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class MainActivity extends ListActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setListAdapter(new ItemAdapter(getItems()));
        }
    
        class ItemAdapter extends ArrayAdapter<Item> {
            final private List<Class<?>> viewTypes;
    
            ItemAdapter(List<Item> items) {
                super(MainActivity.this, 0, items);
                if (items.contains(null))
                    throw new IllegalArgumentException("null item");
                viewTypes = getViewTypes(items);
            }
    
            private List<Class<?>> getViewTypes(List<Item> items) {
                Set<Class<?>> set = new HashSet<>();
                for (Item i : items) 
                    set.add(i.getClass());
                List<Class<?>> list = new ArrayList<>(set);
                return Collections.unmodifiableList(list);
            }
    
            @Override
            public int getViewTypeCount() {
                return viewTypes.size();
            }
    
            @Override
            public int getItemViewType(int position) {
                Item t = getItem(position);
                return viewTypes.indexOf(t.getClass());
            }
    
            @Override
            public View getView(int position, View v, ViewGroup unused) {
                return getItem(position).getView(getLayoutInflater(), v);
            }
        }
    
        abstract private class Item {
            final private String text;
    
            Item(String text) {
                this.text = text;
            }
    
            String text() { return text; }
    
            abstract View getView(LayoutInflater i, View v);
        }
    
        private class HeaderItem extends Item {
            HeaderItem(String text) {
                super(text);
            }
    
            @Override
            View getView(LayoutInflater i, View v) {
                ViewHolder h;
                if (v == null) {
                    v = i.inflate(R.layout.header, null);
                    h = new ViewHolder(v);
                    v.setTag(h);
                } else {
                    h = (ViewHolder) v.getTag();
                }
                h.category.setText(text());
                return v;
            }
    
            private class ViewHolder {
                final TextView category;
    
                ViewHolder(View v) {
                    category = v.findViewById(R.id.category);
                }
            }
        }
    
        private class RowItem extends Item {
            RowItem(String text) {
                super(text);
            }
    
            @Override
            View getView(LayoutInflater i, View v) {
                ViewHolder h;
                if (v == null) {
                    v = i.inflate(R.layout.row, null);
                    h = new ViewHolder(v);
                    v.setTag(h);
                } else {
                    h = (ViewHolder) v.getTag();
                }
                h.option.setText(text());
                return v;
            }
    
            private class ViewHolder {
                final TextView option;
    
                ViewHolder(View v) {
                    option = v.findViewById(R.id.option);
                }
            }
        }
    
        private List<Item> getItems() {
            List<Item> t = new ArrayList<>();
            t.add(new HeaderItem("Header 1"));
            t.add(new RowItem("Row 2"));
            t.add(new HeaderItem("Header 3"));
            t.add(new RowItem("Row 4"));
    
            t.add(new HeaderItem("Header 5"));
            t.add(new RowItem("Row 6"));
            t.add(new HeaderItem("Header 7"));
            t.add(new RowItem("Row 8"));
    
            t.add(new HeaderItem("Header 9"));
            t.add(new RowItem("Row 10"));
            t.add(new HeaderItem("Header 11"));
            t.add(new RowItem("Row 12"));
    
            t.add(new HeaderItem("Header 13"));
            t.add(new RowItem("Row 14"));
            t.add(new HeaderItem("Header 15"));
            t.add(new RowItem("Row 16"));
    
            t.add(new HeaderItem("Header 17"));
            t.add(new RowItem("Row 18"));
            t.add(new HeaderItem("Header 19"));
            t.add(new RowItem("Row 20"));
    
            t.add(new HeaderItem("Header 21"));
            t.add(new RowItem("Row 22"));
            t.add(new HeaderItem("Header 23"));
            t.add(new RowItem("Row 24"));
    
            t.add(new HeaderItem("Header 25"));
            t.add(new RowItem("Row 26"));
            t.add(new HeaderItem("Header 27"));
            t.add(new RowItem("Row 28"));
            t.add(new RowItem("Row 29"));
            t.add(new RowItem("Row 30"));
    
            t.add(new HeaderItem("Header 31"));
            t.add(new RowItem("Row 32"));
            t.add(new HeaderItem("Header 33"));
            t.add(new RowItem("Row 34"));
            t.add(new RowItem("Row 35"));
            t.add(new RowItem("Row 36"));
    
            return t;
        }
    
    }
    

    还有两个列表项布局,每个项子类一个。以下是HeaderItem使用的布局header

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFAAAAAA"
        >
        <TextView
            android:id="@+id/category"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="4dp"
            android:textColor="#FF000000"
            android:textSize="20sp"
            android:textStyle="bold"
            />
     </LinearLayout>
    

    下面是RowItem使用的布局row

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?android:attr/listPreferredItemHeight"
        >
        <TextView
            android:id="@+id/option"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="15sp"
            />
    </LinearLayout>
    

    下面是生成的ListView的一部分的图像:

    ListView with multiple headers

  2. # 2 楼答案

    您可能正在寻找一个ExpandableListView,它有头(组)来分隔项目(child)

    关于这个主题的不错的教程:here

  3. # 3 楼答案

    我是如何将日期(如2016年12月1日)作为标题的。 我使用了StickyHeaderListView库

    https://github.com/emilsjolander/StickyListHeaders

    将日期转换为长毫秒[不包括时间],并将其作为标题Id

    @Override
    public long getHeaderId(int position) {
        return <date in millis>;
    }
    
  4. # 4 楼答案

    我是这样做的,键是Adapter类中的getItemViewTypegetViewTypeCountgetViewTypeCount返回列表中有多少类型的项,在本例中,我们有一个标题项和一个事件项,所以有两个getItemViewType应该返回我们在输入position中的View类型

    然后,Android会自动在convertView中向您传递正确类型的View

    下面是下面代码的结果:

    首先,我们有一个接口,我们的两个列表项类型将实现该接口

    public interface Item {
        public int getViewType();
        public View getView(LayoutInflater inflater, View convertView);
    }
    

    然后我们有一个适配器,它接受Item

    public class TwoTextArrayAdapter extends ArrayAdapter<Item> {
        private LayoutInflater mInflater;
    
        public enum RowType {
            LIST_ITEM, HEADER_ITEM
        }
    
        public TwoTextArrayAdapter(Context context, List<Item> items) {
            super(context, 0, items);
            mInflater = LayoutInflater.from(context);
        }
    
        @Override
        public int getViewTypeCount() {
            return RowType.values().length;
    
        }
    
        @Override
        public int getItemViewType(int position) {
            return getItem(position).getViewType();
        }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
       return getItem(position).getView(mInflater, convertView);
    }
    

    编辑 性能更好。。滚动时可以注意到

    private static final int TYPE_ITEM = 0; 
    private static final int TYPE_SEPARATOR = 1; 
    
    public View getView(int position, View convertView, ViewGroup parent)  {
        ViewHolder holder = null;
        int rowType = getItemViewType(position);
        View View;
        if (convertView == null) {
            holder = new ViewHolder();
            switch (rowType) {
                case TYPE_ITEM:
                    convertView = mInflater.inflate(R.layout.task_details_row, null);
                    holder.View=getItem(position).getView(mInflater, convertView);
                    break;
                case TYPE_SEPARATOR:
                    convertView = mInflater.inflate(R.layout.task_detail_header, null);
                    holder.View=getItem(position).getView(mInflater, convertView);
                    break;
            }
            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }
        return convertView; 
    } 
    
    public static class ViewHolder {
        public  View View; } 
    }
    

    然后我们让类实现Item并膨胀正确的布局。在你的例子中,你会有Header类和ListItem

       public class Header implements Item {
        private final String         name;
    
        public Header(String name) {
            this.name = name;
        }
    
        @Override
        public int getViewType() {
            return RowType.HEADER_ITEM.ordinal();
        }
    
        @Override
        public View getView(LayoutInflater inflater, View convertView) {
            View view;
            if (convertView == null) {
                view = (View) inflater.inflate(R.layout.header, null);
                // Do some initialization
            } else {
                view = convertView;
            }
    
            TextView text = (TextView) view.findViewById(R.id.separator);
            text.setText(name);
    
            return view;
        }
    
    }
    

    然后是ListItem

        public class ListItem implements Item {
        private final String         str1;
        private final String         str2;
    
        public ListItem(String text1, String text2) {
            this.str1 = text1;
            this.str2 = text2;
        }
    
        @Override
        public int getViewType() {
            return RowType.LIST_ITEM.ordinal();
        }
    
        @Override
        public View getView(LayoutInflater inflater, View convertView) {
            View view;
            if (convertView == null) {
                view = (View) inflater.inflate(R.layout.my_list_item, null);
                // Do some initialization
            } else {
                view = convertView;
            }
    
            TextView text1 = (TextView) view.findViewById(R.id.list_content1);
            TextView text2 = (TextView) view.findViewById(R.id.list_content2);
            text1.setText(str1);
            text2.setText(str2);
    
            return view;
        }
    
    }
    

    和一个简单的Activity来显示它

    public class MainActivity extends ListActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<Item> items = new ArrayList<Item>();
            items.add(new Header("Header 1"));
            items.add(new ListItem("Text 1", "Rabble rabble"));
            items.add(new ListItem("Text 2", "Rabble rabble"));
            items.add(new ListItem("Text 3", "Rabble rabble"));
            items.add(new ListItem("Text 4", "Rabble rabble"));
            items.add(new Header("Header 2"));
            items.add(new ListItem("Text 5", "Rabble rabble"));
            items.add(new ListItem("Text 6", "Rabble rabble"));
            items.add(new ListItem("Text 7", "Rabble rabble"));
            items.add(new ListItem("Text 8", "Rabble rabble"));
    
            TwoTextArrayAdapter adapter = new TwoTextArrayAdapter(this, items);
            setListAdapter(adapter);
        }
    
    }
    

    用于R.layout.header的布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
    
        <TextView
            style="?android:attr/listSeparatorTextViewStyle"
            android:id="@+id/separator"
            android:text="Header"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#757678"
            android:textColor="#f5c227" />
    
    </LinearLayout>
    

    用于R.layout.my_list_item的布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" >
    
        <TextView
            android:id="@+id/list_content1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_margin="5dip"
            android:clickable="false"
            android:gravity="center"
            android:longClickable="false"
            android:paddingBottom="1dip"
            android:paddingTop="1dip"
            android:text="sample"
            android:textColor="#ff7f1d"
            android:textSize="17dip"
            android:textStyle="bold" />
    
        <TextView
            android:id="@+id/list_content2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_margin="5dip"
            android:clickable="false"
            android:gravity="center"
            android:linksClickable="false"
            android:longClickable="false"
            android:paddingBottom="1dip"
            android:paddingTop="1dip"
            android:text="sample"
            android:textColor="#6d6d6d"
            android:textSize="17dip" />
    
    </LinearLayout>
    

    用于R.layout.activity_main.xml的布局

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
    
        <ListView
            android:id="@android:id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    
    </RelativeLayout>
    

    你也可以变得更花哨,使用ViewHolders,异步加载,或者你喜欢的任何东西

  5. # 5 楼答案

    作为替代方案,有一个很好的3rd party library专门为这个用例设计。因此,您需要根据存储在适配器中的数据生成标题。它们被称为Rolodex适配器,与ExpandableListViews一起使用。它们可以很容易地进行定制,使其行为类似于带有标题的普通列表

    使用OP的Event对象并知道头是基于与之关联的Date。。。代码如下所示:

    活动

        //There's no need to pre-compute what the headers are. Just pass in your List of objects. 
        EventDateAdapter adapter = new EventDateAdapter(this, mEvents);
        mExpandableListView.setAdapter(adapter);
    

    适配器

    private class EventDateAdapter extends NFRolodexArrayAdapter<Date, Event> {
    
        public EventDateAdapter(Context activity, Collection<Event> items) {
            super(activity, items);
        }
    
        @Override
        public Date createGroupFor(Event childItem) {
            //This is how the adapter determines what the headers are and what child items belong to it
            return (Date) childItem.getDate().clone();
        }
    
        @Override
        public View getChildView(LayoutInflater inflater, int groupPosition, int childPosition,
                                 boolean isLastChild, View convertView, ViewGroup parent) {
            //Inflate your view
    
            //Gets the Event data for this view
            Event event = getChild(groupPosition, childPosition);
    
            //Fill view with event data
        }
    
        @Override
        public View getGroupView(LayoutInflater inflater, int groupPosition, boolean isExpanded,
                                 View convertView, ViewGroup parent) {
            //Inflate your header view
    
            //Gets the Date for this view
            Date date = getGroup(groupPosition);
    
            //Fill view with date data
        }
    
        @Override
        public boolean hasAutoExpandingGroups() {
            //This forces our group views (headers) to always render expanded.
            //Even attempting to programmatically collapse a group will not work.
            return true;
        }
    
        @Override
        public boolean isGroupSelectable(int groupPosition) {
            //This prevents a user from seeing any touch feedback when a group (header) is clicked.
            return false;
        }
    }