Big Bug Ban

兴趣 践行 创新

Archive for 12月, 2013

android开发日志-自适应宽度的AutoFitLinearLayout

 

最近需要实现一个如下图所示的列表

QQ截图20140308220730

但是系统提供的GridView抑或是ListView均不能实现item自动排列

于是自己实现了一个

核心在于自己实现了adaper和view添加的事件,添加的时候决定是否生成一个新的line来容纳item

另外注意这个实现有一处优化的地方。

即若到第三行的时候,第三行放不下,会尝试从第一行开始计算,这样可以尽可能保证每行都是好看的效果

  1.  
  2.  
  3. /**
  4.  * Copyright 2013
  5.  * Created on : 13-11-27 , 上午11:53
  6.  * Author     : haku
  7.  * Blog       : http://haku.hk
  8.  */
  9. public class AutoFitLinearLayout extends LinearLayout {
  10.  
  11.     private DataSetObserver obv;
  12.     private BaseAdapter adapter;
  13.     private ArrayList<LinearLayout> lineViews = new ArrayList<LinearLayout>();
  14.  
  15.     private AdapterView.OnItemClickListener itemClickListener;
  16.  
  17.     private class ItemProxyClickListener implements OnClickListener {
  18.         int pos;
  19.  
  20.         ItemProxyClickListener(int pos) {
  21.             this.pos = pos;
  22.         }
  23.  
  24.         @Override
  25.         public void onClick(View v) {
  26.             itemClickListener.onItemClick(null, v, pos, 0);
  27.         }
  28.     }
  29.  
  30.     public AutoFitLinearLayout(Context context, AttributeSet attrs) {
  31.         super(context, attrs);
  32.         this.setOrientation(LinearLayout.VERTICAL);
  33.     }
  34.  
  35.     public AutoFitLinearLayout(Context context) {
  36.         super(context);
  37.         this.setOrientation(LinearLayout.VERTICAL);
  38.     }
  39.  
  40.     /**
  41.      * 清空绑定view
  42.      */
  43.     public void reset() {
  44.         int total = lineViews.size();
  45.         for (int i = 0; i < total; i++) {
  46.             this.removeView(lineViews.get(i));
  47.         }
  48.         lineViews.clear();
  49.     }
  50.  
  51.     /**
  52.      * @param adp
  53.      */
  54.     public void setAdapter(BaseAdapter adp) {
  55.         adapter = adp;
  56.         obv = new DataSetObserver() {
  57.             @Override
  58.             public void onChanged() {
  59.                 super.onChanged();
  60.                 reset();
  61.                 int total = adapter.getCount();
  62.                 for (int i = 0; i < total; i++) {
  63.                     View v = adapter.getView(i, null, getLastLineHolder());
  64.                     if (getItemClickListener() != null) {
  65.                         v.setOnClickListener(new ItemProxyClickListener(i));
  66.                     }
  67.                     addToSuitableLayout(v);
  68.                 }
  69.             }
  70.         };
  71.         adapter.registerDataSetObserver(this.obv);
  72.     }
  73.  
  74.     public void addToSuitableLayout(View v) {
  75.         LinearLayout suitableLayout = getBestLineHolder(v);
  76.         suitableLayout.addView(v);
  77.         // 添加子view后重新计算宽度
  78.         suitableLayout.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  79.     }
  80.  
  81.     /**
  82.      * 添加一个水平的layout
  83.      *
  84.      * @return
  85.      */
  86.     public LinearLayout addNewLineHolder() {
  87.         LinearLayout v = new LinearLayout(this.getContext());
  88.  
  89.         LayoutParams layoutParams = new LayoutParams(
  90.                 ViewGroup.LayoutParams.MATCH_PARENT,
  91.                 ViewGroup.LayoutParams.WRAP_CONTENT);
  92.  
  93.         v.setOrientation(LinearLayout.HORIZONTAL);
  94.         v.setLayoutParams(layoutParams);
  95.         lineViews.add(v);
  96.         this.addView(v);
  97.         return v;
  98.     }
  99.  
  100.     /**
  101.      * 自动计算宽度后反馈line holder
  102.      *
  103.      * @return
  104.      */
  105.     public LinearLayout getBestLineHolder(View v) {
  106.         // 计算子view的宽度和margin
  107.         v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  108.         int viewWidth = v.getMeasuredWidth();
  109.         LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) v.getLayoutParams();
  110.  
  111.         if (lineViews.isEmpty()) {
  112.             this.addNewLineHolder();
  113.         }
  114.         LinearLayout lHolder;
  115.         // 遍历所有存在的line,计算剩余宽度,如果适合就返回
  116.         for (int i = 0, size = lineViews.size(); i < size; i++) {
  117.             lHolder = lineViews.get(i);
  118.             int lineMaxWidth = lHolder.getMeasuredWidth();
  119.             if (lineMaxWidth + viewWidth + lp.leftMargin + lp.rightMargin < this.getMeasuredWidth()) {
  120.                 return lHolder;
  121.             }
  122.         }
  123.         lHolder = this.addNewLineHolder();
  124.         return lHolder;
  125.     }
  126.  
  127.     /**
  128.      * @return
  129.      */
  130.     public LinearLayout getLastLineHolder() {
  131.         if (lineViews.isEmpty()) {
  132.             this.addNewLineHolder();
  133.         }
  134.         // 得到最后一行,计算其剩余宽度
  135.         LinearLayout lHolder = lineViews.get(lineViews.size()  1);
  136.         return lHolder;
  137.     }
  138.  
  139.     public void setOnItemClickListener(AdapterView.OnItemClickListener itemClickListener) {
  140.         this.itemClickListener = itemClickListener;
  141.     }
  142.  
  143.     public AdapterView.OnItemClickListener getItemClickListener() {
  144.         return itemClickListener;
  145.     }
  146. }

Written by princehaku

12月 2nd, 2013 at 11:43 下午