Archive for 12月, 2013
android开发日志-自适应宽度的AutoFitLinearLayout
最近需要实现一个如下图所示的列表
但是系统提供的GridView抑或是ListView均不能实现item自动排列
于是自己实现了一个
核心在于自己实现了adaper和view添加的事件,添加的时候决定是否生成一个新的line来容纳item
另外注意这个实现有一处优化的地方。
即若到第三行的时候,第三行放不下,会尝试从第一行开始计算,这样可以尽可能保证每行都是好看的效果
- /**
- * Copyright 2013
- * Created on : 13-11-27 , 上午11:53
- * Author : haku
- * Blog : http://haku.hk
- */
- public class AutoFitLinearLayout extends LinearLayout {
- private DataSetObserver obv;
- private BaseAdapter adapter;
- private ArrayList<LinearLayout> lineViews = new ArrayList<LinearLayout>();
- private AdapterView.OnItemClickListener itemClickListener;
- private class ItemProxyClickListener implements OnClickListener {
- int pos;
- ItemProxyClickListener(int pos) {
- this.pos = pos;
- }
- @Override
- public void onClick(View v) {
- itemClickListener.onItemClick(null, v, pos, 0);
- }
- }
- public AutoFitLinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.setOrientation(LinearLayout.VERTICAL);
- }
- public AutoFitLinearLayout(Context context) {
- super(context);
- this.setOrientation(LinearLayout.VERTICAL);
- }
- /**
- * 清空绑定view
- */
- public void reset() {
- int total = lineViews.size();
- for (int i = 0; i < total; i++) {
- this.removeView(lineViews.get(i));
- }
- lineViews.clear();
- }
- /**
- * @param adp
- */
- public void setAdapter(BaseAdapter adp) {
- adapter = adp;
- obv = new DataSetObserver() {
- @Override
- public void onChanged() {
- super.onChanged();
- reset();
- int total = adapter.getCount();
- for (int i = 0; i < total; i++) {
- View v = adapter.getView(i, null, getLastLineHolder());
- if (getItemClickListener() != null) {
- v.setOnClickListener(new ItemProxyClickListener(i));
- }
- addToSuitableLayout(v);
- }
- }
- };
- adapter.registerDataSetObserver(this.obv);
- }
- public void addToSuitableLayout(View v) {
- LinearLayout suitableLayout = getBestLineHolder(v);
- suitableLayout.addView(v);
- // 添加子view后重新计算宽度
- suitableLayout.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- }
- /**
- * 添加一个水平的layout
- *
- * @return
- */
- public LinearLayout addNewLineHolder() {
- LinearLayout v = new LinearLayout(this.getContext());
- LayoutParams layoutParams = new LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- v.setOrientation(LinearLayout.HORIZONTAL);
- v.setLayoutParams(layoutParams);
- lineViews.add(v);
- this.addView(v);
- return v;
- }
- /**
- * 自动计算宽度后反馈line holder
- *
- * @return
- */
- public LinearLayout getBestLineHolder(View v) {
- // 计算子view的宽度和margin
- v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int viewWidth = v.getMeasuredWidth();
- LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) v.getLayoutParams();
- if (lineViews.isEmpty()) {
- this.addNewLineHolder();
- }
- LinearLayout lHolder;
- // 遍历所有存在的line,计算剩余宽度,如果适合就返回
- for (int i = 0, size = lineViews.size(); i < size; i++) {
- lHolder = lineViews.get(i);
- int lineMaxWidth = lHolder.getMeasuredWidth();
- if (lineMaxWidth + viewWidth + lp.leftMargin + lp.rightMargin < this.getMeasuredWidth()) {
- return lHolder;
- }
- }
- lHolder = this.addNewLineHolder();
- return lHolder;
- }
- /**
- * @return
- */
- public LinearLayout getLastLineHolder() {
- if (lineViews.isEmpty()) {
- this.addNewLineHolder();
- }
- // 得到最后一行,计算其剩余宽度
- LinearLayout lHolder = lineViews.get(lineViews.size() – 1);
- return lHolder;
- }
- public void setOnItemClickListener(AdapterView.OnItemClickListener itemClickListener) {
- this.itemClickListener = itemClickListener;
- }
- public AdapterView.OnItemClickListener getItemClickListener() {
- return itemClickListener;
- }
- }