何らかの種類のイベントを含む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);
そして、これは私のクラスのTwoTextがどのように見えるかです:
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 Android.app.Activity;
import Android.content.Context;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.widget.ArrayAdapter;
import Android.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;
}
}
これはmy_list_item.xmlです
<?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="vertical" >
<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
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>
</LinearLayout>
現時点で私がしていることは、ヘッダーを通常のリストオブジェクトと同じように追加することですが、ヘッダーとして追加したいので、私の場合は日付を付けます。
ヘッダーのxmlに次のコードがあります。
<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" />
不要な場合は非表示にし、必要な場合は表示しようとしましたが、残りのコードを台無しにしました。私はさらにいくつかのチュートリアルを試しましたが、それらも同じ効果がありました。
誰でも簡単な方法を教えてもらえますか?
方法は次のとおりです。キーは、Adapter
クラスの getItemViewType および getViewTypeCount です。 getViewTypeCount
は、リストにあるアイテムのタイプの数を返します。この場合、ヘッダーアイテムとイベントアイテムがあるため、2つです。 getItemViewType
は、入力View
にあるposition
のタイプを返します。
その後、AndroidはView
に適切なタイプのconvertView
を自動的に渡してくれます。
以下のコードの結果は次のようになります。
最初に、2つのリスト項目タイプが実装するインターフェイスがあります
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); }
EDITBetter For Performance ..スクロール時に気付くことができます
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
を使用したり、非同期でロードしたり、好きなものをロードしたりできます。
おそらく ExpandableListView を探しています。これには、項目(子)を分離するヘッダー(グループ)があります。
このテーマに関する素晴らしいチュートリアル: here 。
別の方法として、このユースケース専用に設計されたNice サードパーティライブラリ があります。これにより、アダプターに保存されているデータに基づいてヘッダーを生成する必要があります。それらは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;
}
}
日付(たとえば、2016年12月1日)をヘッダーとして作成したこと。 StickyHeaderListViewライブラリを使用しました
https://github.com/emilsjolander/StickyListHeaders
日付をミリ単位のlongに変換し(時間を含めない)、ヘッダーIDとして作成します。
@Override
public long getHeaderId(int position) {
return <date in millis>;
}
ここにサンプルプロジェクトがあります 、antewの詳細かつ有用な回答に基づいて、スクロールパフォーマンスを改善するためにビューホルダーを組み込む複数のヘッダーを持つListView
を実装します。
このプロジェクトでは、ListView
で表されるオブジェクトは、クラスHeaderItem
またはクラスRowItem
のいずれかのインスタンスであり、どちらも抽象クラスItem
のサブクラスです。 Item
の各サブクラスは、カスタムアダプターの異なる変数ItemAdapter
に対応しています。 ItemAdapter
のメソッドgetView()
は、各リスト項目のビューの作成を、アダプターのgetView()
メソッドに渡される位置で使用されるHeaderItem
サブクラスに応じて、RowItem
またはItem
の個別のgetView()
メソッドに委任します。各Item
サブクラスは、独自のビューホルダーを提供します。
ビューホルダーは次のように実装されます。 Item
サブクラスのgetView()
メソッドは、View
のgetView()
メソッドに渡されたItemAdapter
オブジェクトがヌルかどうかをチェックします。その場合、適切なレイアウトが拡大され、ビューホルダーオブジェクトがインスタンス化され、View.setTag()
を介して拡大されたビューに関連付けられます。 View
オブジェクトがnullでない場合、ビューホルダーオブジェクトは既にビューに関連付けられており、ビューホルダーは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;
}
}
また、各アイテムサブクラスに1つずつ、2つのリストアイテムレイアウトがあります。 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の一部の画像を次に示します。