package carbon.widget; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import java.text.Format; import java.util.HashMap; import java.util.List; import java.util.Map; import carbon.Carbon; import carbon.R; import carbon.recycler.ListAdapter; public class TableView extends RecyclerView { Map<Class, CellRenderer> cellRenderers = new HashMap<>(); public TableView(Context context) { super(context); initTableView(context); } public TableView(Context context, AttributeSet attrs) { super(context, attrs); initTableView(context); } public TableView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initTableView(context); } private void initTableView(Context context) { setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); putCellRenderer(String.class, new StringRenderer()); putCellRenderer(Integer.class, new IntegerRenderer()); putCellRenderer(Float.class, new FloatRenderer()); putCellRenderer(Boolean.class, new BooleanRenderer()); } public static abstract class Adapter extends ListAdapter<Adapter.ViewHolder, List<?>> { private TableView tableView; public Adapter(TableView tableView) { this.tableView = tableView; } public abstract String getColumnName(int column); public abstract Class getColumnClass(int column); public abstract int getColumnCount(); public int getColumnWeight(int column) { return 1; } public Format getColumnFormat(int column) { return null; } @Override public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LinearLayout linearLayout = (LinearLayout) View.inflate(parent.getContext(), R.layout.carbon_tablelayout_row, null); linearLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); linearLayout.setMinimumHeight((int) parent.getContext().getResources().getDimension(R.dimen.carbon_tableRowHeight)); float weightSum = 0; for (int i = 0; i < getColumnCount(); i++) { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, getColumnWeight(i)); linearLayout.addView(tableView.getCellRenderer(getColumnClass(i)).getView(parent.getContext()), params); weightSum += getColumnWeight(i); } linearLayout.setWeightSum(weightSum); return new ViewHolder(linearLayout); } @Override public void onBindViewHolder(Adapter.ViewHolder holder, final int position) { for (int i = 0; i < holder.row.getChildCount(); i++) { View cell = holder.row.getChildAt(i); CellRenderer cellRenderer = tableView.getCellRenderer(getColumnClass(i)); cellRenderer.bindView(cell, getItem(position).get(i), getColumnFormat(i)); } } static class ViewHolder extends RecyclerView.ViewHolder { LinearLayout row; public ViewHolder(View itemView) { super(itemView); row = (LinearLayout) itemView; } } } private CellRenderer getCellRenderer(Class c) { return cellRenderers.get(c); } public void putCellRenderer(Class c, CellRenderer cellRenderer) { cellRenderers.put(c, cellRenderer); } public interface CellRenderer<T, V extends View> { V getView(Context context); void bindView(V view, T value, Format format); } public static class StringRenderer implements CellRenderer<String, TextView> { @Override public TextView getView(Context context) { TextView textView = new TextView(context); textView.setPadding((int) context.getResources().getDimension(R.dimen.carbon_padding), 0, (int) context.getResources().getDimension(R.dimen.carbon_padding), 0); textView.setGravity(Gravity.CENTER_VERTICAL); textView.setTextColor(Carbon.getThemeColor(context, android.R.attr.textColorPrimary)); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); textView.setMaxLines(1); textView.setEllipsize(TextUtils.TruncateAt.END); return textView; } @Override public void bindView(TextView view, String value, Format format) { view.setText(value); } } public static class IntegerRenderer implements CellRenderer<Integer, TextView> { @Override public TextView getView(Context context) { TextView textView = new TextView(context); textView.setPadding((int) context.getResources().getDimension(R.dimen.carbon_padding), 0, (int) context.getResources().getDimension(R.dimen.carbon_padding), 0); textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.END); textView.setTextColor(Carbon.getThemeColor(context, android.R.attr.textColorPrimary)); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); textView.setMaxLines(1); textView.setEllipsize(TextUtils.TruncateAt.END); return textView; } @Override public void bindView(TextView view, Integer value, Format format) { if (format != null) { view.setText(format.format(value)); } else { view.setText(value); } } } public static class FloatRenderer implements CellRenderer<Float, TextView> { @Override public TextView getView(Context context) { TextView textView = new TextView(context); textView.setPadding((int) context.getResources().getDimension(R.dimen.carbon_padding), 0, (int) context.getResources().getDimension(R.dimen.carbon_padding), 0); textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.END); textView.setTextColor(Carbon.getThemeColor(context, android.R.attr.textColorPrimary)); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13); textView.setMaxLines(1); textView.setEllipsize(TextUtils.TruncateAt.END); return textView; } @Override public void bindView(TextView view, Float value, Format format) { if (format != null) { view.setText(format.format(value)); } else { view.setText(String.valueOf(value)); } } } public static class BooleanRenderer implements CellRenderer<Boolean, FrameLayout> { @Override public FrameLayout getView(Context context) { FrameLayout layout = new FrameLayout(context); CheckBox checkBox = new CheckBox(context); checkBox.setPadding(0, 0, 0, 0); checkBox.setEnabled(false); FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); params.gravity = Gravity.CENTER; layout.addView(checkBox, params); return layout; } @Override public void bindView(FrameLayout view, Boolean value, Format format) { ((CheckBox) view.getChildAt(0)).setChecked(value); } } }