一个RecyclerView项目中的OnClick会影响其他项目

时间:2019-02-16 13:57:13

标签: java android android-fragments android-recyclerview

  

编辑#1:通过调试,我发现错误“消失了”。基本上,我设置了一个断点,然后慢慢地执行检查每个multiChoiceItem的步骤,其他RecyclerView子项的高度不变。这是否意味着它是与图形/时序相关的问题?

     

编辑#2:另外,如果我更改了Child: 6的高度,它也会更改为Child: 3Child: 0

很长的问题我深表歉意。我检查了有关同一问题的其他答案,但没有一个适用。我尝试自己解决此问题,但无法解决,因此我希望获得一些帮助。如果有什么我可以做的使它更容易阅读的信息,请告诉我,我会尽快解决!

以我编写代码的方式,从技术上讲这应该是不可能发生的,但实际上是这样。


问题:我在一个onClickListener()项目中有一个TextView的{​​{1}}。 RecyclerView调用onClickListener()的容器类中的multiChoiceItem AlertDialog,然后在完成后调用RecyclerAdapter,并在末尾notifyDataSet()处测量高度在绘制新的addOnLayoutChangeListener()之后。

通知数据集已结束,然后导致RecyclerView项中的TextView更改以显示每个 Checked 项的文本。然后,在RecyclerView中测量此高度,并将其发送到addOnLayoutChangeListener(),该ViewModel测量三个片段的同一位置项目的高度,并将项目高度设置为最大高度,以便它们看起来都相同。

令人困惑的部分::仅当三个片段之一发生此问题,而其他受影响的物品高度与其他两个片段不匹配时,才会发生此问题。告诉我这是本地化为一个片段(具有自己的类)


代码: 代码很长,所以我将其简化为我认为很重要的

ViewHolder

class TextViewViewHolder extends RecyclerView.ViewHolder {

    TextView vhTVTextView;
    TextView vhTVMainTextView;
    CardView vhTVCardView;
    TextViewClickedListener vhTextViewClickedListener;

    // Gets current position from 'onBindViewHolder'
    int vhPosition = 0;

    public TextViewViewHolder(View itemView, TextViewClickedListener textViewClickedListener) {
        super(itemView);

        this.vhTextViewClickedListener = textViewClickedListener;

        this.vhTVCardView = itemView.findViewById(R.id.thoughtCard);
        this.vhTVTextView = itemView.findViewById(R.id.thoughtNumber);
        this.vhTVMainTextView = itemView.findViewById(R.id.textEntry);

        /*
            When the main TextView is clicked, it calls a function in the container
            'FragTextView' which pops up an AlertDialog. It was chosen to do it in the
            container instead of here because the Adapter is so adapt the lists data to the view
            and the container is what dictates what the lists data actually is.
         */
        vhTVMainTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(vhTextViewClickedListener != null) {
                    vhTextViewClickedListener.onTextViewClicked(vhPosition);
                }
            }
        });
    }
}

onBindViewHolder

@Override
public int getItemViewType(int position) {
    /*
        If mThoughtEntries is not null, then that means we can find the ViewType we are working
        with inside of it. Otherwise, we are mDistortions and we must be working on TYPE_TEXTVIEW
     */
    if(mThoughtEntries != null) return mThoughtEntries.get(position).getViewType();
    else return Constants.TYPE_TEXTVIEW;
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

    int adapterPosition = holder.getAdapterPosition();
    switch (holder.getItemViewType()) {
        case Constants.TYPE_EDITTEXT:
            EditTextViewHolder editTextViewHolder = (EditTextViewHolder)holder;
            // update MyCustomEditTextListener every time we bind a new item
            // so that it knows what item in mDataset to update
            editTextViewHolder.mMyCustomEditTextListener.setTWPosition(holder.getAdapterPosition());

            //Displaying list item to its correct position
            editTextViewHolder.vhETTextView.setText(String.valueOf(adapterPosition + 1));
            editTextViewHolder.vhETEditText.setText(mThoughtEntries.get(adapterPosition).getThought());
            break;

        case Constants.TYPE_TEXTVIEW:
            TextViewViewHolder textViewViewHolder = (TextViewViewHolder)holder;

            // Send current position to viewHolder so when the text listener is called, it knows
            // exactly which position of the Distortions list to change
            textViewViewHolder.vhPosition = adapterPosition;

            //Displaying list item to its correct position
            textViewViewHolder.vhTVTextView.setText(String.valueOf(adapterPosition + 1));
            textViewViewHolder.vhTVMainTextView.setText(distortionsToString(mDistortions.get(adapterPosition)));

            break;
    }
}

父级中的“警告对话框”

@Override
public void onTextViewClicked(int position) {
    //pass the 'context' here
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(getContext());
    final int recyclerPosition = position;

    /*
        Turning the distortions into a list of strings and an array of what should, or should
        not, be checked.
     */
    final String[] distortionStrings = distortionNameToStringArray(mDistortions.get(position));
    final boolean[] checkedDistortions = distortionCheckToBooleanArray(mDistortions.get(position));

    alertDialog.setMultiChoiceItems(distortionStrings, checkedDistortions,
            new DialogInterface.OnMultiChoiceClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which, boolean isChecked) {
                    if (isChecked) {
                        // If the user checked the item, add it to the selected items
                        mDistortions.get(recyclerPosition).get(which).setChecked(true);
                    } else {
                        // Else, if the item is already in the array, remove it
                        mDistortions.get(recyclerPosition).get(which).setChecked(false);
                    }
                    /*
                        Because the RecyclerView takes a while to draw, if we call the below function
                        as we normally we would, it would appear to have no effect because it would
                        be automatically overwritten when the RecyclerView is drawn. So we call this
                        onLayout change listener to wait til the view is drawn and then we call
                        the function
                     */
                    mRecyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                        @Override
                        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                            mRecyclerView.removeOnLayoutChangeListener(this);
                            // Send new height to the ViewModel
                            if(mLayoutManager.findViewByPosition(recyclerPosition) != null) {
                                // Get view of item measuring
                                View recyclerChild = mLayoutManager.findViewByPosition(recyclerPosition);
                                // Get LinearLayout from view
                                LinearLayout linearLayout = recyclerChild.findViewById(R.id.horizontalLayout);
                                // This is called to find out how big a view should be. The constraints are to check
                                // measurement when it is set to 'wrap_content'.
                                linearLayout.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                                // Get height of the specified view
                                int height = linearLayout.getMeasuredHeight();
                                // Send to child abstracted class which then calls function from 'SharedEntryFragments'
                                setViewModelHeight(height, recyclerPosition);
                            }
                        }
                    });
                    mAdapter.notifyDataSetChanged();
                }
            });

    alertDialog.setPositiveButton("Okay", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // DO SOMETHING HERE
            dialog.cancel();
        }
    });

    AlertDialog dialog = alertDialog.create();
    dialog.show();
}

使所有片段项目高度相等的功能

  

我知道代码的这一部分不会影响它,因为高度更改的视图被if(positionalHeight.get(i) != 0) {}跳过了,因此从技术上来说,它们永远都不会改变!

    /*
        This is the listener that will set all the RecyclerViews childrens heights. It
        listens to getTallestLiveHeight() inside of 'SharedEntryFragments.java' and when
        a change occurs, this is called
     */
    if(getActivity() != null) {
        // The container holds the ViewModel so this must make sure getActivity() is not null
        mViewModel = ViewModelProviders.of(getActivity()).get(SharedEntryFragments.class);
        /*
            Creates the observer which updates the UI. The observer takes the
            PositionalHeight class as an input. This class keeps track of which index
            of the RecyclerView to change and what height it will be changed to.
         */
        final Observer<List<Integer>> maxHeight = new Observer<List<Integer>>() {
            @Override
            public void onChanged(@Nullable final List<Integer> positionalHeight) {
                if (positionalHeight != null) {
                    // Get the index that we are going to change and its height
                    //int position = positionalHeight.getPosition();
                    //int height = positionalHeight.getHeight();

                    /*
                        We're going to run through each child of mRecyclerView and change
                        its height accordingly
                     */
                    int listSize = positionalHeight.size();
                    for(int i = 0; i < listSize; i++) {
                        // If height reads zero then skip because it will make our view disappear
                        if(positionalHeight.get(i) != 0) {
                            // This is the child item that we will be changing
                            View recyclerChild = mLayoutManager.findViewByPosition(i);

                            // Ensure that the child exists before continuing
                            if (recyclerChild != null) {
                                // We will be changing the CardView's height
                                // TODO might have to add a check to detect which viewholder
                                CardView cardView = recyclerChild.findViewById(R.id.thoughtCard);
                                // Get the LayoutParams first to ensure everything stays the same
                                ViewGroup.LayoutParams lparams = cardView.getLayoutParams();
                                // Get and set height
                                lparams.height = positionalHeight.get(i);
                                cardView.setLayoutParams(lparams);
                            }
                        }
                    }
                }
            }
        };
        mViewModel.getTallestLiveHeight().observe(this, maxHeight);
    }
}

1 个答案:

答案 0 :(得分:0)

我希望我可以为其他人提供更好的答案,但这是我发现的:

由于某种原因,当我在AlertDialog函数中调用mAdapter.notifyDataSetChanged();时,RecyclerView中的每三个项目都变为相等的高度。我决定将其更改为mAdapter.notifyItemChanged(recyclerPosition);,以节省内存,巧合的是,该错误已消失。

如果有人可以解释原因,我将其设置为可接受的答案,但是到目前为止,这已经满足了该问题,因此我将其保留为答案。