CardView внутри RecyclerView не изменяет размеры до правильной высоты при расширении - PullRequest
0 голосов
/ 25 сентября 2018

После создания RecyclerView я заметил, что мой CardView не изменяет размер до нужной высоты при его расширении ( Элемент A , Элемент B и Элемент C).Он должен быть такой же высоты, как txtSubtitle TextView.Я думаю, что txtSubtitleHeight может быть виновником, но кто-нибудь знает, что является причиной этой проблемы и как ее решить?

enter image description here

public class MyFragmentRV extends android.support.v4.app.Fragment {

    public int mGridViewHeight;
//    public int txtSubtitleHeight;
    private static final int ITEM_TYPE = 100;
    private static final int HEADER_TYPE = 101;
    private static final int HEADER_TYPE_2 = 102;
    private static final int GRID_TYPE = 103;
//    GridView mGridViewA;
    ValueAnimator mAnimatorGV, mAnimatorTV;
    TextView txtArrowGV, txtTitle;

    //
    static final String[] frenchVowels = new String[]{
            "a", "e", "i", "o", "u", "y"
    };

    public MyFragmentRV.MyAdapter adapterGV;

    public MyFragmentRV() {}

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.fragment_rv, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        View v = getView();
        assert v != null;

        recyclerView = v.findViewById(R.id.my_recyclerview);

        // set the linear layout manager
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));

        // SpannableStrings
        // dynamically change SpannableString colour using defined attribute
        int[] attrS = {R.attr.spannablestringtextColor};
        TypedArray ta = getActivity().getTheme().obtainStyledAttributes(attrS);
        int colorSS = ta.getColor(0, Color.BLACK); //Color.BLACK - default value (colour will change automatically depending on chosen theme)
        Log.d(TAG, "clickMethod 1) " + Integer.toHexString(colorSS));
        ta.recycle();


        // SpannableString (start)
        SpannableStringBuilder ssb = new SpannableStringBuilder();

        SpannableString str1 = new SpannableString(" Item A ");
        str1.setSpan(new BackgroundColorSpan(Color.BLACK), 0, str1.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        str1.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.yellow)), 0, str1.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        ssb.append(str1);

        SpannableString str2 = new SpannableString(" Hello World");
        str2.setSpan(new ForegroundColorSpan(colorSS), 0, str2.length(), 0);
        ssb.append(str2);
        // SpannableString (end)

        // init data
        data = new ArrayList<>();
        data.add(ssb);
        data.add("Item B");
        data.add("Item C");

        subdata = new ArrayList<>();
        subdata.add("\u2022 a");
        subdata.add("\u2022 b\n\u2022 bb");
        subdata.add("\u2022 c\n\u2022 cc\n\u2022 ccc");

        adapter = createAdapter();

        recyclerView.setAdapter(adapter);

        super.onActivityCreated(savedInstanceState);
    }

    RecyclerView recyclerView;
    ArrayList<CharSequence> data;
    ArrayList<String> subdata;
    RecyclerView.Adapter<ViewHolder> adapter;


    // creates the adapter
    private RecyclerView.Adapter<ViewHolder> createAdapter() {
        return new RecyclerView.Adapter<ViewHolder>() {
            @NonNull
            @Override
            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) {
                switch (type) {
                    case HEADER_TYPE:
                        return new ViewHolder(inflateHelper(R.layout.header, parent));

                    case HEADER_TYPE_2:
                        return new ViewHolder(inflateHelper(R.layout.header, parent));

                    case ITEM_TYPE:
                        return new ViewHolder(inflateHelper(R.layout.recyclerview_item_tv, parent));

                    case GRID_TYPE:
                        return new ViewHolder(inflateHelper(R.layout.recyclerview_item_gv, parent));

                    default:
                        return new ViewHolder(inflateHelper(R.layout.recyclerview_item_tv, parent));
                }
            }

            @Override
            public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
                final Typeface iconFont = FontManager.getTypeface(getContext(), FontManager.FONTAWESOME); // FontManager class must be accessed first before text views can be set as image views

                switch (getItemViewType(position)) {
                    case HEADER_TYPE:
                        Button expandButton = viewHolder.itemView.findViewById(R.id.button);
                        expandButton.setText("Expand all");

                        expandButton.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                            }
                        });
                    break;
                    case HEADER_TYPE_2:
                        Button collapseButton = viewHolder.itemView.findViewById(R.id.button);
                        collapseButton.setText("Collapse all");

                        collapseButton.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                            }
                        });
                    break;
                    case ITEM_TYPE:
                        // get the current item
                        CharSequence itemA = data.get(position - 3);
                        String itemB = subdata.get(position - 3);


                        txtTitle = viewHolder.itemView.findViewById(R.id.tv_tv_A);
                        txtTitle.setText(itemA);

                        final TextView txtSubtitle = viewHolder.itemView.findViewById(R.id.tv_tv_B);
                        txtSubtitle.setText(itemB);
                        txtSubtitle.setVisibility(View.GONE);

                        //Add onPreDrawListener
                        txtSubtitle.getViewTreeObserver().addOnPreDrawListener(
                        new ViewTreeObserver.OnPreDrawListener() {

                            @Override
                            public boolean onPreDraw() {
                                txtSubtitle.getViewTreeObserver().removeOnPreDrawListener(this);
                                txtSubtitle.setVisibility(View.GONE);

                                final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                                final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                                txtSubtitle.measure(widthSpec, heightSpec);

                                txtSubtitleHeight = txtSubtitle.getMeasuredHeight();

                                return true;
                            }
                        });

                        final TextView txtArrowTV = viewHolder.itemView.findViewById(R.id.tv_tv_expandcollapse);
                        txtArrowTV.setText(R.string.fa_icon_chevron_down);
                        txtArrowTV.setTypeface(iconFont);

                        //
                        CardView cardView = viewHolder.itemView.findViewById(R.id.cv_tv);
                        LinearLayout mLinearLayoutTV = viewHolder.itemView.findViewById(R.id.cardview_tv_titlerow);

                        cardView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
//                                Toast.makeText(getActivity(),"CardView clicked", Toast.LENGTH_SHORT).show();
                                if(txtSubtitle.getVisibility() == View.GONE){
                                    expandTV(txtSubtitle, txtArrowTV);
                                } else {
                                    collapseTV(txtSubtitle, txtArrowTV);
                                }
                            }
                        });

                        mLinearLayoutTV.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if(txtSubtitle.getVisibility() == View.GONE){
                                    expandTV(txtSubtitle, txtArrowTV);
                                } else {
                                    collapseTV(txtSubtitle, txtArrowTV);
                                }
                            }
                        });

                        txtArrowTV.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if(txtSubtitle.getVisibility() == View.GONE){
                                    expandTV(txtSubtitle, txtArrowTV);
                                } else {
                                    collapseTV(txtSubtitle, txtArrowTV);
                                }
                            }
                        });
                    break;
                    case GRID_TYPE:
                        TextView titleG = viewHolder.itemView.findViewById(R.id.tv_gv_A);

                        titleG.setText("French vowels");

                        final TextView txtArrowGV = viewHolder.itemView.findViewById(R.id.tv_gv_expandcollapse);
                        txtArrowGV.setText(R.string.fa_icon_chevron_down);
                        txtArrowGV.setTypeface(iconFont);

                        final GridView mGridViewA = viewHolder.itemView.findViewById(R.id.gv);
                        mGridViewA.setVisibility(View.GONE);
                        mGridViewA.setEnabled(false);
                        mGridViewA.setVerticalScrollBarEnabled(false);
                        adapterGV = new MyFragmentRV.MyAdapter(getActivity().getApplicationContext(), 0);
                        mGridViewA.setAdapter(adapterGV);
                        for (String frenchVowel : frenchVowels) {
                            adapterGV.addAdapterItem(new MyFragmentRV.AdapterItem(frenchVowel));
                        }


                        //Add onPreDrawListener
                        mGridViewA.getViewTreeObserver().addOnPreDrawListener(
                        new ViewTreeObserver.OnPreDrawListener() {

                            @Override
                            public boolean onPreDraw() {
                                mGridViewA.getViewTreeObserver().removeOnPreDrawListener(this);
                                mGridViewA.setVisibility(View.GONE);

                                final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                                final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                                mGridViewA.measure(widthSpec, heightSpec);

                                mGridViewHeight = mGridViewA.getMeasuredHeight();

                                return true;
                            }
                        });


                        CardView cardViewG = viewHolder.itemView.findViewById(R.id.cv_gv);
                        LinearLayout mLinearLayoutGV = viewHolder.itemView.findViewById(R.id.cardview_gv_titlerow);

                        cardViewG.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if(mGridViewA.getVisibility() == View.GONE){
                                    expandGV(mGridViewA);
                                } else {
                                    collapseGV(mGridViewA);
                                }
                            }
                        });

                        mLinearLayoutGV.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if(mGridViewA.getVisibility() == View.GONE){
                                    expandGV(mGridViewA);
                                } else {
                                    collapseGV(mGridViewA);
                                }
                            }
                        });

                        txtArrowGV.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                if(mGridViewA.getVisibility() == View.GONE){
                                    expandGV(mGridViewA);
                                } else {
                                    collapseGV(mGridViewA);
                                }
                            }
                        });
                    break;
                }
            }

            @Override
            public int getItemCount() {
                return data.size() + 3;
            }

            @Override
            public int getItemViewType(int position) {
                switch (position) {
                    case 0:
                        return HEADER_TYPE;
                    case 1:
                        return HEADER_TYPE_2;
                    case 2:
                        return GRID_TYPE;
                    default: return ITEM_TYPE;
                }
            }
        };
    }

    private View inflateHelper(int resId, ViewGroup parent) {
        return LayoutInflater.from(getActivity()).inflate(resId, parent, false);
    }

    // inner class for viewholder to use,
    class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }

    public void expandGV(final GridView mGridViewA) {
        mGridViewA.setVisibility(View.VISIBLE);
        txtArrowGV.setText(R.string.fa_icon_chevron_up);

       ValueAnimator mAnimatorGV = slideAnimator(0, mGridViewHeight, mGridViewA);
        mAnimatorGV.start();
    }
    public void collapseGV(final GridView mGridViewA) {
        txtArrowGV.setText(R.string.fa_icon_chevron_down);

        int finalGVHeight = mGridViewA.getHeight();

        mAnimatorGV = slideAnimator(finalGVHeight, 0, mGridViewA);

        mAnimatorGV.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationEnd(Animator animator) {
                mGridViewA.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationStart(Animator animator) {
            }

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        mAnimatorGV.start();
    }
    public void expandTV(final TextView txtSubtitle, final TextView txtArrowTV) {
        txtSubtitle.setVisibility(View.VISIBLE);

        txtArrowTV.setText(R.string.fa_icon_chevron_up);

        mAnimatorTV = slideAnimator(0, txtSubtitleHeight, txtSubtitle);

        mAnimatorTV.start();
    }

    public void collapseTV(final TextView txtSubtitle, final TextView txtArrowTV) {
        txtArrowTV.setText(R.string.fa_icon_chevron_down);

        int finalTVHeight = txtSubtitle.getHeight();

        mAnimatorTV = slideAnimator(finalTVHeight, 0, txtSubtitle);

        mAnimatorTV.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationEnd(Animator animator) {
                txtSubtitle.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationStart(Animator animator) {
            }

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        mAnimatorTV.start();
    }


    public ValueAnimator slideAnimator(int start, int end, final View txtSubtitle) {

        final ValueAnimator animator = ValueAnimator.ofInt(start, end);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                // update height
                int value = (Integer) valueAnimator.getAnimatedValue();

                ViewGroup.LayoutParams layoutParamsTV = txtSubtitle.getLayoutParams();
                layoutParamsTV.height = value;
                txtSubtitle.setLayoutParams(layoutParamsTV);

//                ViewGroup.LayoutParams layoutParamsGV = mGridViewA.getLayoutParams();
//                layoutParamsGV.height = value;
//                mGridViewA.setLayoutParams(layoutParamsGV);
            }
        });
        return animator;
    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:focusable="true"
    android:id="@+id/cv_tv"
    android:layout_marginBottom="20dp"
    >

    <LinearLayout
        android:id="@+id/cardview_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="10dp"
        android:animateLayoutChanges="true">

        <LinearLayout
            android:id="@+id/cardview_tv_titlerow"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginBottom="2dp"
            android:weightSum="100">

            <TextView
                android:id="@+id/tv_tv_A"
                android:layout_weight="90"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Medium" />

            <TextView
                android:id="@+id/tv_tv_expandcollapse"
                android:clickable="true"
                android:focusable="true"
                android:layout_weight="10"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large" />
        </LinearLayout>

        <RelativeLayout
            android:id="@+id/relativelayout_tv"
            android:animateLayoutChanges="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/tv_tv_B"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="?android:attr/textColorPrimary"
                style="@android:style/TextAppearance.Large" />
        </RelativeLayout>
    </LinearLayout>
</android.support.v7.widget.CardView>

Предложение Macmist

enter image description here

1 Ответ

0 голосов
/ 26 сентября 2018

Хорошо, так что кажется, что ваша функция - получить неверную высоту.На самом деле, перечитывая ваш код, я думаю, что мог бы найти представление о том, что происходит.С помощью тестов, которые вы сделали, мы определили, что проблема была в стороне функции, которая извлекает размер.Теперь, когда вы демонстрируете gif, все расширенные представления имеют одинаковый размер, а для последней карты, кажется, он имеет нужный размер, без пробела после текста.

Итак, основываясь наэта информация, я думаю, следующая:

  • ваша функция для определения высоты действительно работает
  • НО у вас есть только одна переменная, определяющая этот размер (txtSubtitleHeight)
  • Таким образом, для каждой карты высчитывается высота, а txtSubtitleHeight заменяется высотой этой карты
  • И, наконец, txtSubtitleHeight имеет высоту последней просмотренной карты.И поскольку вы используете эту переменную для расширения каждой карты, каждая карта будет иметь высоту от этой последней просмотренной карты.

Так что, исходя из этого, если я не ошибаюсь, простое исправление будетиметь одну переменную высоты для каждой карты, поэтому по одной для каждого держателя вида из вашего адаптера.

Вы можете сделать так:

   // inner class for viewholder to use,
    class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
        }
        int height;
    }

, тогда вы можете обновить свою функцию onPreDraw следующим образом:

@Override
public boolean onPreDraw() {
    txtSubtitle.getViewTreeObserver().removeOnPreDrawListener(this);
                                txtSubtitle.setVisibility(View.GONE);
    final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                                txtSubtitle.measure(widthSpec, heightSpec);
    viewHolder.height = txtSubtitle.getMeasuredHeight();
    return true;
}

И, наконец, в вашем расширении TV

public void expandTV(final TextView txtSubtitle, final TextView txtArrowTV, final ViewHolder holder) {
    txtSubtitle.setVisibility(View.VISIBLE);

    txtArrowTV.setText(R.string.fa_icon_chevron_up);

    mAnimatorTV = slideAnimator(0, holder.height, txtSubtitle);

    mAnimatorTV.start();
}

И я считаю, что это должно решить вашу проблему:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...