查閱了很多關於層級數列的,筆者技術薄弱,因爲用到了註解和反射什麼的,感覺看起來比較複雜,所以想是否可以有別的方式實現,嘗試了會兒之後實現瞭如圖的效果
方塊爲佔位的列項,具體圖片自行更換
- 首先每列都爲ImageView + TextView 所以xml文件是這樣的list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="40dp" >
<ImageView
android:id="@+id/id_item_icon"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:src="@drawable/tree_close" />
<TextView
android:layout_centerVertical="true"
android:id="@+id/id_item_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/id_item_icon"
android:text="@string/hello_world"
android:textSize="18dp" />
</RelativeLayout>
- 因爲涉及到層級,感覺用遞歸的方式去實現會比較簡單,所以在設計Javabean時,考慮了樹的數據結構的方式
TreeItem.java
public class TreeItem {
//儲存的數據
private String mString;
//層級,方便縮進
private int level;
//是否展開
private boolean open;
//子項
private List<TreeItem> mSons;
public TreeItem(String string) {
mString = string;
//每個item默認層級爲1,被添加到父類中時根據父類更改層級
this.level = 1;
this.open = false;
}
public String getString() {
return mString;
}
//是否有子項,若有則返回子項集合,若沒有則爲空
public List<TreeItem> getSons() {
if(mSons == null || mSons.size() == 0)
return null;
return mSons;
}
public TreeItem addSons(TreeItem sons) {
//在初次添加時候初始化
if(mSons == null)
mSons = new ArrayList<>();
//根據自己層級爲子項設定層級
sons.setSonLevel(sons,this.level);
//把子項加入到自己的列表
mSons.add(sons);
return this;
}
public void setString(String string) {
mString = string;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public boolean isOpen() {
return open;
}
public void setOpen(boolean open) {
this.open = open;
}
private void setSonLevel(TreeItem treeItem,int level){
//子項的層級比父類大1
treeItem.setLevel(level+1);
//若有子項,則遞歸調用,設置其層級
if (treeItem.getSons() != null) {
for (TreeItem item : treeItem.getSons()) {
setSonLevel(item, item.getLevel());
}
}
}
}
這樣的設計使得添加數據比較方便靈活,結構清晰,可以直接看出顯示的效果
mTreeItems.add(new TreeItem("Game")
.addSons(new TreeItem("Steam")
.addSons(new TreeItem("CHi"))
.addSons(new TreeItem("Sha")
.addSons(new TreeItem("bbbb"))
.addSons(new TreeItem("cccc"))))
.addSons(new TreeItem("LOL"))
.addSons(new TreeItem("Car")));
- TreeListAdapter.java 在適配器中,分爲兩個列表,一個儲存所有的子項,一個用於儲存需要展示的數據,在每一次刷新列表時候都重新填充列表
public class TreeListAdapter extends RecyclerView.Adapter<TreeListAdapter.TreeViewHolder> {
private Context mContext;
//傳入的列表數據
private List<TreeItem> mTreeItems;
//用於判斷是否爲第一次加載,方便爲展示列表重新添加數據
private boolean begin;
//展示的列表數據
private List<TreeItem> mItemList;
public TreeListAdapter(Context context, List<TreeItem> treeItems) {
mContext = context;
mTreeItems = treeItems;
mItemList = new ArrayList<>();
begin = true;
}
@NonNull
@Override
public TreeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false);
TreeViewHolder holder = new TreeViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull TreeViewHolder holder, int position) {
//在getList方法中爲mItemList添加了所有需要展示出來的數據,所以根據順序依次展示即可
TreeItem treeItem = mItemList.get(position);
//設置縮進
holder.itemView.setPadding(30 * treeItem.getLevel(), 0, 0, 0);
//如果有子類
if (treeItem.getSons() != null) {
//如果子項展開了
if (treeItem.isOpen()) {
holder.mImageView.setBackgroundResource(R.drawable.tree_open);
} else {
holder.mImageView.setBackgroundResource(R.drawable.tree_close);
}
//給有子項的列表圖片添加點擊事件,更改是否展開
holder.mImageView.setOnClickListener((v) -> {
treeItem.setOpen(!treeItem.isOpen());
//刷新列表,重新添加數據
begin = true;
notifyDataSetChanged();
});
} else {
//根節點設置標誌
holder.mImageView.setBackgroundResource(R.drawable.ic_launcher_background);
}
//添加文本
holder.mTextView.setText(treeItem.getString());
}
//因爲在每次刷新列表首先調用的是這個方法,所以在這個方法中填充mItemList列表
@Override
public int getItemCount() {
if (begin) {
mItemList.clear();
getList(mTreeItems);
//每次刷新只添加一次
begin = false;
}
return mItemList.size();
}
//傳入TreeItem數列
private void getList(List<TreeItem> treeItems) {
//依次取出數列中的每一項
for (TreeItem treeItem : treeItems) {
//首先加入到需要展示的列表中
mItemList.add(treeItem);
//如果此項又有子項,且是展開的
if (treeItem.getSons() != null && treeItem.isOpen()) {
//則把此項的子項列表傳入
getList(treeItem.getSons());
}
}
}
class TreeViewHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
TextView mTextView;
public TreeViewHolder(@NonNull View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.id_item_icon);
mTextView = itemView.findViewById(R.id.id_item_text);
}
}
}
- 主界面xml文件 activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/id_listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
- 主界面activity :MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List<TreeItem> mTreeItems = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addlist();
TreeListAdapter adapter = new TreeListAdapter(this,mTreeItems);
mRecyclerView = findViewById(R.id.id_listview);
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
private void addlist(){
mTreeItems.add(new TreeItem("Game")
.addSons(new TreeItem("Steam")
.addSons(new TreeItem("CHi"))
.addSons(new TreeItem("Sha")
.addSons(new TreeItem("bbbb"))
.addSons(new TreeItem("cccc"))))
.addSons(new TreeItem("LOL"))
.addSons(new TreeItem("Car")));
}
}
github地址:https://github.com/jiangkerLove/RecyclerViewList