(android) 动态嵌套回收器视图项随机变化的问题 [英] (android) Problems with random changes in dynamic nested recycler view items

查看:27
本文介绍了(android) 动态嵌套回收器视图项随机变化的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个动态的 Nested RecyclerView.

Hi, I'm making a dynamic Nested RecyclerView.

Outer RecyclerView (Routine) 由部分(A、B、C...)、添加按钮、

The Outer RecyclerView (Routine) consists of parts (A, B, C...), add button,

和delete按钮,内部RecyclerView(Detail Routine)由text view(set、weight和count)组成.

and delete button, and the inner RecyclerView (Detail Routine) consists of text view (set, weight and count).

当我添加一个外部项目时,它默认有一个内部 RecyclerView 项目.

When i add an outer item, it have one inner RecyclerView item by default.

我认为实施是成功的,但事实并非如此.

I thought the implementation was successful, but it wasn't.

图片是我提前制作了一些物品的条件.

The picture is a condition that I have made some items in advance.

这是一张在那里创建其他项目的图片.

This is a picture that creates additional items there.

但是,在图中,当我添加G item时,可以看到F item

However, in the picture, when I added the G item, you can see that the F item

B项有变化.

奇怪的是,G 项有两个基本项.本来就是一个.

And the G item, oddly enough, has two basic items. Originally, it is one.

第二张图是后期添加的项目.

The second picture is the later item addition.

如果我添加一个新的outer recyclerview项,整体会有一个新的变化

If i add a new outer recyclerview item, there will be a new change in the whole

再次物品.

我不确定为什么会发生这种变化.如果您添加一个新项目,您需要

I am not sure why this change is happening. If you add a new item, you want the

要保留的现有项目.

请告诉我原因

这是代码

RoutineAdapter.java(外部 RecyclerView Adpater)

public class RoutineAdapter extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> {
    Context context;
    ArrayList<RoutineModel> routineItems = new ArrayList<>();
    public RoutineDetailAdapter detailAdapter;
    OnRoutineItemClickListener listener;

    public void setOnRoutineClickListener(OnRoutineItemClickListener listener) {
        this.listener = listener;
    }

    public void addItem(RoutineModel item) {
        routineItems.add(item);
        notifyDataSetChanged();
    }

    public void addDetailItem(RoutineDetailAdapter curDetailAdapter) {
        curDetailAdapter.addItem(new RoutineDetailModel());
    }
    public void deleteDetailItem(RoutineDetailAdapter curDetailAdapter) {
        curDetailAdapter.deleteItem();
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);
        View itemView = inflater.inflate(R.layout.routine_item, parent, false);
        ViewHolder holder = new ViewHolder(itemView);
        detailAdapter = new RoutineDetailAdapter();
        holder.setRoutineDetailRecyClerView();
        holder.rv_detail.setAdapter(detailAdapter);
        detailAdapter.addItem(new RoutineDetailModel());

        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        RoutineModel curRoutineItem = routineItems.get(position);
        holder.setItems(curRoutineItem);
    }

    @Override
    public int getItemCount() {
        return routineItems.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder  {
        RecyclerView rv_detail;
        TextView routine;
        Button addSet;
        Button deleteSet;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            initViews();

            addSet.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    RoutineDetailAdapter curDetailAdapter = (RoutineDetailAdapter) rv_detail.getAdapter();
                    listener.OnAddBtnClick(curDetailAdapter);
                }
            });

            deleteSet.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    RoutineDetailAdapter curDetailAdapter = (RoutineDetailAdapter) rv_detail.getAdapter();
                    listener.OnDeleteBtnClick(curDetailAdapter);
                }
            });
        }

        private void initViews() {
            routine = itemView.findViewById(R.id.routine);
            rv_detail = itemView.findViewById(R.id.detail_routine);
            addSet = itemView.findViewById(R.id.add_set);
            deleteSet = itemView.findViewById(R.id.delete_set);
        }
        private void setItems(RoutineModel routineItem) {
            routine.setText(routineItem.getRoutine());
        }

        public void setRoutineDetailRecyClerView() {
            rv_detail.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false));
        }
    }

    public interface OnRoutineItemClickListener {
        public void OnAddBtnClick(RoutineDetailAdapter detailAdapter);
        public void OnDeleteBtnClick(RoutineDetailAdapter detailAdapter);
    }
}

RoutineDetailAdapter.java(内部 RecyclerView 适配器)

public class RoutineDetailAdapter extends  RecyclerView.Adapter<RoutineDetailAdapter.ViewHolder>{
    ArrayList<RoutineDetailModel> items = new ArrayList<>();
    Context context;
    int insertPosition;
    int deletePosition;

    public void addItem(RoutineDetailModel item) {
        items.add(item);
        notifyItemInserted(insertPosition);
    }

    public void deleteItem() {
        try {
            if(items.size() > 1) { // Leave at least one set
                items.remove(deletePosition);
                notifyItemRemoved(deletePosition);
                deletePosition -= 1;
            }
        } catch (Exception e) {
            // empty
        }
    }

    public ArrayList<RoutineDetailModel> getItem() {
        return this.items;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(R.layout.routine_detail_item, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        RoutineDetailModel item = items.get(position);
        holder.setItem(item, position);
        insertPosition = position + 1;
        deletePosition = position;
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView set;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            set = itemView.findViewById(R.id.set);
        }

        private void setItem(RoutineDetailModel item, int setCount) {
            set.setText(setCount + 1 + "set");
        }
    }
}

WriteRoutineActivity.java

public class WriteRoutineActivity extends AppCompatActivity {
    Button add_routine_btn;
    TextView title;
    RecyclerView routine_rv;

    RoutineAdapter routineAdapter;
    LinearLayoutManager routineLayoutManger;
    ArrayList<String> titleData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_write_routine);

        initViews();
        setPageTitle(getIntent());
        setRoutineRecyclerview();

        routineAdapter = new RoutineAdapter();
        routine_rv.setAdapter(routineAdapter);

        add_routine_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                WorkoutListDialogFragment routineDialog = new WorkoutListDialogFragment();
                routineDialog.show(getSupportFragmentManager(), "RoutineListDialog");
            }
        });

        routineAdapter.setOnRoutineClickListener(new RoutineAdapter.OnRoutineItemClickListener() {
            @Override
            public void OnAddBtnClick(RoutineDetailAdapter curDetailAdapter) {
                routineAdapter.addDetailItem(curDetailAdapter);
            }

            @Override
            public void OnDeleteBtnClick(RoutineDetailAdapter curDetailAdapter) {
                routineAdapter.deleteDetailItem(curDetailAdapter);
            }
        });
    }

    private void initViews() {
        title = findViewById(R.id.body_part_detail_title);
        routine_rv = findViewById(R.id.routine_recyclerview);
        add_routine_btn = findViewById(R.id.add_routine);
    }

    private void setRoutineRecyclerview() {
        routineLayoutManger = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
        routine_rv.setLayoutManager(routineLayoutManger);
        routine_rv.setHasFixedSize(true);
        RecyclerView.ItemDecoration divider = new DividerItemDecorator(ContextCompat.getDrawable(getApplicationContext(), R.drawable.divider));
        routine_rv.addItemDecoration(divider);
    }

    public void setPageTitle(Intent intent) {
        if(intent != null) {
            titleData = intent.getStringArrayListExtra("bodypart");
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                String new_title = String.join(" / ", titleData);
                title.setText(new_title);
            }
            else {
                StringBuilder new_title = new StringBuilder();
                for (int i = 0; i < titleData.size(); i++) {
                    if (i == titleData.size() - 1) {
                        new_title.append(titleData.get(i));
                        break;
                    }
                    new_title.append(titleData.get(i)).append(" / ");
                }
                title.setText(new_title);
            }
        }
    }

    public void addRoutine(String routine) {
        routineAdapter.addItem(new RoutineModel(routine));
        routine_rv.smoothScrollToPosition(routineAdapter.getItemCount() - 1);
    }
}

添加

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".data.DailyRecordDetailActivity">
    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Theme.AppBarOverlay"
        app:elevation="0dp">
        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <TextView
                    android:id="@+id/body_part_detail_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="PART"
                    android:textColor="@color/white"
                    android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
                    android:layout_centerHorizontal="true"/>
            </RelativeLayout>
        </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
        <Button
            android:id="@+id/add_routine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ROUTINE ADD"
            android:backgroundTint="@color/light_green"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/routine_recyclerview"
            app:layout_constraintRight_toRightOf="parent"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/routine_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:scrollbars="vertical"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/add_routine"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

RoutineItem.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@color/white"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp">
    <LinearLayout
        android:id="@+id/linear_routine"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent">
        <TextView
            android:id="@+id/routine"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:paddingLeft="10dp"
            android:text="ROUTINE"
            android:textSize="16dp"
            android:textStyle="bold"
            android:layout_weight="2"/>
        <Button
            android:id="@+id/add_set"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="?android:selectableItemBackground"
            android:text="ADD"
            android:textColor="@color/black"
            android:gravity="center"
            android:layout_weight="1"/>
        <Button
            android:id="@+id/delete_set"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="?android:selectableItemBackground"
            android:text="DELETE"
            android:textColor="@color/black"
            android:layout_weight="1"/>
    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/detail_routine"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toBottomOf="@+id/linear_routine"
        app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

RoutineDetail.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="wrap_content"
    android:orientation="horizontal"
    android:layout_marginLeft="5dp"
    android:padding="10dp"
    android:clipToPadding="false">
    <TextView
        android:id="@+id/set"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="SET"/>
    <TextView
        android:id="@+id/weight"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="0 kg"/>
    <TextView
        android:id="@+id/reps"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="0"/>

</LinearLayout>

推荐答案

对于每个 RoutineModel 项,您都需要重新创建 detailAdapter 但需要新的实例.在下面的代码中检查 TODO:

For every RoutineModel item you recreate detailAdapter but you need new instance. Check TODO in code below:

public class RoutineAdapter extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> {
        Context context;
        ArrayList<RoutineModel> routineItems = new ArrayList<>();
        //public RoutineDetailAdapter detailAdapter; //TODO move it to local variable in method onCreateViewHolder
        OnRoutineItemClickListener listener;

喜欢这个

@NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);
        View itemView = inflater.inflate(R.layout.routine_item, parent, false);
        ViewHolder holder = new ViewHolder(itemView);
        RoutineDetailAdapter detailAdapter = new RoutineDetailAdapter(); //TODO Create local variable
        detailAdapter.addItem(new RoutineDetailModel());
        holder.setRoutineDetailRecyClerView();
        holder.rv_detail.setAdapter(detailAdapter);

        return holder;
    }

但这不是解决这个问题的好方法......最好使用一个具有多个项目视图的适配器.我现在没时间解释,稍后我会发布一些代码...

已编辑

我遇到了同样的问题,并以这种(更好的)方式解决了这个问题:

I had same problem and and solved this on this (better) way:

创建支持多视图的Adapter

Create Adapter that support multiple views

public class MultipleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private Context context;
    private List<Object> items; //List<Object or Generic class or abstarct base Model class parent of Routine and RoutineDetails>
    private OnItemClickListener listener; //TODO new interface

        ..............

}

像这样覆盖 onCreateViewHolder

Override onCreateViewHolder like this

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == 1){
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_item, parent, false);
            return new RoutineViewHolder (itemView);
        }/*else{*/
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_detail_item, parent, false);
            return new RoutineDetailsViewHolder (itemView);
        //}
    }

像这样覆盖 onBindViewHolder 并创建您的 updateViews 方法

Override onBindViewHolder like this and create your updateViews methods

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    Object object = items.get(position); //Object or Generic class or abstarct base Model class parent of Routine and RoutineDetails>
    if(object instanceof RoutineModel) {
        //create method
        updateRoutineViews((RoutineViewHolder) holder, (RoutineModel) object, position);
    }else if(object instanceof RoutineDetailsModel) {
        //create method
        updateRoutineDetailsViewHolder((RoutineDetailsViewHolder) holder, (RoutineDetailModel) object);
    }
}

并覆盖 getItemViewType 方法

and override getItemViewType method

@Override
    public int getItemViewType(int position) {
        Object object = items.get(position);
        if(object instanceof RoutineModel){
            return 1;
        }
        //else if instanceOf RoutineDetailModel return 0
        return 0; 
    }

这很简单,而且性能更好...

This is so simple and better for performance...

也在 OnItemClickListener 中按位置获取项目并像上面一样检查 instanceOf 对象.您可以使用 adapter.notifyDataSetChanges()

Also in OnItemClickListener get item by position and check instanceOf object like above. You can add new item to the clickedItemPosition + 1 with adapter.notifyDataSetChanges()

在 MainActivity 中,您必须创建包含例程和例程详细信息的混合列表

In MainActivity you have to create mixed list with Routine and Routine details

List<Object> mixedList = new ArrayList<>();
for(RoutineModel rm: routineList){
    mixedList.add(rm);
    if(rm has routineDetailModels){ //pseudo code
        for(RoutineDetailModels rmdetilas: rm.getRoutineDetailModels()){
            mixedList.add(rmdetilas);
        }
    }
}
adpater.swapData(mixedList); //create your method to swap or set data to adapter

已编辑处理点击

public interface OnItemClickListener{
    void onClick(View view, int position);
    void onLongClick(View view, int position);
}

adapter.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onClick(View view, int position) {
            Object item = (Object) adapter.getItem(position);
            if(item instanceof Routine) {
                if (view.getId() == R.id.delete_id) {
                    //TODO delete form list, notifyItemRemoved or generate all mixeddata again and swap
                } else if (view.getId() == R.id.whateveryouwant) {
                    //TODO doSomething()
                }

            }
        }

        @Override
        public void onLongClick(View view, int position) {

        }
    });

上面的代码只是如何解决问题的一个例子如需更多帮助,请随时发表评论

The code above is just an example of how to solve the problem For more help feel free to comment

编辑 2

public class RoutineViewHolder extends RecyclerView.ViewHolder  {
    public RecyclerView rv_detail;
    public TextView routine;
    public Button addSet;
    public Button deleteSet;

    public ViewHolder(@NonNull View itemView) {
        super(itemView);
        //initViews(); in constructor
        routine = itemView.findViewById(R.id.routine);
        rv_detail = itemView.findViewById(R.id.detail_routine);
        addSet = itemView.findViewById(R.id.add_set);
        deleteSet = itemView.findViewById(R.id.delete_set);
    } 
}

从 onBindViewHolder 调用的更新方法

update method called from onBindViewHolder

private void updateRoutineViews(RoutineViewHolder holder, RoutineModel routineItem, position){
    holder.routine.setText(routineItem.getRoutine());
    holder.rv_detail.setText(routineItem.getWhateverYouWant());

    holder.deleteSet.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onItemClickListener.onClick(v, position); //or holder.getAdapterPosition()
        }
    });
}


完整代码

创建完整的新应用来测试和理解(复制/粘贴此代码),然后集成到您的应用中...

Create complete new app to test it and understand (copy/paste this code), then integrate in your app...

还有更多改进,但我没有时间,这是一个快速修复

There are more improvements but I don't have time, this is a quick fix

活动

public class RoutineActivity extends AppCompatActivity {

    private MultipleViewAdapter adapter;
    private List<RoutineModel> routineList;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_routine);

        RecyclerView contentList = findViewById(R.id.list);
        contentList.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MultipleViewAdapter(this, new ArrayList<>());
        contentList.setAdapter(adapter);
        adapter.setOnItemClickListener(new MultipleViewAdapter.OnItemClickListener() {
            @Override
            public void onClick(View view, int position) {
                Object item = (Object) adapter.getItem(position);
                if(item instanceof RoutineModel) {
                    RoutineModel routineModel = (RoutineModel) item;
                    if (view.getId() == R.id.add_set) {
                        int weight = randomInt(99);
                        Toast.makeText(RoutineActivity.this, "New item with weight: " + weight + " kg", Toast.LENGTH_SHORT).show();
                        routineModel.addDetails(new RoutineDetailsModel(routineModel.getDetailsSize() + 1, weight));
                        adapter.swapData(getMixedList()); // OR add item to adapter and notify item inserted
                        //TODO implement SnappingLinearLayoutManager and set list.smoothScroleto... routineModel
                    } else if (view.getId() == R.id.delete_set) {
                        //TODO doSomething()
                        boolean deleted = routineModel.removeDetails(routineModel.getDetailsSize() - 1); // -1 !!! to delete last item
                        Toast.makeText(RoutineActivity.this, deleted ? "Last item is deleted": "No more items", Toast.LENGTH_SHORT).show();
                        adapter.swapData(getMixedList()); // OR remove item from adapter and notify item removed
                        //TODO implement SnappingLinearLayoutManager and set list.smoothScroleto.... routineModel
                    }

                }else if(item instanceof RoutineDetailsModel) {
                    RoutineDetailsModel routineModel = (RoutineDetailsModel) item;
                    Toast.makeText(RoutineActivity.this, "Weight: " + routineModel.getWeight() + " kg", Toast.LENGTH_SHORT).show();

                //TODO EDITED 4 (copy/paste this) random new Weight
                routineModel.setWeight(randomInt(99));
                adapter.notifyItemChanged(position);
                Toast.makeText(RoutineActivity.this, "New Weight: " + routineModel.getWeight() + " kg", Toast.LENGTH_SHORT).show();

                }
            }

            @Override
            public void onLongClick(View view, int position) {

            }
        });

        initFakeData();
        adapter.swapData(getMixedList());
    }


    private List<Object> getMixedList() {
        List<Object> mixedList = new ArrayList<>();
        for(RoutineModel rm: routineList){
            mixedList.add(rm);
            if(rm.getRoutineDetailsModel() != null && rm.getRoutineDetailsModel().size() > 0){
                for(RoutineDetailsModel rmdetilas: rm.getRoutineDetailsModel()){
                    mixedList.add(rmdetilas);
                }
            }
        }
        return mixedList;
    }


    private void initFakeData() {
        routineList = new ArrayList<>();
        for(int i = 0; i < 5; i++){
            RoutineModel routineModel = new RoutineModel(String.valueOf(i + 1));
            for(int j = 0; j < 4; j++){
                routineModel.addDetails(new RoutineDetailsModel(j+1, randomInt(99)));
            }
            routineList.add(routineModel);
        }
    }

    private int randomInt(int max) {
        return (int) Math.floor(Math.random() * max);
    }
}

活动布局

<?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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

适配器

public class MultipleViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private final Context context; // TODO only if you need conetxt
    private List<Object> items;
    private OnItemClickListener onItemClickListener;

    public MultipleViewAdapter(Context context, List<Object> items) {
        this.context = context;
        this.items = items;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == 1){
            View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_item, parent, false);
            return new RoutineViewHolder(itemView);
        }/*else{*/
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.routine_detail_item, parent, false);
        return new RoutineDetailsViewHolder(itemView);
        //}
    }


    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        Object object = items.get(position); //Object or Generic class or abstarct base Model class parent of Routine and RoutineDetails>
        if(object instanceof RoutineModel) {
            updateRoutineViews((RoutineViewHolder) holder, (RoutineModel) object, position);
        }else if(object instanceof RoutineDetailsModel) {
            updateRoutineDetailsViewHolder((RoutineDetailsViewHolder) holder, (RoutineDetailsModel) object, position);
        }
    }

    private void updateRoutineViews(RoutineViewHolder holder, RoutineModel routineItem, int position){
        holder.routine.setText("Routine " + routineItem.getRoutine());

        holder.addSet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(onItemClickListener != null) onItemClickListener.onClick(v, position);
            }
        });

        holder.deleteSet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(onItemClickListener != null) onItemClickListener.onClick(v, position);
            }
        });
    }

    private void updateRoutineDetailsViewHolder(RoutineDetailsViewHolder holder, RoutineDetailsModel routineDetailsModel, int position){
        holder.set.setText(routineDetailsModel.getSet() + " set");
        holder.weight.setText(routineDetailsModel.getWeight()  + " kg");
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(onItemClickListener != null) onItemClickListener.onClick(v, position);
            }
        });
    }


    @Override
    public int getItemViewType(int position) {
        Object object = items.get(position);
        if(object instanceof RoutineModel){
            return 1;
        }
        //else if instanceOf RoutineDetailModel return 0
        return 0;
    }

    @Override
    public int getItemCount() {
        if(items == null) return 0;
        return items.size();
    }

    public Object getItem(int position) {
        if(this.items == null || position < 0 || position >= this.items.size()) return null;
        return this.items.get(position);
    }

    public void swapData(List<Object> newItems) {
        if (newItems != null) {
            this.items = newItems;
            notifyDataSetChanged();
        }
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public interface OnItemClickListener{
        void onClick(View view, int position);
        void onLongClick(View view, int position);
    }


    public static class RoutineViewHolder extends RecyclerView.ViewHolder  {
        public TextView routine;
        public Button addSet;
        public Button deleteSet;

        public RoutineViewHolder(@NonNull View itemView) {
            super(itemView);
            //initViews(); in constructor
            routine = itemView.findViewById(R.id.routine);
            addSet = itemView.findViewById(R.id.add_set);
            deleteSet = itemView.findViewById(R.id.delete_set);
        }
    }

    public static class RoutineDetailsViewHolder extends RecyclerView.ViewHolder {
        public TextView set;
        public TextView weight;
        public RoutineDetailsViewHolder(@NonNull View itemView) {
            super(itemView);
            set = itemView.findViewById(R.id.set);
            weight = itemView.findViewById(R.id.weight);
        }
    }



}

常规模型

public class RoutineModel {

    private List<RoutineDetailsModel> routineDetailsList;
    private String routine;

    public RoutineModel(String routine) {
        this.routine = routine;
    }

    public List<RoutineDetailsModel> getRoutineDetailsModel() {
        return routineDetailsList;
    }

    public void setRoutineDetailsModel(List<RoutineDetailsModel> routineDetailsModel) {
        this.routineDetailsList = routineDetailsModel;
    }

    public void addDetails(RoutineDetailsModel item) {
        if(routineDetailsList == null) {
            routineDetailsList = new ArrayList<>();
        }
        this.routineDetailsList.add(item);
    }
    public boolean removeDetails(int index) {
        if(routineDetailsList == null || index >= routineDetailsList.size() || index < 0) return false;
        this.routineDetailsList.remove(index);
        return true;
    }

    public String getRoutine() {
        return routine;
    }

    public void setRoutine(String routine) {
        this.routine = routine;
    }

    public int getDetailsSize() {
        if(routineDetailsList == null) return 0;
        return routineDetailsList.size();
    }
}

RoutineDetailsModel

RoutineDetailsModel

public class RoutineDetailsModel {

    private int set;
    private int weight;

    public RoutineDetailsModel(int set, int weight) {
        this.set = set;
        this.weight = weight;
    }

    public int getSet() {
        return set;
    }

    public void setSet(int set) {
        this.set = set;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

项目布局

查找问题:routine_item.xmlroutine_detail_item.xml

这篇关于(android) 动态嵌套回收器视图项随机变化的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆