Android 实现伸缩布局效果示例代码
程序员文章站
2024-02-23 15:57:22
最近项目实现下面的图示的效果,本来想用listview+gridview实现,但是貌似挺麻烦的于是就用flowlayout 来addview实现添加伸缩的效果,实现也比较简...
最近项目实现下面的图示的效果,本来想用listview+gridview实现,但是貌似挺麻烦的于是就用flowlayout 来addview实现添加伸缩的效果,实现也比较简单。
mainactivity 布局
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <relativelayout android:id="@+id/rl_category_title_bar_layout" android:layout_height="wrap_content" android:layout_width="match_parent" > <relativelayout android:layout_height="50dp" android:layout_width="match_parent" > <textview android:id="@+id/tv_category_title" android:layout_height="50dp" android:layout_width="wrap_content" android:text="分类" android:textsize="18sp" android:layout_centerinparent="true" android:gravity="center" /> </relativelayout> </relativelayout> <listview android:id="@+id/lv_category_menu" android:layout_height="match_parent" android:layout_width="match_parent" /> </linearlayout>
自定义布局flowlayout
package comskyball.addflowlayout; import android.content.context; import android.content.res.typedarray; import android.util.attributeset; import android.view.view; import android.view.viewgroup; import java.util.arraylist; import java.util.list; public class flowlayout extends viewgroup { private context mcontext; private int usefulwidth; // the space of a line we can use(line's width minus the sum of left and right padding private int linespacing = 0; // the spacing between lines in flowlayout list<view> childlist = new arraylist(); list<integer> linenumlist = new arraylist(); public flowlayout(context context) { this(context, null); } public flowlayout(context context, attributeset attrs) { this(context, attrs, 0); } public flowlayout(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); mcontext = context; typedarray mtypedarray = context.obtainstyledattributes(attrs, r.styleable.flowlayout); linespacing = mtypedarray.getdimensionpixelsize( r.styleable.flowlayout_linespacing, 0); mtypedarray.recycle(); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int mpaddingleft = getpaddingleft(); int mpaddingright = getpaddingright(); int mpaddingtop = getpaddingtop(); int mpaddingbottom = getpaddingbottom(); int widthsize = measurespec.getsize(widthmeasurespec); int heightmode = measurespec.getmode(heightmeasurespec); int heightsize = measurespec.getsize(heightmeasurespec); int lineused = mpaddingleft + mpaddingright; int liney = mpaddingtop; int lineheight = 0; for (int i = 0; i < this.getchildcount(); i++) { view child = this.getchildat(i); if (child.getvisibility() == gone) { continue; } int spacewidth = 0; int spaceheight = 0; layoutparams childlp = child.getlayoutparams(); if (childlp instanceof marginlayoutparams) { measurechildwithmargins(child, widthmeasurespec, 0, heightmeasurespec, liney); marginlayoutparams mlp = (marginlayoutparams) childlp; spacewidth = mlp.leftmargin + mlp.rightmargin; spaceheight = mlp.topmargin + mlp.bottommargin; } else { measurechild(child, widthmeasurespec, heightmeasurespec); } int childwidth = child.getmeasuredwidth(); int childheight = child.getmeasuredheight(); spacewidth += childwidth; spaceheight += childheight; if (lineused + spacewidth > widthsize) { //approach the limit of width and move to next line liney += lineheight + linespacing; lineused = mpaddingleft + mpaddingright; lineheight = 0; } if (spaceheight > lineheight) { lineheight = spaceheight; } lineused += spacewidth; } setmeasureddimension( widthsize, heightmode == measurespec.exactly ? heightsize : liney + lineheight + mpaddingbottom ); } @override protected void onlayout(boolean changed, int l, int t, int r, int b) { int mpaddingleft = getpaddingleft(); int mpaddingright = getpaddingright(); int mpaddingtop = getpaddingtop(); int linex = mpaddingleft; int liney = mpaddingtop; int linewidth = r - l; usefulwidth = linewidth - mpaddingleft - mpaddingright; int lineused = mpaddingleft + mpaddingright; int lineheight = 0; int linenum = 0; linenumlist.clear(); for (int i = 0; i < this.getchildcount(); i++) { view child = this.getchildat(i); if (child.getvisibility() == gone) { continue; } int spacewidth = 0; int spaceheight = 0; int left = 0; int top = 0; int right = 0; int bottom = 0; int childwidth = child.getmeasuredwidth(); int childheight = child.getmeasuredheight(); layoutparams childlp = child.getlayoutparams(); if (childlp instanceof marginlayoutparams) { marginlayoutparams mlp = (marginlayoutparams) childlp; spacewidth = mlp.leftmargin + mlp.rightmargin; spaceheight = mlp.topmargin + mlp.bottommargin; left = linex + mlp.leftmargin; top = liney + mlp.topmargin; right = linex + mlp.leftmargin + childwidth; bottom = liney + mlp.topmargin + childheight; } else { left = linex; top = liney; right = linex + childwidth; bottom = liney + childheight; } spacewidth += childwidth; spaceheight += childheight; if (lineused + spacewidth > linewidth) { //approach the limit of width and move to next line linenumlist.add(linenum); liney += lineheight + linespacing; lineused = mpaddingleft + mpaddingright; linex = mpaddingleft; lineheight = 0; linenum = 0; if (childlp instanceof marginlayoutparams) { marginlayoutparams mlp = (marginlayoutparams) childlp; left = linex + mlp.leftmargin; top = liney + mlp.topmargin; right = linex + mlp.leftmargin + childwidth; bottom = liney + mlp.topmargin + childheight; } else { left = linex; top = liney; right = linex + childwidth; bottom = liney + childheight; } } child.layout(left, top, right, bottom); linenum ++; if (spaceheight > lineheight) { lineheight = spaceheight; } lineused += spacewidth; linex += spacewidth; } // add the num of last line linenumlist.add(linenum); } /** * resort child elements to use lines as few as possible */ public void relayouttocompress() { int childcount = this.getchildcount(); if (0 == childcount) { //no need to sort if flowlayout has no child view return; } int count = 0; for (int i = 0; i < childcount; i++) { view v = getchildat(i); if (v instanceof blankview) { //blankview is just to make childs look in alignment, we should ignore them when we relayout continue; } count++; } view[] childs = new view[count]; int[] spaces = new int[count]; int n = 0; for (int i = 0; i < childcount; i++) { view v = getchildat(i); if (v instanceof blankview) { //blankview is just to make childs look in alignment, we should ignore them when we relayout continue; } childs[n] = v; layoutparams childlp = v.getlayoutparams(); int childwidth = v.getmeasuredwidth(); if (childlp instanceof marginlayoutparams) { marginlayoutparams mlp = (marginlayoutparams) childlp ; spaces[n] = mlp.leftmargin + childwidth + mlp.rightmargin; } else { spaces[n] = childwidth; } n++; } int[] compressspaces = new int[count]; for (int i = 0; i < count; i++) { compressspaces[i] = spaces[i] > usefulwidth ? usefulwidth : spaces[i]; } sorttocompress(childs, compressspaces); this.removeallviews(); for (view v : childlist) { this.addview(v); } childlist.clear(); } private void sorttocompress(view[] childs, int[] spaces) { int childcount = childs.length; int[][] table = new int[childcount + 1][usefulwidth + 1]; for (int i = 0; i < childcount +1; i++) { for (int j = 0; j < usefulwidth; j++) { table[i][j] = 0; } } boolean[] flag = new boolean[childcount]; for (int i = 0; i < childcount; i++) { flag[i] = false; } for (int i = 1; i <= childcount; i++) { for (int j = spaces[i-1]; j <= usefulwidth; j++) { table[i][j] = (table[i-1][j] > table[i-1][j-spaces[i-1]] + spaces[i-1]) ? table[i-1][j] : table[i-1][j-spaces[i-1]] + spaces[i-1]; } } int v = usefulwidth; for (int i = childcount ; i > 0 && v >= spaces[i-1]; i--) { if (table[i][v] == table[i-1][v-spaces[i-1]] + spaces[i-1]) { flag[i-1] = true; v = v - spaces[i - 1]; } } int rest = childcount; view[] restarray; int[] restspaces; for (int i = 0; i < flag.length; i++) { if (flag[i] == true) { childlist.add(childs[i]); rest--; } } if (0 == rest) { return; } restarray = new view[rest]; restspaces = new int[rest]; int index = 0; for (int i = 0; i < flag.length; i++) { if (flag[i] == false) { restarray[index] = childs[i]; restspaces[index] = spaces[i]; index++; } } table = null; childs = null; flag = null; sorttocompress(restarray, restspaces); } /** * add some blank view to make child elements look in alignment */ public void relayouttoalign() { int childcount = this.getchildcount(); if (0 == childcount) { //no need to sort if flowlayout has no child view return; } int count = 0; for (int i = 0; i < childcount; i++) { view v = getchildat(i); if (v instanceof blankview) { //blankview is just to make childs look in alignment, we should ignore them when we relayout continue; } count++; } view[] childs = new view[count]; int[] spaces = new int[count]; int n = 0; for (int i = 0; i < childcount; i++) { view v = getchildat(i); if (v instanceof blankview) { //blankview is just to make childs look in alignment, we should ignore them when we relayout continue; } childs[n] = v; layoutparams childlp = v.getlayoutparams(); int childwidth = v.getmeasuredwidth(); if (childlp instanceof marginlayoutparams) { marginlayoutparams mlp = (marginlayoutparams) childlp ; spaces[n] = mlp.leftmargin + childwidth + mlp.rightmargin; } else { spaces[n] = childwidth; } n++; } int linetotal = 0; int start = 0; this.removeallviews(); for (int i = 0; i < count; i++) { if (linetotal + spaces[i] > usefulwidth) { int blankwidth = usefulwidth - linetotal; int end = i - 1; int blankcount = end - start; if (blankcount >= 0) { if (blankcount > 0) { int eachblankwidth = blankwidth / blankcount; marginlayoutparams lp = new marginlayoutparams(eachblankwidth, 0); for (int j = start; j < end; j++) { this.addview(childs[j]); blankview blank = new blankview(mcontext); this.addview(blank, lp); } } this.addview(childs[end]); start = i; i --; linetotal = 0; } else { this.addview(childs[i]); start = i + 1; linetotal = 0; } } else { linetotal += spaces[i]; } } for (int i = start; i < count; i++) { this.addview(childs[i]); } } /** * use both of relayout methods together */ public void relayouttocompressandalign(){ this.relayouttocompress(); this.relayouttoalign(); } /** * cut the flowlayout to the specified num of lines * @param line_num */ public void specifylines(int line_num) { int childnum = 0; if (line_num > linenumlist.size()) { line_num = linenumlist.size(); } for (int i = 0; i < line_num; i++) { childnum += linenumlist.get(i); } list<view> viewlist = new arraylist<view>(); for (int i = 0; i < childnum; i++) { viewlist.add(getchildat(i)); } removeallviews(); for (view v : viewlist) { addview(v); } } @override protected layoutparams generatelayoutparams(layoutparams p) { return new marginlayoutparams(p); } @override public layoutparams generatelayoutparams(attributeset attrs) { return new marginlayoutparams(getcontext(), attrs); } @override protected layoutparams generatedefaultlayoutparams() { return new marginlayoutparams(super.generatedefaultlayoutparams()); } class blankview extends view { public blankview(context context) { super(context); } } }
adapter
package comskyball.addflowlayout; import java.util.arraylist; import android.content.context; import android.os.handler; import android.os.message; import android.util.log; import android.view.view; import android.view.view.onclicklistener; import android.view.viewgroup; import android.widget.baseadapter; import android.widget.imageview; import android.widget.linearlayout; import android.widget.textview; import android.widget.toast; public class categorylvadapter extends baseadapter { public context context; public arraylist<category> list; public boolean ismore=true; public categorylvadapter(context context,arraylist<category> list) { this.context=context; this.list=list; } @override public int getcount() { return list.size(); } @override public object getitem(int position) { return 0; } @override public long getitemid(int position) { return 0; } @override public view getview(final int position, view convertview, viewgroup parent) { viewholder viewholder=null; if(convertview==null){ convertview=view.inflate(context, r.layout.lv_category_item, null); viewholder=new viewholder(); viewholder.iv_lv_category_img=(imageview) convertview.findviewbyid(r.id.iv_lv_category_img); viewholder.tv_lv_category=(textview) convertview.findviewbyid(r.id.tv_lv_category); viewholder.flow_layout_lv_category=(flowlayout) convertview.findviewbyid(r.id.flow_layout_lv_category); viewholder.ll_lv_category_add=(linearlayout) convertview.findviewbyid(r.id.ll_lv_category_add); viewholder.iv_lv_category_arrow=(imageview) convertview.findviewbyid(r.id.iv_lv_category_arrow); convertview.settag(viewholder); }else{ viewholder=(viewholder) convertview.gettag(); } // imageloader.getinstance().displayimage(appconfig.app_url+list.get(position).getimg(),viewholder.iv_lv_category_img,app.normaloption); viewholder.tv_lv_category.settext(list.get(position).getcate_name()); viewholder.iv_lv_category_arrow.setbackgroundresource(r.drawable.arrow_down); viewholder.flow_layout_lv_category.removeallviews(); utils.addflow(context,6, list.get(position).getnext(),viewholder.flow_layout_lv_category); final flowlayout flowlayoutlvcategory = viewholder.flow_layout_lv_category; final imageview ivlvcategoryarrow = viewholder.iv_lv_category_arrow; viewholder.ll_lv_category_add.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { if(ismore){ ismore=false; flowlayoutlvcategory.removeallviews(); utils.addflow(context,list.get(position).getnext().size(), list.get(position).getnext(),flowlayoutlvcategory); ivlvcategoryarrow.setbackgroundresource(r.drawable.arrow_up); }else{ ismore=true; flowlayoutlvcategory.removeallviews(); utils.addflow(context,6, list.get(position).getnext(),flowlayoutlvcategory); ivlvcategoryarrow.setbackgroundresource(r.drawable.arrow_down); } } }); return convertview; } public class viewholder{ public imageview iv_lv_category_img; public textview tv_lv_category; public flowlayout flow_layout_lv_category; public linearlayout ll_lv_category_add; public imageview iv_lv_category_arrow; } }
adapter item布局
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" > <linearlayout android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" > <relativelayout android:layout_height="35dp" android:layout_width="match_parent" > <imageview android:id="@+id/iv_lv_category_img" style="@style/category_iv_left_style" /> <textview android:id="@+id/tv_lv_category" style="@style/category_tv_style" android:text="衣食" android:layout_torightof="@id/iv_lv_category_img" /> </relativelayout> <view style="@style/category_view_style" /> <scrollview android:layout_width="match_parent" android:layout_height="match_parent" > <relativelayout android:layout_height="match_parent" android:layout_width="match_parent" > <comskyball.addflowlayout.flowlayout android:id="@+id/flow_layout_lv_category" android:layout_width="match_parent" android:layout_height="wrap_content" app:linespacing="10dp" app:maxline="3" android:background="#f0f0f0" android:layout_margintop="5dp" /> <linearlayout android:id="@+id/ll_lv_category_add" style="@style/category_ll_style" android:layout_height="35dp" android:layout_below="@id/flow_layout_lv_category" > <imageview android:id="@+id/iv_lv_category_arrow" style="@style/category_iv_style" android:background="@drawable/arrow_down" /> <view style="@style/category_view_style" /> </linearlayout> </relativelayout> </scrollview> </linearlayout> </relativelayout>
以上所述是小编给大家介绍的android 实现伸缩布局效果,希望对大家有所帮助