package cn.mutils.app.ui.adapter; import android.content.Context; import android.util.AttributeSet; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TableRow; import java.util.LinkedList; import java.util.List; /** * Adapter for {@link TableLayout} * * @see ItemAdapter */ public abstract class TableAdapter<DATA_ITEM> extends CacheAdapter<DATA_ITEM, List<IItemView<DATA_ITEM>>> { protected int mColumnCount; protected List<OTableRow> mCacheRows = new LinkedList<OTableRow>(); @Override public void setContainer(ViewGroup container) { if (container != null) { if (!(container instanceof TableLayout)) { throw new IllegalArgumentException("container is not TableLayout"); } } super.setContainer(container); } public int getColumnCount() { return mColumnCount; } public void setColumnCount(int columnCount) { if (columnCount < 1) { throw new IllegalArgumentException(); } if (mColumnCount == columnCount) { return; } onColumnTransform(columnCount - mColumnCount); mColumnCount = columnCount; mCacheInvalidate = true; notifyDataSetChanged(); } @Override protected int getCacheSizeRequired() { if (mDataProvider == null || mColumnCount == 0) { return 0; } int requiredViews = mDataProvider.size(); int requiredRows = requiredViews / mColumnCount; int requiredViews4Bottom = requiredViews % mColumnCount; if (requiredViews4Bottom > 0) { requiredRows++; } return requiredRows; } @Override protected boolean freeCacheNoUse() { return Math.random() > 0.3 && mCacheViews.size() / getCacheSizeRequired() > 2; } @Override protected void freeCacheAt(int index) { List<IItemView<DATA_ITEM>> rowViews = mCacheViews.get(index); for (int j = rowViews.size() - 1; j >= 0; j--) { IItemView<DATA_ITEM> itemView = rowViews.get(j); itemView.setAdapter(null); itemView.setDataProvider(null); rowViews.remove(j); } mCacheRows.remove(index); mCacheViews.remove(index); } @Override protected void allocCacheAt(int index) { OTableRow row = new OTableRow(getContext()); row.setColumn(mColumnCount); List<IItemView<DATA_ITEM>> rowViews = new LinkedList<IItemView<DATA_ITEM>>(); int viewType=getItemViewType(-1); for (int j = 0; j < mColumnCount; j++) { IItemView<DATA_ITEM> itemView = getItemView(viewType); itemView.setAdapter(this); itemView.onCreate(); fixItemViewParams(itemView); row.addView(itemView.toView()); rowViews.add(itemView); } mCacheRows.add(index, row); mCacheViews.add(index, rowViews); } @Override protected IItemView<DATA_ITEM> getItemViewAt(int index) { return mCacheViews.get(index / mColumnCount).get(index % mColumnCount); } @Override protected void onDataSetChanged() { if (mColumnCount == 0) { return; } super.onDataSetChanged(); } protected void onColumnTransform(int transform) { if (mContainer == null || mDataProvider == null || mColumnCount == 0) { return; } int newColumnCount = mColumnCount + transform; int containerRows = mContainer.getChildCount(); int viewType=getItemViewType(-1); if (transform > 0) {// column increase for (int i = 0, size = containerRows; i < size; i++) { OTableRow row = mCacheRows.get(i); row.setColumn(newColumnCount); List<IItemView<DATA_ITEM>> rowViews = mCacheViews.get(i); for (int j = 0; j < transform; j++) { IItemView<DATA_ITEM> itemView = getItemView(viewType); itemView.setAdapter(this); itemView.onCreate(); fixItemViewParams(itemView); rowViews.add(itemView); for (int k = row.getChildCount(); k < mColumnCount; k++) { IItemView<DATA_ITEM> itemMore = rowViews.get(k); row.addView(itemMore.toView()); } row.addView(itemView.toView()); } } for (int i = mCacheViews.size() - 1; i >= containerRows; i--) { freeCacheAt(i); } } else if (transform < 0) {// column decrease List<IItemView<DATA_ITEM>> deleteViews = new LinkedList<IItemView<DATA_ITEM>>(); for (int i = 0, size = mCacheViews.size(); i < size; i++) { OTableRow row = mCacheRows.get(i); row.setColumn(newColumnCount); List<IItemView<DATA_ITEM>> rowViews = mCacheViews.get(i); for (int j = mColumnCount - 1; j >= newColumnCount; j--) { IItemView<DATA_ITEM> itemView = rowViews.get(j); itemView.setAdapter(null); itemView.setDataProvider(null); rowViews.remove(j); if (itemView.toView().getParent() == row) { row.removeView(itemView.toView()); } deleteViews.add(itemView); if (deleteViews.size() >= newColumnCount) { addCacheRow(deleteViews, newColumnCount); } } } if (deleteViews.size() != 0) { addCacheRow(deleteViews, newColumnCount); } } } protected void addCacheRow(List<IItemView<DATA_ITEM>> rowViews, int columnCount) { OTableRow newRow = new OTableRow(getContext()); newRow.setColumn(columnCount); LinkedList<IItemView<DATA_ITEM>> newRowViews = new LinkedList<IItemView<DATA_ITEM>>(); for (int i = 0; i < rowViews.size(); i++) { IItemView<DATA_ITEM> itemView = rowViews.get(i); newRowViews.add(itemView); newRow.addView(itemView.toView()); } int viewType=getItemViewType(-1); for (int i = newRowViews.size(); i < columnCount; i++) { IItemView<DATA_ITEM> itemView = getItemView(viewType); itemView.setAdapter(this); itemView.onCreate(); fixItemViewParams(itemView); newRowViews.add(itemView); newRow.addView(itemView.toView()); } mCacheViews.add(newRowViews); mCacheRows.add(newRow); rowViews.clear(); } protected void fixContainerSize() { int requiredRows = getCacheSizeRequired(); if (requiredRows == 0) { mContainer.removeAllViews(); return; } int requiredViews4Bottom = mDataProvider.size() % mColumnCount; requiredViews4Bottom = requiredViews4Bottom != 0 ? requiredViews4Bottom : mColumnCount; for (int i = 0; i < requiredRows; i++) {// fix items of row in container List<IItemView<DATA_ITEM>> rowViews = mCacheViews.get(i); OTableRow row = mCacheRows.get(i); int containerRowItems = row.getChildCount(); int requiredRowItems = (i == requiredRows - 1) ? requiredViews4Bottom : mColumnCount; if (requiredRowItems < containerRowItems) { row.removeViews(requiredRowItems, containerRowItems - requiredViews4Bottom); } else if (requiredRowItems > containerRowItems) { for (int j = containerRowItems; j < requiredRowItems; j++) { IItemView<DATA_ITEM> itemView = rowViews.get(j); row.addView(itemView.toView()); } } } int containerRows = mContainer.getChildCount(); if (requiredRows != containerRows) {// fix row in container if (requiredRows < containerRows) { mContainer.removeViews(requiredRows, containerRows - requiredRows); } else if (requiredRows > containerRows) { for (int i = containerRows; i < requiredRows; i++) { mContainer.addView(mCacheRows.get(i)); } } } } protected void fixItemViewParams(IItemView<DATA_ITEM> itemView) { ViewGroup.LayoutParams itemParams = itemView.toView().getLayoutParams(); boolean renewParams = false; if (itemParams != null) { if (itemParams instanceof TableRow.LayoutParams) { TableRow.LayoutParams itemRowParams = (TableRow.LayoutParams) itemParams; if (itemRowParams.width != 0 || itemRowParams.weight != 1) { itemRowParams.width = 0; itemRowParams.weight = 1; itemView.toView().setLayoutParams(itemRowParams); } } else { renewParams = true; } } else { renewParams = true; } if (renewParams) { itemView.toView().setLayoutParams(new TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1)); } } static class OTableRow extends TableRow { protected int mColumn; public OTableRow(Context context) { super(context); } public OTableRow(Context context, AttributeSet attrs) { super(context, attrs); } public int getColumn() { return mColumn; } public void setColumn(int column) { mColumn = column; } @Override public int getVirtualChildCount() { super.getVirtualChildCount(); return mColumn; } } }