猿问

具有相互通信的多个视图类型的 Recyclerview?

具有多种视图类型的 RecyclerView 是否可以相互传递数据/通信/监听?

我有一个具有 3 种视图类型的 RecyclerView(分别命名为顶部、中间、底部)。我有 2 个编辑文本位于第二个视图类型中,名为重量和数量。第三个视图类型中的 1 个文本视图计算并显示输入的重量和数量的体积。我希望第三个视图类型包含在输入重量或数量字段时动态动态更改的总体积。


largeQ
浏览 129回答 1
1回答

波斯汪

您可以使用Google Android架构中的LiveData以及一些接口来实现您想要的。-> 声明Interfaces您需要调用的各种方法ViewHolders来实现您想要的逻辑interface AnimalVolumeChangeListener{    public void onAnimalVolumeChanged(int groupId, double previousVolume, double currentVolume);}interface TotalVolumeInterface{    public Pair<LifecycleOwner,LiveData<Double>> getTotalVolume(int groupId);    public void removeObservers(int groupId);}-> 将这些接口作为对象传递到 Recycler Adapter 的构造函数中。class Animal_Volume_Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {    private ArrayList<AnimalsArray> mList;    private TotalVolumeInterface mTotalVolumeInterface;    private AnimalVolumeChangeListener mAnimalVolumeChangeListener;    private double volume = 0;    public Animal_Volume_Adapter(ArrayList<AnimalsArray> list,                                 TotalVolumeInterface totalVolumeInterface,                                 AnimalVolumeChangeListener animalVolumeChangeListener) {        this.mList = list;        this.mTotalVolumeInterface = totalVolumeInterface;        this.mAnimalVolumeChangeListener = animalVolumeChangeListener;    }-> 在创建视图持有者时将您作为参数传递给相应视图持有者的接口设置@Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        switch (viewType) {            case AnimalsArray.TOP:                View top = LayoutInflater.from(parent.getContext()).inflate(R.layout.animal_top_layout, parent, false);                return new Top(top);            case AnimalsArray.MIDDLE:                View data = LayoutInflater.from(parent.getContext()).inflate(R.layout.animal_middle_layout, parent, false);                Middle middleHolder = new Middle(data);                middleHolder.setAnimalVolumeChangeListener(mAnimalVolumeChangeListener);                return middleHolder;            case AnimalsArray.BOTTOM:                View footer = LayoutInflater.from(parent.getContext()).inflate(R.layout.animal_bottom_layout, parent, false);                Bottom bottomHolder = new Bottom(footer);                bottomHolder.setTotalVolumeInterface(mTotalVolumeInterface);                return bottomHolder;        }        return null;    }修改ViewHolder类static class Middle extends RecyclerView.ViewHolder {    Context context;    EditText weight;    EditText quantity;    TextView volume;    AnimalVolumeChangeListener animalVolumeChangeListener;    Middle(final View itemView) {        super(itemView);        context = itemView.getContext();        volume = (EditText) itemView.findViewById(R.id.volume);        weight = (EditText) itemView.findViewById(R.id.weight);        quantity= (EditText) itemView.findViewById(R.id.quantity);    }    public void setAnimalVolumeChangeListener(AnimalVolumeChangeListener animalVolumeChangeListener) {        this.animalVolumeChangeListener = animalVolumeChangeListener;    }}static class Bottom extends RecyclerView.ViewHolder {    TextView volume;    TotalVolumeInterface totalVolumeInterface;    Bottom(View itemView) {        super(itemView);        volume = (TextView) itemView.findViewById(R.id.volumeText);    }    public void setTotalVolumeInterface(TotalVolumeInterface totalVolumeInterface) {        this.totalVolumeInterface = totalVolumeInterface;    }}-> 在需要时从 onBindViewHolder 中的界面调用方法。在您的情况下,您需要有一种方法来识别 ViewHolderMiddle的总体积对 ViewHolder 的值有贡献Bottom(因此下面我用来groupId表示此参数)。@Override    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {        final AnimalsArray object = mList.get(position);        /* middle holders contributing to the total volume of the same have the         *same groupId together with their corressponding bottom holder.         *TODO: Assigned this value in accordance to however you are assigning Middle ViewHolders to Bottom ViewHolders*/        int groupId = 0;        if (object != null) {            switch (object.getCategory()) {                case AnimalsArray.TOP:                    break;                case AnimalsArray.MIDDLE:                    Middle middleHolder = (Middle) holder;                    middleHolder.weight.addTextChangedListener(new TextWatcher() {                        @Override                        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {                        }                        @Override                        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,                                                      int arg3) {                        }                        @Override                        public void afterTextChanged(Editable arg0) {                            //While this edittext is being changed, I would like the 3rd viewtype which contains the volume to be calculated on the fly as the user enters numbers in this field.                            String volumeBeforeChange = middleHolder.volume.getText().toString();                            double previousVolume = Double.parseDouble(volumeBeforeChange);                            if (arg0.toString().isEmpty() || arg0.toString().length() <= 0 || arg0.toString().equals("") || arg0.toString() == null || arg0.toString().equals("0") || arg0.toString().startsWith(".")) {                                middleHolder.weight.setText("0");                                middleHolder.animalVolumeChangeListener.onAnimalVolumeChanged(middleHolder.groupId,previousVolume,0);                            } else {                                volume = calculateWarmUpVolume(context, arg0.toString(), ((Middle) holder).quantity.getText().toString());                                middleHolder.animalVolumeChangeListener.onAnimalVolumeChanged(middleHolder.groupId,previousVolume,volume);                            }                        }                    });                    middleHolder.quantity.addTextChangedListener(new TextWatcher() {                        @Override                        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {                        }                        @Override                        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,                                                      int arg3) {                        }                        @Override                        public void afterTextChanged(Editable arg0) {                            //While this edittext is being changed, I would like the 3rd viewtype which contains the volume to be calculated on the fly as the user enters numbers in this field.                            String volumeBeforeChange = middleHolder.volume.getText().toString();                            double previousVolume = Double.parseDouble(volumeBeforeChange);                            if (arg0.toString().isEmpty() || arg0.toString().length() <= 0 || arg0.toString().equals("") || arg0.toString() == null || arg0.toString().equals("0") || arg0.toString().startsWith(".")) {                                ((Middle) holder).quantity.setText("0");                                middleHolder.animalVolumeChangeListener.onAnimalVolumeChanged(middleHolder.groupId,previousVolume,0);                            } else {                                volume = calculateWarmUpVolume(context, ((Middle) holder).weight.getText().toString(), arg0.toString());                                middleHolder.animalVolumeChangeListener.onAnimalVolumeChanged(middleHolder.groupId,previousVolume,volume);                            }                        }                    });                    break;                case AnimalsArray.BOTTOM:                    Bottom bottomHolder = ((Bottom) holder);                    Pair<LifecycleOwner, LiveData<Double>> totalVolumePair = bottomHolder.totalVolumeInterface.getTotalVolume(groupId);                    totalVolumePair.second.observe(totalVolumePair.first,                            new Observer<Double>(){                                @Override                                public void onChanged(Double aDouble) {                                    //Check if double is a whole number. If it is, remove decimal by converting to integer                                    String volumedWeight;                                    if ((aDouble % 1) == 0) {                                        int roundedVolume = aDouble.intValue();                                        volumedWeight = Integer.toString(roundedVolume);                                    } else {                                        volumedWeight = Double.toString(volume);                                    }                                    bottomHolder.volume.setText(String.valueOf(volumedWeight));                                }                            }                    );                    break;            }        }    }    @Override    public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {        super.onViewRecycled(holder);        /* middle holders contributing to the total volume of the same have the         *same groupId together with their corressponding bottom holder.         */        int groupId = 0;        if(holder instanceof Bottom){            ((Bottom) holder).totalVolumeInterface.removeObservers(groupId);        }    }-> 最后为接口的重写方法编写逻辑。public class SetupRecyclerClass extends AppCompatActivity implements TotalVolumeInterface, AnimalVolumeChangeListener{    HashMap<Integer, MutableLiveData<Double>> mTotalVolumesMap = new HashMap<>();    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ArrayList<AnimalsArray> animalsArrayArrayList = new ArrayList<>();        Animal_Volume_Adapter adapter = new Animal_Volume_Adapter(animalsArrayArrayList,this, this);    }    @Override    public Pair<LifecycleOwner, LiveData<Double>> getTotalVolume(int groupId) {        if(mTotalVolumesMap.get(groupId) == null){            mTotalVolumesMap.put(groupId,new MutableLiveData<>(0.0));        }        return new Pair<>(this,mTotalVolumesMap.get(groupId));    }    @Override    public void removeObservers(int groupId) {        mTotalVolumesMap.get(groupId).removeObservers(this);    }    @Override    public void onAnimalVolumeChanged(int groupId, double previousVolume, double currentVolume) {        if(mTotalVolumesMap.get(groupId) == null){            mTotalVolumesMap.put(groupId,new MutableLiveData<>(0.0));        }        double newTotalVolume = (mTotalVolumesMap.get(groupId).getValue()-previousVolume)+currentVolume;        mTotalVolumesMap.get(groupId).setValue(newTotalVolume);    }}希望这可以帮助。
随时随地看视频慕课网APP

相关分类

Java
我要回答