android - CardView wrap its content dynamically -


i have following card in layout:

<android.support.v7.widget.cardview     android:id="@+id/card1"     android:layout_width="match_parent"     android:layout_marginbottom="6dp">      <relativelayout         android:id="@+id/content"         android:layout_width="match_parent"         android:layout_height="wrap_content">          <textview             android:id="@+id/label"             android:layout_width="match_parent"             android:layout_height="wrap_content" />          <!-- [a recyclerview list linearlayout header] -->         <include             android:id="@+id/table"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_above="@+id/total_label"             android:layout_below="@id/label"             android:layout_marginbottom="4dp"             android:layout_margintop="4dp" />          <!-- [a linearlayout 2 textviews] -->         <include             android:id="@+id/total_label"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_alignparentbottom="true" />      </relativelayout> </android.support.v7.widget.cardview> 

what try achieve click on label textview , hide other content card (let visible label component). again, clicking further label expand hidden content. can if set explicitly height of card i.e. 400dp, way if containing recyclerview used list have not many items (which same height , fixed) there empty space. how can card wrap content? (when use wrap_content in layout_height of card label visible).

this click handler card:

card.setonclicklistener(new view.onclicklistener() {             @override             public void onclick(view v) {                 resources r = getresources();                  if (toggle) {                     tablecontainer.setvisibility(view.gone);                     totallabel.setvisibility(view.gone);                      linearlayout.layoutparams params = new linearlayout.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content);                      float pxtopmargin = typedvalue.applydimension(typedvalue.complex_unit_dip, getresources().getdimension(r.dimen.card_list_margin_top), r.getdisplaymetrics());                      params.topmargin = (int) pxtopmargin;                      card.setlayoutparams(params);                     card.setvisibility(view.gone);                     card.setvisibility(view.visible);                 } else {                     tablecontainer.setvisibility(view.visible);                     totallabel.setvisibility(view.visible);                       float pxheight = typedvalue.applydimension(typedvalue.complex_unit_dip, 400, r.getdisplaymetrics());                      linearlayout.layoutparams params = new linearlayout.layoutparams(viewgroup.layoutparams.match_parent, (int) pxheight);                      float pxtopmargin = typedvalue.applydimension(typedvalue.complex_unit_dip, getresources().getdimension(r.dimen.card_list_margin_top), r.getdisplaymetrics());                      params.topmargin = (int) pxtopmargin;                     params.bottommargin = (int) pxtopmargin;                      card.setlayoutparams(params);                     card.setvisibility(view.gone);                     card.setvisibility(view.visible);                 }                  toggle = !toggle;             }         }); 

solution

ok problem create list using recyclerview has property:

a specific number of rows visible (i.e. 15) , if lower wrap content

i found other thread (comment se.solovyev) custom linear layout , edited little. result satisfying (although don't know if did bad in there, works).

package com.trafficbroker.trafficbroker.views;  import android.content.context; import android.graphics.rect; import android.support.v4.view.viewcompat; import android.support.v7.widget.recyclerview; import android.util.log; import android.view.view;  import java.lang.reflect.field;  /**  * {@link android.support.v7.widget.linearlayoutmanager} wraps content. note class  * wrap content regardless of {@link android.support.v7.widget.recyclerview} layout parameters.  * <p/>  * it's impossible run add/remove animations child views have arbitrary dimensions (height  * vertical orientation , width horizontal). if child views have fixed dimensions  * {@link #setchildsize(int)} method might used let layout manager know how big going be.  * if animations not used @ normal measuring procedure run , child views measured during  * measure pass.  */ public class wrappinglinearlayoutmanager extends    android.support.v7.widget.linearlayoutmanager {  private static boolean canmakeinsetsdirty = true; private static field insetsdirtyfield = null;  private static final int child_width = 0; private static final int child_height = 1; private static final int default_child_size = 100;  private final int[] childdimensions = new int[2]; private final recyclerview view;  private int childsize = default_child_size; private boolean haschildsize; private int overscrollmode = viewcompat.over_scroll_always; private final rect tmprect = new rect();  @suppresswarnings("unuseddeclaration") public wrappinglinearlayoutmanager(context context) {     super(context);     this.view = null; }  @suppresswarnings("unuseddeclaration") public wrappinglinearlayoutmanager(context context, int orientation, boolean reverselayout) {     super(context, orientation, reverselayout);     this.view = null; }  @suppresswarnings("unuseddeclaration") public wrappinglinearlayoutmanager(recyclerview view) {     super(view.getcontext());     this.view = view;     this.overscrollmode = viewcompat.getoverscrollmode(view); }  @suppresswarnings("unuseddeclaration") public wrappinglinearlayoutmanager(recyclerview view, int orientation, boolean reverselayout) {     super(view.getcontext(), orientation, reverselayout);     this.view = view;     this.overscrollmode = viewcompat.getoverscrollmode(view); }  public void setoverscrollmode(int overscrollmode) {     if (overscrollmode < viewcompat.over_scroll_always || overscrollmode > viewcompat.over_scroll_never)         throw new illegalargumentexception("unknown overscroll mode: " + overscrollmode);     if (this.view == null) throw new illegalstateexception("view == null");     this.overscrollmode = overscrollmode;     viewcompat.setoverscrollmode(view, overscrollmode); }  public static int makeunspecifiedspec() {     return view.measurespec.makemeasurespec(0, view.measurespec.unspecified); }  @override public void onmeasure(recyclerview.recycler recycler, recyclerview.state state, int widthspec, int heightspec) {     final int widthmode = view.measurespec.getmode(widthspec);     final int heightmode = view.measurespec.getmode(heightspec);      final int widthsize = view.measurespec.getsize(widthspec);     final int heightsize = view.measurespec.getsize(heightspec);      final boolean haswidthsize = widthmode != view.measurespec.unspecified;     final boolean hasheightsize = heightmode != view.measurespec.unspecified;      final boolean exactwidth = widthmode == view.measurespec.exactly;     final boolean exactheight = heightmode == view.measurespec.exactly;      final int unspecified = makeunspecifiedspec();      if (exactwidth && exactheight) {         // in case of exact calculations both dimensions let's use default "onmeasure" implementation         super.onmeasure(recycler, state, widthspec, heightspec);         return;     }      final boolean vertical = getorientation() == vertical;      initchilddimensions(widthsize, heightsize, vertical);      int width = 0;     int height = 0;      // it's possible scrap views in recycler bound old (invalid) adapter entities.     // happens because invalidation happens after "onmeasure" method. workaround let's clear     // recycler (it should not cause performance issues while scrolling "onmeasure" never     // called whiles scrolling)     recycler.clear();      final int stateitemcount = state.getitemcount();     final int adapteritemcount = (getitemcount() < 15 ? getitemcount() : 15);//getitemcount();   // max visible rows     // adapter contains actual data while state might contain old data (f.e. data before animation     // done). want measure view actual data must use data adapter , not      // state     (int = 0; < adapteritemcount; i++) {         if (vertical) {             if (!haschildsize) {                 if (i < stateitemcount) {                     // should not exceed state count, otherwise we'll indexoutofboundsexception. such items                     // use calculated dimensions                     measurechild(recycler, i, widthsize, unspecified, childdimensions);                 } else {                     logmeasurewarning(i);                 }             }             height += childdimensions[child_height];             if (i == 0) {                 width = childdimensions[child_width];             }             if (hasheightsize && height >= heightsize) {                 break;             }         } else {             if (!haschildsize) {                 if (i < stateitemcount) {                     // should not exceed state count, otherwise we'll indexoutofboundsexception. such items                     // use calculated dimensions                     measurechild(recycler, i, unspecified, heightsize, childdimensions);                 } else {                     logmeasurewarning(i);                 }             }             width += childdimensions[child_width];             if (i == 0) {                 height = childdimensions[child_height];             }             if (haswidthsize && width >= widthsize) {                 break;             }         }     }      if (exactwidth) {         width = widthsize;     } else {         width += getpaddingleft() + getpaddingright();         if (haswidthsize) {             width = math.min(width, widthsize);         }     }      if (exactheight) {         height = heightsize;     } else {         height += getpaddingtop() + getpaddingbottom();         if (hasheightsize) {             height = math.min(height, heightsize);         }     }      setmeasureddimension(width, height);      if (view != null && overscrollmode == viewcompat.over_scroll_if_content_scrolls) {         final boolean fit = (vertical && (!hasheightsize || height < heightsize))                 || (!vertical && (!haswidthsize || width < widthsize));          viewcompat.setoverscrollmode(view, fit ? viewcompat.over_scroll_never : viewcompat.over_scroll_always);     } }  private void logmeasurewarning(int child) {     if (buildconfig.debug) {         log.w("linearlayoutmanager", "can't measure child #" + child + ", used dimensions reused." +                 "to remove message either use #setchildsize() method or don't run recyclerview animations");     } }  private void initchilddimensions(int width, int height, boolean vertical) {     if (childdimensions[child_width] != 0 || childdimensions[child_height] != 0) {         // initialized, skipping         return;     }     if (vertical) {         childdimensions[child_width] = width;         childdimensions[child_height] = childsize;     } else {         childdimensions[child_width] = childsize;         childdimensions[child_height] = height;     } }  @override public void setorientation(int orientation) {     // might called before constructor of class called     //noinspection constantconditions     if (childdimensions != null) {         if (getorientation() != orientation) {             childdimensions[child_width] = 0;             childdimensions[child_height] = 0;         }     }     super.setorientation(orientation); }  public void clearchildsize() {     haschildsize = false;     setchildsize(default_child_size); }  public void setchildsize(int childsize) {     haschildsize = true;     if (this.childsize != childsize) {         this.childsize = childsize;         requestlayout();     } }  private void measurechild(recyclerview.recycler recycler, int position, int widthsize, int heightsize, int[] dimensions) {     final view child;     try {         child = recycler.getviewforposition(position);     } catch (indexoutofboundsexception e) {         if (buildconfig.debug) {             log.w("linearlayoutmanager", "linearlayoutmanager doesn't work animations. consider switching them off", e);         }         return;     }      final recyclerview.layoutparams p = (recyclerview.layoutparams) child.getlayoutparams();      final int hpadding = getpaddingleft() + getpaddingright();     final int vpadding = getpaddingtop() + getpaddingbottom();      final int hmargin = p.leftmargin + p.rightmargin;     final int vmargin = p.topmargin + p.bottommargin;      // must make insets dirty in order calculateitemdecorationsforchild work     makeinsetsdirty(p);     // method should called before getxxxdecorationxxx() methods     calculateitemdecorationsforchild(child, tmprect);      final int hdecoration = getrightdecorationwidth(child) + getleftdecorationwidth(child);     final int vdecoration = gettopdecorationheight(child) + getbottomdecorationheight(child);      final int childwidthspec = getchildmeasurespec(widthsize, hpadding + hmargin + hdecoration, p.width, canscrollhorizontally());     final int childheightspec = getchildmeasurespec(heightsize, vpadding + vmargin + vdecoration, p.height, canscrollvertically());      child.measure(childwidthspec, childheightspec);      dimensions[child_width] = getdecoratedmeasuredwidth(child) + p.leftmargin + p.rightmargin;     dimensions[child_height] = getdecoratedmeasuredheight(child) + p.bottommargin + p.topmargin;      // view recycled let's not keep old measured values     makeinsetsdirty(p);     recycler.recycleview(child); }  private static void makeinsetsdirty(recyclerview.layoutparams p) {     if (!canmakeinsetsdirty) {         return;     }     try {         if (insetsdirtyfield == null) {             insetsdirtyfield = recyclerview.layoutparams.class.getdeclaredfield("minsetsdirty");             insetsdirtyfield.setaccessible(true);         }         insetsdirtyfield.set(p, true);     } catch (nosuchfieldexception e) {         onmakeinsertdirtyfailed();     } catch (illegalaccessexception e) {         onmakeinsertdirtyfailed();     } }  private static void onmakeinsertdirtyfailed() {     canmakeinsetsdirty = false;     if (buildconfig.debug) {         log.w("linearlayoutmanager", "can't make layoutparams insets dirty, decorations measurements might incorrect");     } } } 

i did example close yours could, key seems be

card.requestlayout(); 

here's had cardview

    <android.support.v7.widget.cardview     android:id="@+id/card1"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:layout_marginbottom="6dp">      <relativelayout         android:id="@+id/content"         android:layout_width="match_parent"         android:layout_height="wrap_content">          <textview             android:id="@+id/label"             android:layout_width="match_parent"             android:layout_height="wrap_content"             />          <!-- [a recyclerview list linearlayout header] -->         <include             layout="@layout/table_container"              android:id="@+id/table"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@id/label"             android:layout_marginbottom="4dp"             android:layout_margintop="4dp" />          <!-- [a linearlayout 2 textviews] -->         <include             layout="@layout/total_label"             android:id="@+id/total_label"             android:layout_width="match_parent"             android:layout_height="wrap_content"             android:layout_below="@id/table" />       </relativelayout> </android.support.v7.widget.cardview> 

here's had listener

card.setonclicklistener(new view.onclicklistener() {         @override         public void onclick(view v) {             if (toggle) {                 tablecontainer.setvisibility(view.gone);                 totallabel.setvisibility(view.gone);                  //viewgroup.layoutparams params = tablecontainer.getlayoutparams();                 //params.height = 1500;                 //tablecontainer.setlayoutparams(params);             } else {                 tablecontainer.setvisibility(view.visible);                 totallabel.setvisibility(view.visible);                  //viewgroup.layoutparams params =   tablecontainer.getlayoutparams();                 //params.height = 1500;                 //tablecontainer.setlayoutparams(params);             }             toggle = !toggle;             card.requestlayout();         }     }); 

here's example of 1 of layouts go include tags.

    xmlns:android="http://schemas.android.com/apk/res/android"     android:layout_height="wrap_content"     android:layout_width="match_parent"     > <textview     android:id="@+id/total_labeltv"     android:layout_width="match_parent"     android:text="total label"     android:background="#c0c0c0"     android:layout_height="wrap_content">  </textview></relativelayout> 

Comments

Popular posts from this blog

authentication - Mongodb revoke acccess to connect test database -

r - Update two sets of radiobuttons reactively - shiny -

ios - Realm over CoreData should I use NSFetchedResultController or a Dictionary? -