[英]CardView inside RecyclerView not resizing to correct height when expanded
After creating a RecyclerView, I've noticed that my CardView does not resize to the correct height when I expand it ( Item A , Item B and Item C ). 创建RecyclerView之后,我注意到我的CardView展开时( 项目A , 项目B和项目C )没有调整为正确的高度。 It should be the same height as the txtSubtitle TextView. 它的高度应与txtSubtitle TextView的高度相同。 I think that txtSubtitleHeight
could be the culprit but does anyone know what is causing this problem and how to resolve it? 我认为txtSubtitleHeight
可能是罪魁祸首,但是没有人知道是什么导致了此问题以及如何解决该问题?
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
<?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's suggestion 麦克米斯特的建议
Ok so it seems that it's your function to get the height that is not correct. 好的,看来这是您获得不正确高度的功能。 Actually By rereading your code, I think I might have found an idea of what is going on. 实际上,通过重新阅读您的代码,我想我可能已经对发生的事情有所了解。 With the tests you have done we've determined that the issue was on the side of the function that retrieve the size. 通过测试,我们确定问题出在检索大小的函数方面。 Now, on your demonstrating gif, all the expanded views have the same size, and for the last card, it seems to have the size you want, which is not having any space after the text. 现在,在演示gif上,所有展开的视图都具有相同的大小,对于最后一张卡片,它似乎具有所需的大小,该文本后没有空格。
So based on those information, my guess is the following: 因此,基于这些信息,我的猜测如下:
So, based on that, if I'm not mistaken, a simple fix would be to have one height variable for each card, so one for each viewholder from your adapter. 因此,基于此,如果我没记错的话,一个简单的解决方法是为每个卡设置一个高度变量,从而为适配器中的每个视口持有者设置一个高度变量。
You could do like: 您可以这样做:
// inner class for viewholder to use,
class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
int height;
}
then you can update your onPreDraw function like this: 那么您可以像这样更新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;
}
And finally in your expandTV 最后在您的expandTV中
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();
}
And I believe it should solve your issue :) 而且我相信它应该可以解决您的问题:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.