Android RecyclerView 2レベルリスト実装
17035 ワード
Android RecyclerView 2レベルリスト実装
2017.5.16 demoを追加
Demo
簡単に述べる
Androidアプリを開発する際には、どうしても2級リストを実現する必要がありますが、自分のプロジェクトで使用しているリストは
android.support.v7.widget
パッケージの中のRecyclerView
で、場合によっては異なるスタイルのリストを実現でき、拡張性が高いというメリットがあります.悪いところは何でも自分で実現しなければならない.だからRecyclerView
で実現しようとした二級リストには、ListView
のようなExpandableListView
がなく、自分で実現するしかないことに気づいた.実装ベース
RecyclerView
を使用する場合は、ListView
と同様に、Adapter
を作成してRecyclerView
がどのように動作するかを示す必要があります.RecyclerView
を作成する場合は、Adapter
を再ロードする必要があります.onCreateViewHolder()
タイプViewHolder
取得onBindViewHolder()
合計ロードitem
を返します.Created with Raphaël 2.1.0 Start getItemCount() getItemViewType() onCreateViewHolder() onBindViewHolder() End
また、カスタム
getItemViewType()
を探すための各コントロールも作成する必要があります.実現構想.
以上より,二次リストを実現するにあたって,
onCreateViewHolder
およびitem
において,一次プロジェクト(GroupItem)がロードされるか,二次サブプロジェクト(SubItem)がロードされるかを判断する.インプリメンテーションプロセス
二次リストデータフォーマット
一般に、1つのGroupItemの下に1つ、または複数のSubItemがあり、1対多である.ここで、このデータフォーマットは、以下のコードでカプセル化される
getItemCount()
でカプセル化される.public class DataTree<K, V> {
private K groupItem;
private List subItems;
public DataTree(K groupItem, List subItems) {
this.groupItem = groupItem;
this.subItems = subItems;
}
public K getGroupItem() {
return groupItem;
}
public List getSubItems() {
return subItems;
}
}
RecyclerView Itemステータス
item
カプセル化リストの各項目の状態は、RecyclerView
itemのタイプ、group itemまたはsubitemViewHolder
一級インデックス位置item
itemが二級サブプロジェクトである場合、サブプロジェクトインデックスを保存する private static class ItemStatus {
public static final int VIEW_TYPE_GROUPITEM = 0;
public static final int VIEW_TYPE_SUBITEM = 1;
private int viewType;
private int groupItemIndex = 0;
private int subItemIndex = -1;
public ItemStatus() {
}
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
public int getGroupItemIndex() {
return groupItemIndex;
}
public void setGroupItemIndex(int groupItemIndex) {
this.groupItemIndex = groupItemIndex;
}
public int getSubItemIndex() {
return subItemIndex;
}
public void setSubItemIndex(int subItemIndex) {
this.subItemIndex = subItemIndex;
}
}
ViewHolder
ここの
onCreateViewHolder()
とonBindViewHolder()
はそれぞれ異なるレイアウトファイルを使っているので、私はDataTree
を別々に書いて、以下のようにします. public static class GroupItemViewHolder extends RecyclerView.ViewHolder {
...
public GroupItemViewHolder(View itemView) {
super(itemView);
...
}
}
public static class SubItemViewHolder extends RecyclerView.ViewHolder {
...
public SubItemViewHolder(View itemView) {
super(itemView);
...
}
}
その他のプロパティとメソッド
ItemStatus
viewType
表示用データgroupItemIndex
保存subItemIndex
ステータス //
public void setDataTrees(List> dt) {
this.dataTrees = dt;
initGroupItemStatus(groupItemStatus);
notifyDataSetChanged();
}
// , groupItem
private void initGroupItemStatus(List l) {
for (int i = 0; i < dataTrees.size(); i++) {
l.add(false);
}
}
getItemStatusByPosition()メソッド実装
名前の通り、
groupItem
に基づいてそのsubItem
を判断する状態を計算し、1つのViewHolder
を返すために使用される.コードは次のとおりです.
private ItemStatus getItemStatusByPosition(int position) {
ItemStatus itemStatus = new ItemStatus();
int count = 0; // groupItemIndex = i ,position
int i = 0;
// groupItem
for (i = 0; i < groupItemStatus.size(); i++ ) {
//pos ,item groupItem
if (count == position) {
itemStatus.setViewType(ItemStatus.VIEW_TYPE_GROUPITEM);
itemStatus.setGroupItemIndex(i);
break;
//pos ,item groupItem(i - 1) subItem
} else if (count > position) {
itemStatus.setViewType(ItemStatus.VIEW_TYPE_SUBITEM);
itemStatus.setGroupItemIndex(i - 1);
itemStatus.setSubItemIndex(position - ( count - dataTrees.get(i - 1).getSubItems().size() ) );
break;
}
// groupItem , , count++
count++;
// groupItem “ ” ,count groupItem
if (groupItemStatus.get(i)) {
count += dataTrees.get(i).getSubItems().size();
}
}
// groupItem
if (i >= groupItemStatus.size()) {
itemStatus.setGroupItemIndex(i - 1);
itemStatus.setViewType(ItemStatus.VIEW_TYPE_SUBITEM);
itemStatus.setSubItemIndex(position - ( count - dataTrees.get(i - 1).getSubItems().size() ) );
}
return itemStatus;
}
getItemCount()メソッド実装
このメソッドはリストを表示するときに複数回実行され、返された項目のカウントが正しくないとプログラムがエラーで潰れ、コードは以下の通りです.
@Override
public int getItemCount() {
Logger.i("1");
int itemCount = 0;
if (groupItemStatus.size() == 0) {
return 0;
}
for (int i = 0; i < dataTrees.size(); i++) {
if (groupItemStatus.get(i)) {
itemCount += dataTrees.get(i).getSubItems().size() + 1;
} else {
itemCount++;
}
}
return itemCount;
}
その他の方法の実装
このメソッドは、
context
の前に実行され、list dataTrees
が返されます.コードは次のとおりです. @Override
public int getItemViewType(int position) {
return getItemStatusByPosition(position).getViewType();
}
list groupItemStatus
で返されるgroupItem
によって異なるプロジェクトレイアウトを選択します.コードは次のとおりです. @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
RecyclerView.ViewHolder viewHolder = null;
if (viewType == ItemStatus.VIEW_TYPE_GROUPITEM) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout
.item_artist_detail_album, parent, false);
viewHolder = new GroupItemViewHolder(v);
} else if (viewType == ItemStatus.VIEW_TYPE_SUBITEM) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout
.item_artist_detail_track, parent, false);
viewHolder = new SubItemViewHolder(v);
}
return viewHolder;
}
position
に基づいて異なるitem
をバインドし、コードは以下の通りである: @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ItemStatus itemStatus = getItemStatusByPosition(position);
final DataTree dt = dataTrees.get(itemStatus.getGroupItemIndex());
if ( itemStatus.getViewType() == ItemStatus.VIEW_TYPE_GROUPITEM ) {
final GroupItemViewHolder groupItemVh = (GroupItemViewHolder) holder;
. . . // groupItem, groupItem
groupItemVh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int groupItemIndex = itemStatus.getGroupItemIndex();
if ( !groupItemStatus.get(groupItemIndex) ) {
. . . //groupItem “ ” “ ”
groupItemStatus.set(groupItemIndex, true);
notifyItemRangeInserted(groupItemVh.getAdapterPosition() + 1, dt.getSubItems().size());
} else {
. . . //groupItem “ ” “ ”
groupItemStatus.set(groupItemIndex, false);
notifyItemRangeRemoved(groupItemVh.getAdapterPosition() + 1, dt.getSubItems().size());
}
}
});
} else if (itemStatus.getViewType() == ItemStatus.VIEW_TYPE_SUBITEM) {
SubItemViewHolder subItemVh = (SubItemViewHolder) holder;
. . . // subItem, subItem
subItemVh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
. . . // subItem
}
});
}
}
まとめ
二級リストは
ItemStatus
を小さく拡張し、実現の過程で、少し面倒な点は特定のonCreateViewHolder()
を識別することであり、すなわちint viewType
の実現であり、ここでは簡単にポーリングを巡る方法で判断すると、より簡単でリソースを節約する方法があるはずだ.2次リストを実装した後,理論的にはマルチレベルリストを実装することができ,試してみることができる.に付随
この方法で実現する前に、
getItemViewType()
が提供する方法であるviewType
を試みたことがあるが、viewType
のロードメカニズムにより、リストがインタフェースから切り出されると破棄され、再び表示されると、ViewHolder
は以前のものではなく新しいRecyclerView
を再作成するので、以前のitem
は見えなくなり、最後に実現できなかったので、興味のある方は試してみてください.[Android RecyclerViewは完全解析体験芸術的なコントロール-hongyang-CSDNブログを使用]http://blog.csdn.net/lmj623565791/article/details/45059587 ↩