عرض شجرة RecyclerView (بدون مكتبات الأطراف الثالثة والمصفوفات التابعة)

يوم جيد ، أيها القراء الأعزاء.

في مقالتي ، أريد مشاركة تطبيق طريقة عرض الشجرة مع RecyclerView. دون استخدام أي مكتبات إضافية ودون استخدام مجموعة فرعية.
من يهتم ، من فضلك ، تحت القط. سأحاول وصف قدر الإمكان ماذا وكيف.



مبدأ تشكيل قائمة العناصر هو أنه سيتم عرض العناصر الفرعية أو إخفاؤها.

على الرغم من أنني قلت إن التنفيذ سيكون بدون مكتبات إضافية ، إلا أن المكتبات القياسية لا تزال بحاجة إلى الاتصال.

مكتبات متصلة
dependencies { implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:design:26.1.0' implementation 'com.android.support:recyclerview-v7:26.1.0' } 


ستكون العلامة ضئيلة للغاية - قائمة RecyclerView فقط.

العلامات
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/recycler_list"> </android.support.v7.widget.RecyclerView> </RelativeLayout> 


بالإضافة إلى ذلك ، نحتاج إلى فصل منفصل سنخزن به قيم القائمة.

فئة البيانات Data.java
 public final class Data { private String valueText = ""; //  private int valueId = 0; //  private boolean itemParent = false; //    private int parentId = -1; //id ,    private boolean childVisibility = false; //   //     public boolean isItemParent() { return itemParent; } //    public void setItemParent(boolean newItemParent) { itemParent = newItemParent; } //    public boolean isChildVisibility() { return childVisibility; } //     public void setChildVisibility(boolean newChildVisibility) { childVisibility = newChildVisibility; } //    public int getParentId() { return parentId; } //    public void setParentId(int newParentId) { parentId = newParentId; } //   public String getValueText() { return valueText; } //   public void setValueText(String newValueText) { valueText = newValueText; } //   public int getValueId() { return valueId; } //   public void setValueId(int newValueId) { valueId = newValueId; } } 


يجب أن تكون التعليقات واضحة ، لكنني سأوضحها. لكل عنصر من عناصر القائمة ، سنقوم بتخزين قيمة المعرف ، وقيمة الاسم ، والنص ، ومعرف العنصر الأصل ، والوسم الذي يشير إلى أن العنصر هو العنصر الأصل ، والقيمة المرئية للعناصر الفرعية التابعة للطفل .

الخطوة التحضيرية التالية هي إنشاء ترميز لعنصر القائمة نفسه.

ترميز item.xml
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/item" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!--     --> <android.support.v7.widget.AppCompatImageView android:id="@+id/icon_tree" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/icon_hide" android:visibility="gone" app:backgroundTint="@color/colorPrimary" android:layout_centerVertical="true"/> <LinearLayout android:id="@+id/block_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_toRightOf="@+id/icon_tree"> <!--  --> <TextView android:id="@+id/value_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:foreground="?android:attr/selectableItemBackground" android:text="sdfdsf"/> </LinearLayout> <!--  --> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/colorPrimary" android:layout_below="@+id/block_text" android:layout_marginTop="4dp" android:layout_marginLeft="4dp" android:layout_marginRight="4dp"/> </RelativeLayout> </LinearLayout> 


مطلوب AppCompatImageView لعرض حالة العنصر الأصل. TextView - لعرض قيمة عنصر. عرض هو فقط للمشاركة.

الخطوة التحضيرية النهائية هي إنشاء فصل دراسي للتعامل مع محول القائمة.

محول للحصول على قائمة RecyclerViewAdapter.java
 public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> { private View vv; private List<Data> allRecords; //   public RecyclerViewAdapter(List<Data> records) { allRecords = records; } @Override public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false); return new RecyclerViewAdapter.ViewHolder(v); } @Override public void onBindViewHolder(final RecyclerViewAdapter.ViewHolder viewHolder, int i) { Data record = allRecords.get(i); String value = record.getValueText(); int id = record.getValueId(); int parentId = record.getParentId(); final int position = i; final String text = "#" + id + ": " + value + " (id  : " + parentId + ")"; //   ,    if (parentId >= 0) { //      setVisibility(viewHolder.item, allRecords.get(parentId).isChildVisibility(), parentId); } else { //  ,   setVisibility(viewHolder.item, true, parentId); } //      if (record.isItemParent()) { viewHolder.iconTree.setVisibility(View.VISIBLE); //   if (record.isChildVisibility()) //   viewHolder.iconTree.setBackgroundResource(R.drawable.icon_show); else //   viewHolder.iconTree.setBackgroundResource(R.drawable.icon_hide); } else //   viewHolder.iconTree.setVisibility(View.GONE); //   if (!TextUtils.isEmpty(value)) { viewHolder.valueText.setText(value); } //     viewHolder.valueText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Data dataItem = allRecords.get(position); if (dataItem.isItemParent()) { //   ,     dataItem.setChildVisibility(!dataItem.isChildVisibility()); notifyDataSetChanged(); } else { //   ,    Snackbar snackbar = Snackbar.make(vv, text, Snackbar.LENGTH_LONG); snackbar.show(); } } }); } //   private void setVisibility(View curV, boolean visible, int parentId) { // ,      LinearLayout vPadding = curV.findViewById(R.id.block_text); LinearLayout.LayoutParams params; if (visible) { params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); if (vPadding != null) { if (parentId >= 0) { //  ,   vPadding.setPadding(80, 0, 0, 0); } else { vPadding.setPadding(0, 0, 0, 0); } } } else params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); curV.setLayoutParams(params); } @Override public int getItemCount() { return allRecords.size(); } class ViewHolder extends RecyclerView.ViewHolder { private LinearLayout item; private TextView valueText; private AppCompatImageView iconTree; public ViewHolder(View itemView) { super(itemView); vv = itemView; item = vv.findViewById(R.id.id_item); valueText = vv.findViewById(R.id.value_name); iconTree = vv.findViewById(R.id.icon_tree); } } } 


تتم المعالجة الرئيسية في إجراء onBindViewHolder . لكل عنصر من عناصر القائمة ، يتم الحصول على معرفها والقيمة والمعلمات الخاصة بالقيمة الأصل. إظهار أو إخفاء العناصر الفرعية ، وكذلك أيقونة الحالة للعنصر الأصل. حسنًا ، تم تعليق معالجة النقرات في القائمة. ثم يقرر الجميع كيف يحتاج إلى معالجة القائمة. يوضح المثال ببساطة رسالة ذات معرف وقيمة العنصر.
في إجراء إظهار أو إخفاء إخفاء setVisibility ، يتم وضع مسافة بادئة للنص بالإضافة إلى العنصر الفرعي عند 80 بكسل.

يبقى فقط لملء القائمة في المكان المناسب.

بناء قائمة
 List<Data> records = new ArrayList<Data>(); //  Data record; RecyclerViewAdapter adapter; int parentId; RecyclerView recyclerView = findViewById(R.id.recycler_list); record = new Data(); record.setValueId(1); record.setValueText("  1"); record.setItemParent(true); //  records.add(record); parentId = records.size() -1; for (int ind = 1; ind <= 3; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText(" " + ind); record.setParentId(parentId); records.add(record); } record = new Data(); record.setValueId(1); record.setValueText("  "); record.setItemParent(true); //  records.add(record); parentId = records.size() -1; for (int ind = 4; ind <= 7; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText("  " + ind); record.setParentId(parentId); records.add(record); } record = new Data(); record.setValueId(1); record.setValueText("  "); record.setItemParent(true); //  records.add(record); parentId = records.size() -1; for (int ind = 8; ind <= 12; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText(" " + ind); record.setParentId(parentId); records.add(record); } for (int ind = 13; ind <= 18; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText("  " + ind); records.add(record); } for (int ind = 19; ind <= 21; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText("   " + ind); records.add(record); } record = new Data(); record.setValueId(1); record.setValueText("  "); record.setItemParent(true); //  records.add(record); parentId = records.size() -1; for (int ind = 22; ind <= 30; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText(": " + ind); record.setParentId(parentId); records.add(record); } for (int ind = 31; ind <= 45; ind ++) { record = new Data(); record.setValueId(ind); record.setValueText("   " + ind); records.add(record); } adapter = new RecyclerViewAdapter(records); RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator(); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(layoutManager); recyclerView.setItemAnimator(itemAnimator); 


والنتيجة هي قائمة بسيطة مع دعم للعناصر الفرعية. يتيح لك هذا التطبيق ملء العديد من العناصر المتداخلة. لكنك تحتاج إلى تحسين المسافة البادئة للعناصر الفرعية قليلاً إذا كان مستوى التعشيش أكثر من 1.

شكرا لكم جميعا على اهتمامكم والمشاريع الناجحة.

Source: https://habr.com/ru/post/ar431718/


All Articles