欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 实现伸缩布局效果示例代码

程序员文章站 2024-02-23 15:57:22
最近项目实现下面的图示的效果,本来想用listview+gridview实现,但是貌似挺麻烦的于是就用flowlayout 来addview实现添加伸缩的效果,实现也比较简...

最近项目实现下面的图示的效果,本来想用listview+gridview实现,但是貌似挺麻烦的于是就用flowlayout 来addview实现添加伸缩的效果,实现也比较简单。

Android 实现伸缩布局效果示例代码

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 实现伸缩布局效果,希望对大家有所帮助